02 Socket网络编程
概述:
Socket又称为套接字,用于描述IP地址和端口,是一个通信链的句柄;
Socket是为网络编程提供的一种机制;
通信两端都有Socket,网络编程就是Socket之间的通信,数据在两个Socket之间通过IO流传输。
学习Socket编程之前,先要了解网络通信的三i个要素,即IP、端口号和传输协议。
ip是设备在网络里面的地址。
端口号是用于标识进程的逻辑地址
- 每个网络程序都会至少有一个逻辑端口
- 用于标识进程的逻辑地址,不同进程的标识
- 有效端口:0-65535,其中0-1024系统使用或保留端口
协议:主要有UDP协议和TCP协议
- UDP协议是将数据源和目的封装成数据包,不需要建立连接,并且每个数据包的大小限制在64k,是一种不可靠协议,优点在于速度快。
- TCP协议是建立连接,并形成数据传输的通道;可以在连接中传输大量的数据;通过三次握手完成连接,是一种可靠协议,但效率较低。
下面就围绕UDP和TCP这两种协议进行网络编程:
1.UDP协议
- 发送端执行步骤
- 创建发送端Socket对象
- 创建数据并打包
- 发送数据
- 释放资源
代码如下:
public static void main(String[] args) throws Exception { //创建发送端Socket对象 DatagramSocket socket = new DatagramSocket(); //创建数据并打包 //DatagramPacket(byte buf[], int length, InetAddress address, int port) String message = "hello,UDP,I'm sender"; byte[] bytes = message.getBytes(); int length = bytes.length; InetAddress address = InetAddress.getByName("DESKTOP-KHNDCKQ"); int port =8888; DatagramPacket p = new DatagramPacket(bytes,length,address,port); //发送数据 socket.send(p); //释放资源 socket.close(); }
需要注意的是,发送端发送数据,需要指定目标ip或主机名,以及端口号。
- 接收端执行步骤
- 创建接收端Socket对象
- 接收数据
- 解析数据
- 输出数据
- 释放资源
代码如下:
//创建接收端对象 DatagramSocket socket = new DatagramSocket(8888); //接收数据 byte[] bytes = new byte[1024]; DatagramPacket data = new DatagramPacket(bytes,bytes.length); socket.receive(data);//阻塞 //解析数据 InetAddress address = data.getAddress();//获取发送端IP byte[] receivedata = data.getData(); int length = data.getLength(); //输出数据 System.out.println("send--->>"+address.getHostAddress()); System.out.println(new String(receivedata,0,length)); System.out.println(new String(bytes,0,length)); //释放资源 socket.close();
说明:在接收端运行的时候,程序会在
socket.receive(data);
这一步进行阻塞,也就是等待发送端发送数据。接收的时候,也是用DatagramPacket类进行接收。
获取数据的方式有两种,一个是构造方法中传入的bytes参数,接受到数据后会直接写到bytes里;还有一种接受方式是通过DatagramPacket实例化对象的getData()方法,赋值给任意要给byte数组。
当然,在Socket编程中有一些墨守成规的规定,也是需要遵守的。
注意事项:
- 如果发送端发送的端口号是错误的,因为UDP是一种不需要建立连接的协议,所以这个数据是可以正常发出去的,也不会出现异常。但是接收方无法接收到数据
- 端口号的作用和属性前面也描述了,所以一个端口一次只能给一个进程使用,如果已经被使用的端口,其他程序想要去使用就会抛出端口被占用的异常。
2.TCP协议
- 发送端执行步骤
- 创建发送端Socket对象(创建连接)
- 获取输出流对象
- 发送数据
- 释放资源
具体代码如下:
public static void main(String[] args) throws IOException { //创建发送端Socket对象(创建连接) Socket socket = new Socket(InetAddress.getByName("DESKTOP-KHNDCKQ"),8899); //获取输出流对象 OutputStream out = socket.getOutputStream(); //发送数据 String str = "hello,TCP,I'm sender"; out.write(str.getBytes()); //释放资源 //out.close(); socket.close(); }
在TCP协议中,客户端(发送端)使用的是Socket对象。而流就相当于管道一样,TCP协议的所有数据都是从管道里传输的。这里需要注意的是,Socket对象除了能获取输出流对象,也能获取输入流对象,这样发送端并不一定只能发送。也是能够获取到数据的。
- 接收端执行步骤
- 创建接收端Socket对象
- 监听(阻塞)
- 获取输入流对象
- 获取数据
- 输出数据
- 释放资源
具体代码如下:
//创建接收端Socket对象 ServerSocket serverSocket = new ServerSocket(8899); //监听(阻塞) Socket socket = serverSocket.accept(); //获取输入流对象 InputStream inputStream = socket.getInputStream(); //获取数据 byte[] bytes = new byte[1024]; int length = inputStream.read(bytes);//用于存储读取到的字节个数 //输出数据 InetAddress inetAddress = socket.getInetAddress(); System.out.println("sender-->"+inetAddress.getHostAddress()); System.out.println(new String(bytes,0,length)); //释放资源 socket.close(); //serverSocket.close(); }
接收端我们用的是ServerSocket类而不是Socket,这一点需要注意
最后一行把服务端关闭方法给注释了,这是因为现实生产场景中,并不是通信一次就直接结束。所以我们的服务端一般情况下可以不用关闭,用于下一次的接收。
第二步我们需要创建监听,就是用服务端的ServerSocket去创建Socket对象,因为只有在这个对象中我们才可以去调用创建输入、输出流的方法,从而进一步去拿到传输的数据。