------- android培训、java培训、期待与您交流! ----------
网络编程基础知识
1.Socket
网络编程. 底层的基本的实现. UDP ,TCP
2. 网络基本常识.
1. ip 地址:网络中计算机的唯一标识. IPv4 32位二进制. 4个字节,无符号的. 表示2(32)个 40亿.
如:192.168.10.1
2. 端口:通过ip地址可以找到互联网中指定的计算机主机,如果想要进行计算机之间的数据传输,程序
和程序之间进行数据的传输. 端口有范围的,0~65535 之间. 端口在系统中是唯一的,如果一个程
序占用了一个端口,其他程序就不能再用了. 不过程序的结束后,端口会释放,重新使用.
0~1024 端口,系统端口,不建议使用. 80 http 21ftp 8080
3. 域名
早期的时候我们想要访问互联网的是通过ip:端口号访问互联网,由于比较难记的原因,采用单词来代替
ip 地址.如:域名:
http://www.baidu.com:80
http: 超文本传输协议, 超文本...
www 万维网.
4. 网络传输协议
IP 地址可以访问互联网中指定的计算机, 通过端口号,可以找到指定的应用程序. 网络应用程要
进行数据的传输. 数据在传输时,就会遵守一个规则,这个规则就是所谓的互联网的传输协议。
他有主要有两种协议:UDP、TCP。
UDP(User datagram protocol):用户数据报协议
特点: 传输数据时,将数据封装为数据报包, 一个包最大是64k,发送发不需要确认接收方是否在
线. 数据有可能丢失,它是一种不可靠的协议.由于发送数据时,不需要确认接收方, 所以速
度快.
总结: 数据被打包(64k),不可靠,速度快
主要是:视频、屏幕广播、视频会议
实时性,很高但是不适合文件的传输.不能保证数据的可靠性...
TCP(Transmission control protocol)
特点:该协议,会通过3次握手,建立一个连接通道, 通过通道进行数据的传输的. 是可靠的协议,而
如何保证可靠性? 传输数据时,如果数据丢失,重发数据,保证数据的完整性。但是速度相对于
UDP稍慢.适合文件传输。
常见的命令:
ipconfig 查看本机ip 地址
ipconfig /all
ping ip地址|主机名 测试网络连接.
ping 127.0.0.1 拼本机.
ping localhost
3. InetAddress
ip地址是一类事物.在java 就被封装为了一个类.这个类就是InetAddress
4.java 的UDP 实现.
针对udp协议的实现...
设计专业的类来支持udp
|---DatagramPacket
表示数据报包.
构造函数: DatagramPacket(byte[] buf, int length)
构造 DatagramPacket,用来接收长度为 length 的数据包。
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
|---DatagramSocket
发送和接收数据报包.
send(DatagramPacket packet); 发送数据报包
receive(DatagramPacket packet); 接收数据报包.
close(); 关闭socket 释放资源.
5.java 的tcp 实现.
针对tcp 协议的实现...
特点: 通过三次握手建立连接通道. 可靠的,速度稍慢(相对于UDP).
即使传输数据,数据丢失也会重发保证数据的完整性,和可靠性.
1. 客户端
Socket
2. 服务端.
ServerSocket
C/S 客户端/服务器 模式.
cf cs 手机端...
B/S 浏览器/服务器 模式.
qq客户端...
客户端和服务端建立连接,可以通信.
UDP案例1发送一句话:
发送端: public class SendDemo1 { public static void main(String[] args) throws IOException { System.out.println("udp 发送端... "); // 1. 数据. String mess = "hello,world"; // 字符串->字节 编码. byte[] datas = mess.getBytes(); // 2. 数据的长度. int length = datas.length; // 3. 目的地. 接收数据的ip InetAddress ip = InetAddress.getByName("192.168.15.10"); // 4. 目的地的端口. int port = 5000; // 5. 封装数据. 数据报包. DatagramPacket packet = new DatagramPacket(datas, length, ip, port); // 6. 发送数据报包. DatagramSocket socket = new DatagramSocket(); socket.send(packet); // 7. 关闭socket. 释放资源. socket.close(); } }
接收端: public class ReceiveDemo1 { public static void main(String[] args) throws IOException { System.out.println("udp 接收端启动"); // 1.创建DatagramPakcet -> 存储发送端发送的数据的. DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); // 2.创建DatagrameSocket-> 接收数据报包的. DatagramSocket socket = new DatagramSocket(5000); // 3.使用对象的专业方法 receive 接收数据报包. // 接收完数据, 数据都被存储到了packet 中. socket.receive(packet); // 4. 通过packet 获取数据. byte[] datas = packet.getData(); String ip = packet.getAddress().getHostAddress(); // 5. 获取接收的数据的长度. int len = packet.getLength(); // 6. 取出数据. 字节-> 字符 解码. String mess = new String(datas, 0, len); System.out.print("发送端:"+ip+"发送了:"); System.out.println(mess); // 7. 关闭socket. socket.close(); } }
循环发送数据,遇到bye结束循环发送数据
发送端: public class SendTest1 { public static void main(String[] args) throws IOException { // 1.控制台获取用户的输入. BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); // 2. 创建Socket DatagramSocket socket = new DatagramSocket(); while(true){ System.out.println("请输入:"); String mess = br.readLine(); // 3. 字符串转换为字节数组. byte[] buffer = mess.getBytes(); // 4. 创建数据报包对象,封装数据. DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getByName("192.168.15.255"), 5000);//广播发送数据 // 5. 发送数据报包. socket.send(packet); if("bye".equals(mess)){ break; } } // 6.关闭socket. socket.close(); } }
接收端: public class ReceiveTest1 { public static void main(String[] args) throws IOException { // 1. 创建Socket(套接词) . DatagramSocket socket = new DatagramSocket(5000); // 2. 创建packet(接收数据报包) DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); while (true) { // 3.使用专业的方法接收数据报包 socket.receive(packet); // 获取的是发送端的ip地址. String ip = packet.getAddress().getHostAddress(); System.out.println(ip + "进来了..."); // 4. 获取数据(获取到了存储数据的缓冲区). byte[] datas = packet.getData(); // 5 获取数据的长度. int len = packet.getLength(); // 6. 解码. String mess = new String(datas, 0, len); System.out.println(mess); if ("bye".equals(mess)) { System.out.println(ip + "离开了..."); //break; } } //socket.close(); } }
文件上传程序案例
客户端: public class Client { public static void main(String[] args) throws IOException { // 1. 控制台获取用户上传的文件的路径. File file = getFile(); System.out.println(file); // 2. 创建客户端Socket. Socket socket = new Socket("192.168.15.10", 5000); // 3. 获取客户端socket 的输入和输出流. InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); // 4. 将客户端文件的名字上传到服务器. out.write(file.getName().getBytes()); // 5. 读取服务端的返回的消息. byte[] buffer = new byte[1024]; int len; len = in.read(buffer); String mess = new String(buffer, 0, len); // 6. 根据服务端的响应,判断文件是否存在. if ("文件存在无需上传".equals(mess)) { System.out.println(mess + ",客户端程序结束!!!"); socket.close(); return; } else { System.out.println(mess); } System.out.println("客户端开始上传!!!"); // 7. 在客户端创建字节输入流. 读取客户端的文件. FileInputStream fis = new FileInputStream(file); // 8. 客户端字节输入流循环读取. while ((len = fis.read(buffer)) != -1) { // 8. 客户端socket 的输出流写出数据. out.write(buffer, 0, len); } // 9. 文件上传完毕,发送结束标记. socket.shutdownOutput(); // 10. 客户端接收服务器的返回的消息. len = in.read(buffer); System.out.println(new String(buffer, 0, len)); // 11. 关闭客户端socket 客户端字节输入流. fis.close(); socket.close(); } } public static File getFile() throws IOException { // 1.控制台获取用户需要上传的文件的路径. BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); while (true) { System.out.println("请输入上传文件的路径:"); String filePath = br.readLine(); File file = new File(filePath); // 2.路径不存在. if (!file.exists()) { System.out.println("路径不存在,请重新输入. "); continue; } // 2. 不支持目录. if (file.isDirectory()) { System.out.println("暂不支持目录上传,等待升级版!!!"); continue; } return file; } } }
服务端 public class Server { public static void main(String[] args) throws IOException { // 1. 创建服务端. System.out.println("tcp 服务器启动.准备接收文件"); ServerSocket server = new ServerSocket(5000); while (true) { // 2. accept 方法等待客户端连接. final Socket socket = server.accept(); new Thread(new Runnable() { @Override //复写run() => 创建多线程 public void run() { String ip = socket.getInetAddress().getHostAddress(); System.out.println("客户端:" + ip + "连接了.."); try { // 3. 获取服务端socket 的输入和输出流. InputStream in = socket.getInputStream(); OutputStream out = socket.getOutputStream(); byte[] buffer = new byte[1024 * 8]; int len; // 4. 服务接收文件的名字. len = in.read(buffer); String fileName = new String(buffer, 0, len); // 5. 在服务器明确该文件保存的路径... File dir = new File("e:\\upload"); // 检测该目录是否存在. 如果不存在,必须创建. if (!dir.exists()) { dir.mkdir(); } // 6. 根据客户端上传的文件名,封装为一个File 对象. File file = new File(dir, fileName); // 7. 服务器, 检测文件是否存在. 如果存在就不再重复上传. if (file.exists()) { out.write("文件存在无需上传".getBytes()); socket.close(); return; } else { out.write("文件不存在可以上传".getBytes()); } System.out.println("服务端开始接收"); // 8. 服务器创建本地的字节输出流. 将socket 读取的数据持 久化存储到服务器. FileOutputStream fos = new FileOutputStream(file); // 9. 服务器开始接收. while ((len = in.read(buffer)) != -1) { fos.write(buffer, 0, len); } System.out.println("服务器接收完毕!!!"); // 10. 服务器接收完毕,想客户端发送结束的消息. out.write("服务器成功接收完毕".getBytes()); // 11. 关闭服务端的创建的字节输出流. fos.close(); } catch (IOException e) { // e.printStackTrace(); } finally { try { socket.close(); } catch (IOException e) { // e.printStackTrace(); } System.out.println("客户端:" + ip + "离开了.."); } } }).start(); } } }