【问题标题】:Why do I receive only 64K data in socket communication between C and Java code?为什么我在 C 和 Java 代码之间的套接字通信中只收到 64K 数据?
【发布时间】:2014-09-08 12:56:15
【问题描述】:

我使用套接字作为 C 程序和 Java 程序之间的桥梁。 C 端是服务器套接字,从 Java 端接收数据,处理数据并返回结果。 Java 端是客户端套接字,将数据发送到 C 端进行处理,然后从 C 端接收结果。

C 端代码(服务器):

const int SOCKET_BUF_IN_LEN = 160024;    //socket_buf_in length
const int SOCKET_BUF_OUT_LEN = 5000;     //socket_buf_out length

unsigned char socket_buf_in[SOCKET_BUF_IN_LEN];
unsigned char socket_buf_out[SOCKET_BUF_OUT_LEN];
struct AlgSocketIn alg_socket_in;
struct AlgSocketOut alg_socket_out;

//... some socket connection setup code 
setsockopt(new_socket_fd, SOL_SOCKET, SO_RCVBUF, &SOCKET_BUF_IN_LEN, sizeof(SOCKET_BUF_IN_LEN));

bytes_recv = recv(new_socket_fd, socket_buf_in, SOCKET_BUF_IN_LEN, 0);

run_alg();    //process the data

bytes_send = send(new_socket_fd, socket_buf_out, SOCKET_BUF_OUT_LEN, 0);

如上所述,套接字发送缓冲区socket_buf_in 有 160024 个字节。我使用setsockopt() 将套接字缓冲区设置为这个大小。

Java 端代码(客户端):

public AlgOutData sendRecvData(AlgInData inData, int portNum) {
    AlgOutData outData = new AlgOutData();
    Socket sock = new Socket("localhost", portNum);
    int sentBytes, recvBytes;
    sock.setSendBufferSize(160024);
    sentBytes = serializeData(inData, sock);    //send data to server
    recvBytes = deserializeData(outData, sock); //receive result from server
    sock.close();
    return outData;
}

private int serializeData(AlgInData inData, Socket socket) throws IOException {
    int totalNumSamples = 160024;
    DataOutputStream os = new DataOutputStream(new BufferedOutputStream(socket.getOutputStream(), 160024));
    for(int i=0; i<totalNumSamples; i++) {
        os.writeByte(inData.getSamples()[i]);
    }
    os.flush();
    int numBytes = os.size();
    return numBytes;
}

但是当我同时启动 C 程序和 Java 程序并完成从 Java 端向 C 端发送字节时,我发现 C 端只从 TCP 套接字流中接收到 65536 个字节。我调试它并通过查看 C 代码中的这一行发现了这一点:

bytes_recv = recv(new_socket_fd, socket_buf_in, SOCKET_BUF_IN_LEN, 0);

完成此调用后,bytes_recv 是 65536 字节,而不是 160024 字节,这是 socket_buf_in 的长度。

但是在Java端,我发现发送的数据确实是160024字节。在serializeData(),行显示

//....      
os.flush();
int numBytes = os.size();

numBytes 是调用os.flush() 后的 160024。

那么为什么我在 C 端只得到 65536 字节的数据,而 Java 端发送所有 160024 字节的数据呢?我是否在 C 端正确使用了正确的套接字发送/接收功能?

我也尝试在 C 端使用以下代码重复接收字节流,直到接收到所有 160024 个字节:

num_bytes = 0;
while (num_bytes < SOCKET_BUF_IN_LEN) {
    bytes_recv = recv(new_socket_fd, socket_buf_in, SOCKET_BUF_IN_LEN, 0);
    if (bytes_recv < 0)
        handle_error("Error on socket recv.\n");
    num_bytes += bytes_recv;
}

但这一次,即使num_bytes 是160024,套接字缓冲区socket_buf_in[160024] 的值全为零,这是错误的。

另一方面,当我调试 Java 端代码时,我发现即使我将输出流对象 os 设置为 160024 缓冲区大小,它也只能正确写入最多 20024 字节的字节,而不是 160024 字节。

对于 160024 字节的套接字通信,C 端或 Java 端代码有什么问题?

【问题讨论】:

    标签: java c sockets tcp


    【解决方案1】:

    您的最终循环看起来几乎正确,但是您需要在将数据读入数组时移动传递给 recv 的指针。否则,每次调用都会覆盖数组的开头。类似的东西

    bytes_recv = recv(new_socket_fd, socket_buf_in+num_bytes, SOCKET_BUF_IN_LEN, 0);
    

    【讨论】:

    • 这就是原因。对于每次调用,我应该将指针移动 num_bytes。那么为什么我需要在循环中连续调用recv() 以接收所有160024 字节,即使我指定套接字缓冲区的长度为160024?是TCP协议的原因吗?
    • C 中有很多这样的命令,它们返回读取的字节数,并留给程序员继续调用函数,直到传递所有需要的数据。主要原因是这些命令中的许多(包括recv)在调用函数时可能没有所有可用的数据,因此它们返回它们所拥有的而不是等待。有些命令甚至可能不知道有多少数据可用。
    • 非常感谢您对此的解释。我确实看到每次recv() 返回一个不确定的字节数,而不是一个固定的数字。
    猜你喜欢
    • 2012-01-26
    • 1970-01-01
    • 2016-10-29
    • 1970-01-01
    • 1970-01-01
    • 2015-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多