使用UDP协议实现客户端与服务端相互通信

UDP协议

1. UDP协议(中文名:用户数据报协议)是一种无连接、不可靠的传输协议。该协议与TCP协议一样用于处理数据包,在OSI模型中,两者都位于传输层,处于IP协议的上一层。

2. UDP报头由4个域组成,其中每个域各占用2个字节,具体包括源端口号、目标端口号、数据报长度、校验值。因为UDP报头使用两个字节存放端口号,所以端口号的有效范围是从0到65535。从理论上说,包含报头在内的数据报的最大长度为65535字节约等于64KB。

3. 这里需要注意,在使用UDP协议传输数据时,是无法得知数据是否安全完整的到达客户端。在网络状况不佳时,会对传输结果造成影响,容易产生丢包的现象。

模型结构图

《使用UDP协议实现客户端与服务端相互通信》

操作步骤

使用UDP协议进行通信分为客户端(发送方)和服务端(接收方),客户端负责发送指定的数据到客户端,服务端负责接收客户端发送的数据。但是如果这样去实现的话只能做到客户端于服务端的单向通信,只能是客户端向服务端发送数据,服务端并不能发送数据到客户端,做不到客户端与服务端之间的相互通信。
如果想实现客户端与服务端之间的相互通信,则每一个客户端内都要存在一个服务端用于接收客户端发送的数据,而每一个服务端内都要存在一个客户端用于发送数据,即你中有我,我中有你。

创建客户端(发送端)

1.使用DatagramSocket套接字指定端口,创建发送端。
2.将需要发送的数据转换成字节数组。
3.将字节数组封装成DatagramPacket数据包,并指定目的地。
4.发送数据包调用DatagramSocket类的send方法。
5.释放资源。

创建服务端(接收端)

1.使用DatagramSocket套接字指定端口,创建接收端。
2.准备接收数据的容器,将这个容器封装成DatagramPacket。
3.阻塞式接收数据包,调用DatagramSocket类的receive方法。
4.调用DatagramPacket类的getData方法和getLenght方法,分别获取到接收的数据和数据长度。
5.释放资源。

实现代码

客户端代码

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.SocketException;
import java.util.Scanner;

/**
 * 客户端(发送端)
 * 
 * @author 谈笑、
 * 时间:2020年1月27日
 */
public class UdpClient implements Runnable {

  // 创建客户端
  private DatagramSocket ds;
  // 封装数据包
  private DatagramPacket dp;
  // 解析主机
  private InetSocketAddress is;
  // 接收键盘输入的数据
  private Scanner sc;
  
  public UdpClient(int cProt, String sIp, int sProt) {
    // 实例化InetSocketAddress类,根据指定的ip和端口解析主机。
    try {
      // 实例化DatagramSocket类,创建客户端并设置客户端端口。
      this.ds = new DatagramSocket(cProt);
    } catch (SocketException e) {
      e.printStackTrace();
    }
    this.is = new InetSocketAddress(sIp, sProt);
    this.sc = new Scanner(System.in);
  }
  
  @Override
  public void run() {
    while(true) {
  			// 接收键盘输入的数据
      String input = this.sc.next();
      byte[] data = input.getBytes();
      // 将数据分装成DatagramPacket数据包,并指定数据包的接收地址。
      this.dp = new DatagramPacket(data, 0, data.length, this.is);
      try {
        // 发送数据包
        this.ds.send(this.dp);
      } catch (IOException e) {
        e.printStackTrace();
      }
    }
  }
  
  public static void main(String[] args) {
    
    Thread a = new Thread(new UdpClient(20001, "localhost", 10001));
    a.start();
    
    // 在客户端内启动一个服务端线程
    Thread b = new Thread(new UdpServer(10002, "A"));
    b.start();
    
  }

}

服务端代码

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;

/**
 * 服务端(接收端)
 * 
 * @author 谈笑、
 * 时间:2020年1月27日
 */
public class UdpServer implements Runnable {

  // 创建服务端端
  private DatagramSocket ds;
  // 解析数据包
  private DatagramPacket dp;
  // 指定数据客户端名称
  private String name;
  public UdpServer(int sProt, String name) {
    try {
      this.ds = new DatagramSocket(sProt);
    } catch (SocketException e) {
      e.printStackTrace();
    }
    this.name = name;
  }
  
  @Override
  public void run() {
    while(true) {
      byte[] temp = new byte[1024 * 10];
      // 将字节数组封装成DatagramPacket数据包,存储接收的数据。
      this.dp = new DatagramPacket(temp, 0, temp.length);
      try {
        this.ds.receive(this.dp);
      } catch (IOException e) {
        e.printStackTrace();
      }
      // 将接收到的字节数据转换为字符串
      String data = new String(this.dp.getData(), 0, this.dp.getLength());
      System.out.println(this.name + ":" + data);
    }
  }
  
  public static void main(String[] args) {
    
    // 在服务端内启动一个客户端线程
    Thread a = new Thread(new UdpClient(20002, "localhost", 10002));
    a.start();
    
    Thread b = new Thread(new UdpServer(10001, "B"));
    b.start();
    
  }

}

 

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注