简体   繁体   English

Java 套接字数据仅在发送时间延迟时才起作用

[英]Java socket data works only when sending time is delayed

I am sending a protobuf from C++ to Java via a raw socket, the C++ program being the client and the java program being the server.我通过原始套接字将 protobuf 从 C++ 发送到 Java,C++ 程序是客户端,java 程序是服务器。 The C++ program generates packets almost every 1ms which is sent to the java program. C++ 程序几乎每 1ms 生成一次数据包,发送给 java 程序。

If I run the program normally, I see that there are only the half the packets being received.如果我正常运行程序,我看到只有一半的数据包被接收。

If I set a breakpoint in the C++ program and then run the client and the server, all the packets are received.如果我在C++程序中设置断点,然后运行客户端和服务器,所有的数据包都被接收。

How do I ensure that all packets are received without setting a breakpoint?如何确保在不设置断点的情况下接收所有数据包? Can I introduce a delay?我可以引入延迟吗?

All the packets have bytes sizes upto a maximum of 15 bytes.所有数据包的字节大小最多为 15 个字节。

By default TCP sockets use the "Nagle Algorithm" which will delay transmission of the next "unfilled" fragment in order to reduce congestion.默认情况下,TCP 套接字使用“Nagle 算法”,它会延迟下一个“未填充”片段的传输以减少拥塞。 Your packet size is small enough and the time delay between packets is small enough that the nagle algorithm will have an effect on your transmissions.您的数据包大小足够小,数据包之间的时间延迟足够小,因此 nagle 算法将对您的传输产生影响。

As already discussed in the comments, what you are trying to do won't work in a reliable way.正如评论中已经讨论的那样,您尝试做的事情不会以可靠的方式工作。 This is also described in the Protobuf documentation :这也在Protobuf 文档中有所描述:

If you want to write multiple messages to a single file or stream, it is up to you to keep track of where one message ends and the next begins.如果您想将多条消息写入单个文件或流,则由您来跟踪一条消息的结束位置和下一条消息的开始位置。 The Protocol Buffer wire format is not self-delimiting, so protocol buffer parsers cannot determine where a message ends on their own. Protocol Buffer 线格式不是自定界的,因此 Protocol Buffer 解析器无法自行确定消息的结束位置。 The easiest way to solve this problem is to write the size of each message before you write the message itself.解决这个问题最简单的方法是在写消息本身之前写下每条消息的大小。 When you read the messages back in, you read the size, then read the bytes into a separate buffer, then parse from that buffer.当您读回消息时,您读取大小,然后将字节读入单独的缓冲区,然后从该缓冲区解析。 (If you want to avoid copying bytes to a separate buffer, check out the CodedInputStream class (in both C++ and Java) which can be told to limit reads to a certain number of bytes.) (如果您想避免将字节复制到单独的缓冲区,请查看 CodedInputStream 类(在 C++ 和 Java 中),它可以被告知将读取限制为一定数量的字节。)

The bold italic part is where you code isn't correct.粗斜体部分是您编码不正确的地方。

On the write side you should write在写方面,你应该写

  1. the Protobuf's length in some format that is understandable for both sender and receiver (selecting the proper format is especially important when transporting between systems whose endianness is different). Protobuf 的长度以某种格式为发送方和接收方都可以理解(在字节序不同的系统之间传输时,选择正确的格式尤其重要)。
  2. the protobuf protobuf

On the receiving end you need to在接收端,您需要

  1. perform a read with the fixed , known size of the length field使用长度字段的固定、已知大小执行读取
  2. a read for the length learned in step 1. This read will retriev the protobuf.读取步骤 1 中学习的长度。此读取将检索 protobuf。

There's example code here on SO in this question: Sending struct via Socket using JAVA and C++在这个问题中,SO 上有示例代码: Sending struct via Socket using JAVA and C++

@fvu: This is my code which I am trying: @fvu:这是我正在尝试的代码:

import Visualization.DataSetProtos.PacketData; // protos import

import java.io.InputStream;
import java.util.Arrays;
import javax.swing.JFrame;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;


class WorkerThread extends Thread {
Socket service;
static DynamicData demo;
static int size;
static int times;
static byte[] buffer;

WorkerThread(Socket service) 
{
    this.service = service;
    buffer = new byte[500];
    size = 1;
    times = 0;
}

static void Print(PacketData packetData) 
{
    System.out.print("Packet Number: " + (++times));
    System.out.print("  DataSet Size: " + packetData.getLength() + "\n");

}

static void Print(PacketHeader packetHeader) 
{
    System.out.print("Packet Number: " + (++times));
    System.out.print("  DataSet Size: " + packetHeader.getLength() + "\n");

}

public void run() {
boolean flag=true;    //you can change this flag's condition, to test if the client disconects

    if(demo == null)
    {
        demo = new DynamicData("GridMate Data Visualization");
        demo.pack();
        RefineryUtilities.centerFrameOnScreen(demo);
        //demo.setVisible(true);
    }
try
{
    while (flag)
    {

        InputStream inputStream = service.getInputStream();
        int read;
        read = inputStream.read(buffer);

        byte[] readBuffer = new byte[read];
        readBuffer = Arrays.copyOfRange(buffer, 0, read);
        PacketData packetData = PacketData.parseFrom(readBuffer);
        Print(packetData);


    }
    service.close();
}
catch(Exception e)
    {
        e.printStackTrace();
    }
}
}



public class Test
{
Test()
{
   server = null;
   client= null;
}
public static void main(final String[] args) {
    int i =0;
    try 
    {
        server = new ServerSocket(25715);

    System.out.println("Server setup and waiting for client connection ...");

            while(true)
            {
                client = server.accept();
                WorkerThread wt = new WorkerThread(client);
                wt.start();
                i++; 
           }
    }
  catch(IOException e)
  { System.out.println("IO Error in streams " + e);
    e.printStackTrace();
  }

}
 public void finalize()
 {
    try
    {
        server.close();
        client.close();
    }
    catch(Exception e)
    {
       e.printStackTrace();
    }

   }

    static ServerSocket server;
    static Socket client;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM