目录
- 初识UDP(编写一个回显服务器)
- UDP socket API的使用
- 实现一个回显服务器
- 服务器代码
- 客户端代码
- 实现效果
- 代码解释
- 流程解释
初识UDP(编写一个回显服务器)
UDP 是传输层的协议
操作系统提供了UDP API(操作系统提供给我们进行网络编程的API叫做“socket API”---->“网络编程套接字”
想必大家应该听说过 UDP的特点:无连接,不可靠传输,面向数据报,全双工
UDP socket API的使用
核心的类有两个:
1.DatagramSocket
(操作系统中有一类文件,就叫做socket文件。通过网卡发送数据,就是写socket文件,通过网卡接收数据,就是读socket文件)、
负责对socket文件读写,也就是借助网卡发送接收数据
2.DatagramPacket
UDP面向数据报,每次发送接收数据的基本单位,就是UDP数据包
DatagramPacket表示了一个UDP数据报
实现一个回显服务器
回显服务器是网络编程中最简单的程序了,属于网络编程的hello world
回显服务器:客户端发啥请求就返回啥响应,没有啥业务逻辑
通过实现这个回显服务器,我们就能知道socket API 的使用,还有典型的客户端服务器基本工作流程
服务器代码
服务器来说:
第一步,需要创建DatagramSocket对象
接下来要操作网卡,操作网卡都是通过socket对象来完成的(socket对象是在内存中,针对这个内存进行操作就能影响到网卡)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private DatagramSocket socket=null;public UdpEchoServer(int port) throws SocketException {socket=new DatagramSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");while(true){DatagramPacket requestPacket=new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);String request=new String(requestPacket.getData(),0,requestPacket.getLength());String response=process(request);DatagramPacket responsePacket =new DatagramPacket(response.getBytes(),response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}public String process(String request){return request;}public static void main(String[] args) throws IOException {UdpEchoServer service=new UdpEchoServer(9090);service.start();}
}
客户端代码
编写客户端的代码
首先也是要创建socket对象。但是此处不需要手动指定端口号。
服务器这边,要手动指定端口。
客户端这边,一般不要手动指定。不手动指定,也有端口,系统自动分配一个空闲的端口号
import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket=null;private String serverIp;private int serverPort;// 此处 ip 使用的字符串, 点分十进制风格. "192.168.2.100"public UdpEchoClient(String serverIp,int serverPort) throws SocketException {this.serverIp=serverIp;this.serverPort=serverPort;socket=new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动!");Scanner scanner=new Scanner(System.in);while (true){//要做四个事情//1.提示用户接下来要输入内容System.out.println("->");//2.从控制台读取要发送的请求数据if(!scanner.hasNext()){break;}String request=scanner.next();//3.构造请求并发送DatagramPacket requestPacket=new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(serverIp),serverPort);socket.send(requestPacket);//4.读取服务器的响应DatagramPacket responsePacket=new DatagramPacket(new byte[4096],4096);socket.receive(responsePacket);//5.把响应显示到控制台上String response=new String(responsePacket.getData(),0,responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client=new UdpEchoClient("127.0.0.1",9090);client.start();}
}
实现效果
代码解释
服务器程序一启动就需要关联上/绑定一个操作系统中的端口号(手动指定一个端口号)
对于服务器来说,需要不停的收到请求,返回响应,收到请求,返回响应
服务器往往是7*24小时运行的,要持续不断地运行下去,这里的while(true)也没有退出的必要,如果你确实想重启服务器咋办,可以直接杀进程即可。
流程解释
整个过程中,首先一定是服务器先启动
- 服务器启动。启动之后,立即进入while循环,执行到receive,进入阻塞。此时没有任何客户端发来请求呢
- 客户端启动。启动之后,立即进入while循环,执行到hasNext这里进入阻塞。此时用户没有在控制台输入任何内容
- 用户在客户端的控制台中输入字符串,按下回车。此时hasNext阻塞解除,next会返回刚才输入的内容。
基于用户输入的内容,构造出一个DatagramPacket对象,并进行send
send执行完毕之后,继续执行到receive操作,等待服务器返回的响应数据(此时服务器还没返回响应呢,这里也会阻塞) - 服务器收到请求之后,就会从receive的阻塞中返回。
返回之后,就会根据读到的DatagramPacket对象,构造String request,通过process方法构造一个String response
再根据response构造一个DatagramPacket表示响应对象,再通过send来进行发送给客户端
执行这个过程中,客户端也始终在阻塞等待 - 客户端从receive中返回执行,就能够得到服务器返回的响应。并且打印倒控制台上。
与此同时,服务器进入下一次循环,也要进入到第二次的receive阻塞,等待下个请求了。
上述代码中,可以看到,UDP是无连接的通信,UDP socket自身不保存对端的IP和端口,而是在每个数据报中有一个
另外代码中也没有"建立连接""接受连接"操作 不可靠传输,代码中体现不到的。
面向数据报,send和receive都是以DatagramPacket为单位。