UDP:用户数据报协议
特点:
①无连接;②不可靠传输;③面向数据报;④全双工
TCP:传输控制协议
特点:
①有连接;②可靠传输;③面向字节流;④全双工
无连接:使用UDP通信的双方,不需要刻意保存对端的基本信息,不需要接收连接也能通信
(比如使用微信发送,及时他没有登录微信,我也可以将我的内容发送给他)
有连接:使用TCP通信的双方,则需要可以保存对端的基本信息,需要先接收连接才能通信
(比如打电话,要记录对方的电话号码,当我拨打电话时,对方必须接通才能进行通话)
不可靠传输:消息发送了,但是并不关注是否发送成功
可靠传输:消息发送了,不能百分百的发送到达对方,但是尽可能的传输过去
面向数据报:以一个UDP数据报为单位
面向字节流:以字节为单位传输,读写方式灵活
全双工:一条路径,双向通信
要想进行通信,需要有socket文件这样的对象,借助socket文件对象间接操作网卡
往这个socket文件里面写数据,相当于通过网卡发送数据;往这个socket文件里面读数据,相当于通过网卡接收消息
UDP数据报套接字变成
DatagramSocket 是UDP Socket,用于发送和接受UDP数据
对象 是一个socket对象
构造方法:
①DatagramSocket():
创建一个UDP数据包套接字的Socket,绑定到本机任意一个随机端口
(无参数的一般用于客户端,客户端不需要手动指定端口号,系统会自动分配)
②DategramSocket(int port):
创建一个UDP数据包套接字的Socket,绑定到本机指定的端口
(一般用于服务端,需要手动提供端口号)
方法:
①void receive():从套接字接收数据,若没有数据,receive会阻塞等待,直到有数据为止
②void send():从套接字中发送数据报
③void close():关闭数据包套接字
DatagramPacket是UDP Socket发送和接受数据的数据报
构造方法:
①DatagramPacket(byte[] buf,int length):
构造一个DatagramPacket用来接收数据报,第一个参数是存放数据报的内容,第二个参数是这个数据包的长度
②DatagramPacket(byte[] buf,int offset.int length,SocketAddress address):
构造一个DatagramPacket用来发送数据报,第一个参数是数据报的内容,第二个参数是想要发送数据报内容的起始位置,第三个参数是想要发送的数据报长度,第四个参数是指定目的主机的端口号和ip
以UDP来实现一个简单的回显服务器
客户端发送一个请求,服务器响应一个一模一样的请求
同一个主机上,一个端口号同一时刻只能被一个进程使用
服务端:
public class UdpEchoSevert { //要进行通信,必须要有socket对象 DatagramSocket socket = null; //服务端要指定端口号,所以在构造方法中,创建socket对象并且指定绑定的端口号 public UdpEchoSevert(int port) throws SocketException { socket = new DatagramSocket(port); } //服务器启动 public void star() throws IOException { while(true) { System.out.println("服务器启动:"); //1.读取请求并分析 //创建一个长度为4090的数据报,目前里面还没有存放东西 DatagramPacket requestPacket = new DatagramPacket(new byte[4090],4090); socket.receive(requestPacket);//将读取到的信息放入到这个数据包中 //为了方便计算响应,将数据包转换成String类型 //requestPacket.getData()获取到数据包的内容,从0位置开始,到这个数据包的长度 String request = new String(requestPacket.getData(),0, requestPacket.getLength()); //2.根据请求计算响应 String respond = process(request); //计算的响应结果放到响应的数据包中,构造响应要指定将这个数据报发送给谁 //respond.getBytes()响应结果内容的起始位置,respond.getBytes().length响应结果内容的长度 // requestPacket.getSocketAddress()获取到ip和端口号 DatagramPacket respondPacket = new DatagramPacket(respond.getBytes(),respond.getBytes().length, requestPacket.getSocketAddress()); socket.send(respondPacket); System.out.printf("[%s:%d] req: %s, rest: %s\n",requestPacket.getAddress().toString(), requestPacket.getPort(),request,respond); } } public static String process(String request) { return request; } public static void main(String[] args) throws IOException { UdpEchoSevert udpEchoSevert = new UdpEchoSevert(9090); udpEchoSevert.star(); } }
客户端:
public class UdpEchoClient { //进行通信要有socket对象 private DatagramSocket socket = null; private String severtIp;//ip private int severtPort;//端口号 //构造socket对象,并且不需要手动指定端口号,在传输时需要明确ip和端口号 public UdpEchoClient(String severtIp,int severtPort) throws SocketException { //客户端不需要手动指定要进行通信的端口号 socket = new DatagramSocket(); this.severtIp = severtIp; this.severtPort = severtPort; } // public void star() throws IOException { //不断的发送请求 Scanner scanner = new Scanner(System.in); while(true) { //1.读取用户从控制台输入的数据 System.out.println("请输入:"); String request = scanner.nextLine(); //2.构造请求数据包并发送数据包 //request.getBytes()获取用户输入的内容 request.getBytes().length内容的的长度是数据包的长度 //构造发送数据报,要指定目的主机的ip和端口号 DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length, InetAddress.getByName(severtIp),severtPort); //客户端发送请求 socket.send(requestPacket); //3.接受服务端的响应 DatagramPacket respondPacket = new DatagramPacket(new byte[4090],4090); socket.receive(respondPacket);//receive将接受到的响应内放到respondPacket报里面 //4.将响应内容转化成字符串,显示在控制台上 String respond = new String(respondPacket.getData(),0,respondPacket.getLength()); System.out.printf("req : %s , resp : %s\n",request,respond); } } public static void main(String[] args) throws IOException { UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1",9090); udpEchoClient.star(); } }
服务端显示的结果:
客户端显示的结果: