当前位置: 首页 > 知识库问答 >
问题:

如何在UDP协议上同步通信?

梁池暝
2023-03-14

我运行了一个模拟测试,以了解UDP通信面临的问题。

我有一个主机,其中有4个UDP客户机正在运行,每个客户机都有自己的线程(T1、T2、T3和T4)。T1和T2共享一个名为socket的DatagramSocket对象,而T3和T4共享一个名为socket2的DatagramSocket对象。

T1和T2正在发送和接收来自IP(例如)udpServer1的UDP服务器的回波,而T3和T4正在与udpServer2通信。

当并行运行线程时,我能够同步共享相同DatagramSocket和Runnable对象的T1和T2。然而,当尝试运行使用不同DatagramSocket和Runnable对象的T1和T3时,T3总是在SocketTimeoutExc0019下失败,但是T1可以毫无问题地发送和接收数据包。

总之:

>

  • 并行运行T1和T2(或T3和T4),共享相同的DatagramSocket和Runnable对象--

    并行运行T1和T3,每个都使用自己的DatagramSocket和Runnable对象--

    为什么T3在自己的DatagramSocket上并在自己的线程上运行时,仍然会获得SocketTimeoutExcsion?我到底做错了什么?

    任何帮助都非常感谢。谢谢。

    @Test
    public void sendRemoteTest() throws InterruptedException, IOException {
        DatagramSocket socket = new DatagramSocket(9987, InetAddress.getByName(localMachineIp));
        DatagramSocket socket2 = new DatagramSocket(9988, InetAddress.getByName(localMachineIp));
        UdpClientRunnable runnable = new UdpClientRunnable(socket, 1);
        UdpClientRunnable runnable2 = new UdpClientRunnable(socket2, 1);
       
        Thread t1 = new Thread(runnable);
        t1.setName("T1");
        Thread t2 = new Thread(runnable);
        t2.setName("T2");
        Thread t3 = new Thread(runnable2);
        t3.setName("T3");
        Thread t4 = new Thread(runnable2);
        t4.setName("T4");
        t1.start();
        t2.start();
        t3.start();
        t4.start();
        Thread.sleep(10000);
        t1.join();
        t2.join();
        t3.join();
        t4.join();
    }
    
    private byte toByte(int num) {
        return (byte) ((byte) (0xFF) & num);
    }
    
    public class UdpClientRunnable implements Runnable {
        private DatagramSocket socket;
        private long delayMillis;
        private byte[] dataToSend;
    
        public UdpClientRunnable(DatagramSocket socket, long delayMilis) {
           this.socket = socket;
           this.delayMillis = delayMilis;
        }
    
        @Override
        public synchronized void run() {
           byte[] data1 = new byte[] { toByte(0x01), toByte(0x01), toByte(0x01),
              toByte(0x01), toByte(0x01) };
           byte[] data2 = new byte[] { toByte(0x02), toByte(0x02), toByte(0x02),
              toByte(0x02), toByte(0x02) };
           byte[] data3 = new byte[] { toByte(0x03), toByte(0x03), toByte(0x03),
              toByte(0x03), toByte(0x03) };
           byte[] data4 = new byte[] { toByte(0x04), toByte(0x04), toByte(0x04),
              toByte(0x04), toByte(0x04) };
    
           String targetIp = "";
           String name = Thread.currentThread().getName();
           if (name.contains("T1")) {
              dataToSend = data1;
              targetIp = udpServer1;
           }
           else if (name.contains("T2")){
              dataToSend = data2;
              targetIp = udpServer1;
           }
           else if (name.contains("T3")) {
              dataToSend = data3;
              targetIp = udpServer2;
           }
           else {
              dataToSend = data4;
              targetIp = udpServer2;
           }
           int count = 0;
           while (count < 250) {
              try {
                 sendAndReceive(targetIp, name, count, dataToSend);
                 Thread.sleep(delayMillis);
              }
              catch (IOException | InterruptedException e) {
                 System.out.println(e + ": " + name + ", iter: " + count);
              }
              finally {
                 ++count;
              }
           }
        }
    
        private synchronized void sendAndReceive(String targetIp, String threadName, int count, byte[] dataToSend) throws IOException, UnknownHostException, SocketException {
            byte[] rcvData = new byte[5];
            DatagramPacket rcvPacket = new DatagramPacket(rcvData, rcvData.length);
            socket.send(new DatagramPacket(dataToSend, 5, InetAddress.getByName(targetIp), 9999));
            socket.setSoTimeout(2000);
            rcvPacket = new DatagramPacket(rcvData, rcvData.length);
            socket.receive(rcvPacket);
            printData(threadName, count, rcvData);
            if (threadName.contains("T1")) {
                Assert.assertArrayEquals(new byte[] { toByte(0x01), toByte(0x01), toByte(0x01),
                    toByte(0x01), toByte(0x01) }, rcvData);
            }
            else if (threadName.contains("T2")){
                Assert.assertArrayEquals(new byte[] { toByte(0x02), toByte(0x02), toByte(0x02),
                    toByte(0x02), toByte(0x02) }, rcvData);
            }
            else if (threadName.contains("T3")){
                Assert.assertArrayEquals(new byte[] { toByte(0x03), toByte(0x03), toByte(0x03),
                    toByte(0x03), toByte(0x03) }, rcvData);
            }
            else if (threadName.contains("T4")){
                Assert.assertArrayEquals(new byte[] { toByte(0x04), toByte(0x04), toByte(0x04),
                    toByte(0x04), toByte(0x04) }, rcvData);
            }
        }
    
        private void printData(String name, int count, byte[] rcvData) {
            String prefix = "";
            for (int i = 0; i < rcvData.length; i++) {
                prefix = (i == 0) ? (name + " iter " + count + ": ") : "";
                System.out.print(prefix + Integer.toHexString((byte) ((byte) (0xFF) & rcvData[i])) + " ");
            }
            System.out.println();
        }
      
    }
    
  • 共有1个答案

    赫连卓
    2023-03-14

    查看代码,有两台服务器位于两台不同的机器上,我假定侦听的是同一端口999。因此,我认为问题可能在于服务器代码。当你回复客户时,你是这样做的吗

    byte[] rcvData = new byte[5];
    DatagramPacket rcvPacket = new DatagramPacket(rcvData, rcvData.length);
    socket.receive(rcvPacket);
    DatagramPacket sendPacket = new DatagramPacket(rcvPacket.getData(), rcvPacket.getLength(), rcvPacket.getAddress(), rcvPacket.getPort());  // note that here we need to use the received packet information on where to send the response back
    socket.send(sendPacket);
    

    很少有其他评论

    1. 将构造函数UdpClientRunnable设置为附加输入目标端口和目标地址,这样就不需要在其中包含所有if-else块
     类似资料:
    • UDP协议是一个简单的面向数据报的传输层协议,它是一种不可靠数据报协议。由于缺乏可靠性且属于非连接导向协定,UDP应用一般必须允许一定量的丢包和出错。 Chrome提供sockets.udp接口使Chrome应用可以进行UDP通信。要使用sockets.udp接口需要在sockets域中声明udp权限: "sockets": { "udp": { "send": ["192

    • 主要内容:本节引言:,1.服务端实现步骤:,2.客户端实现步骤:,本节小结:本节引言: 本节给大家带来Socket的最后一节:基于UDP协议的Socket通信,在第一节中我们已经详细地 比较了两者的区别,TCP和UDP最大的区别在于是否需要客户端与服务端建立连接后才能进行 数据传输,如果你学了前两节TCP的,传输前先开服务端,accept,等客户端接入,然后获得 客户端socket然后进行IO操作,而UDP则不用,UDP以数据报作为数据的传输载体,在进行传输时 首先要把传

    • 我们已经讲解了物理层、连接层和网络层。最开始的连接层协议种类繁多(Ethernet、Wifi、ARP等等)。到了网络层,我们只剩下一个IP协议(IPv4和IPv6是替代关系)。进入到传输层(transport layer),协议的种类又开始繁多起来(比如TCP、UDP、SCTP等)。这就好像下面的大树,根部(连接层)分叉很多,然后统一到一个树干(网络层),到了树冠(传输层)部分又开始开始分叉,而每

    • 如何定制协议 实际上制定自己的协议是比较简单的事情。简单的协议一般包含两部分: 区分数据边界的标识 数据格式定义 一个例子 协议定义 这里假设区分数据边界的标识为换行符”\n”(注意请求数据本身内部不能包含换行符),数据格式为Json,例如下面是一个符合这个规则的请求包。 {"type":"message","content":"hello"}   注意上面的请求数据末尾有一个换行字符(在PHP中

    • 本文向大家介绍TCP、UDP 协议的区别?相关面试题,主要包含被问及TCP、UDP 协议的区别?时的应答技巧和注意事项,需要的朋友参考一下 tcp 和 udp 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。 两者的区别大致如下: tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接; tcp 提供可靠的服务(数据

    • UDP 简介 UDP 是一个简单的传输层协议。和 TCP 相比,UDP 有下面几个显著特性: UDP 缺乏可靠性。UDP 本身不提供确认,序列号,超时重传等机制。UDP 数据报可能在网络中被复制,被重新排序。即 UDP 不保证数据报会到达其最终目的地,也不保证各个数据报的先后顺序,也不保证每个数据报只到达一次 UDP 数据报是有长度的。每个 UDP 数据报都有长度,如果一个数据报正确地到达目的地,