【问题标题】:Sending int via socket from Java to C - strange results通过套接字从 Java 发送 int 到 C - 奇怪的结果
【发布时间】:2013-04-20 07:02:56
【问题描述】:

我有一个用 Java 编写的简单服务器,它只向连接的客户端发送一个整数。我有一个用 C 编写的客户端,它连接到服务器并打印出接收到的整数。

我的问题是结果各不相同。大约一半的时间执行客户端我得到正确的结果 (234),但其他时候我得到 8323072。

这是服务器:

class TCPServer {
  public static void main(String args[]) throws Exception {
     ServerSocket welcomeSocket = new ServerSocket(6789);

     while(true)
     {
        Socket connectionSocket = welcomeSocket.accept();
        System.out.println("welcomeSocket.accept() called");
        DataInputStream inFromClient = new DataInputStream(connectionSocket.getInputStream());
        DataOutputStream outToClient = new DataOutputStream(connectionSocket.getOutputStream());

        outToClient.writeInt(234);
     }
  }

}

这是客户端:

int main(int argc, char *argv[])
{
    if(argc != 4){
        printUsage();
        return;
    }

    char* serverIP = argv[1];
    char* serverPortC = argv[2];
    char* integerToSendC = argv[3];

    int serverPort = atoi(serverPortC);
    int integerToSend = atoi(integerToSendC);

    int socketDesc = socket(AF_INET, SOCK_STREAM, 0);

    if(socketDesc < 0) {
        printf("Error when creating socket\n");
        return;
    } 

    struct sockaddr_in serverAddr;
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(serverPort);
    inet_pton(AF_INET, serverIP, &serverAddr.sin_addr);

    int connection = connect(socketDesc, (struct sockaddr*) &serverAddr, sizeof serverAddr);

    if(connection < 0) {
        printf("Error when establishing connection\n");
        return;
    }

    char intBuffer[4];

    if(recv(socketDesc, intBuffer, sizeof intBuffer, 0) == -1){
        printf("Error while receiving Integer\n");
    }

    int receivedInt = ntohl(*((int *) &intBuffer));

    printf("Received int: %d\n", receivedInt);

    close(socketDesc);
}

提前感谢您的帮助!

编辑: 所以最后我做了这样的事情,只是为了任何有同样问题的人:

while(receivedBytes < 4){
    int readBytes = read(receiverSocket, &intBuffer, (sizeof intBuffer) - receivedBytes, receivedBytes);
    receivedInteger += (intBuffer << (8*receivedBytes));
    receivedBytes += readBytes;
}

【问题讨论】:

  • 可能是因为在 Java 和 C 及其相关子边界中为 int 分配了多少字节。尝试发送小数字。如果 Java 为 int 分配 4 个字节,C 分配 2 个字节。所以范围在 C 中要小得多
  • 那个数字是 2**16 * 127(即第三个字节全为 1,底部两个全为 0)
  • @LittleChild 我也这么认为,但DataOutputStream.writeInt 似乎很清楚发送四个字节,至少在 32 位运行时。
  • 你的演员阵容看起来很糟糕,更不用说非英特尔硬件上总线错误的主要位置了。您是否考虑过只是阅读int32_t。 ?
  • ntohl()之后返回的值为0x7F0000。 IE。 127 以第三个八位字节结束。我很想知道在ntohl() 之前它是什么样子的

标签: java c sockets network-programming


【解决方案1】:

您能确定您在客户端收到了sizeof intBuffer 字节吗?不,你不能,因为recv() 可能返回的字节数少于请求的字节数。

修改您的代码以循环 recv(),只要收到的字节数少于请求的字节数并且没有发生错误。

请注意,recv()ing 0 字节表示连接已被另一端关闭。

还要确保服务器端按网络字节顺序发送。

另外^2:初始化变量是个好主意(此处为intBuffer),至少在开发阶段会说:在调整阶段之前。

【讨论】:

  • 它没有解释接收到的值:123 映射到网络上的00 00 00 7B。接收到的值83230727F 00 00 00。即使读取了1个字节,也不应该是7F
  • @ValeriAtamaniouk:很可能对方挂断了连接,recv() 返回了0,因此没有记录错误消息,并且为receivedInt 打印出8323072 很简单intBuffer 的垃圾在传递给 recv() 之前没有被初始化。
  • 可能是,但这与对应部分的来源不完全匹配:DataOutputStream shell 在关闭前发送 4 个字节。
  • 感谢您的提示,循环 read() 并处理接收到的字节终于让它工作了!
【解决方案2】:

您的问题可能是由于各种数据类型的子边界。

在 Java 中,4 个字节分配给 int,2 个字节分配给 short
在 C 中,4 个字节用于long,2 个字节用于int

这意味着Java int -> C longJava short -> C int
现在,这取决于您的优先事项在哪里。

如果您想在 Java 中执行密集的数学计算并将结果通过套接字发送到 C,我建议您使用Java int -&gt; C long
如果您只想发送少量数字并在 C 中进行密集计算,请执行 Java short -> C int 转换。

希望有所帮助。

【讨论】:

  • 在 C 中,在我的电脑中,int 的 4 个字节。
  • DataOutputStream.writeInt。看来writeInt 总是以大端写入 4 个字节。只要它在 C 端正确重组为 4 字节 int,我希望这是正确的。
  • @WhozCraig 我不会用 C 编程。我只是指维基百科上基本数据类型的大小,它说 C 分配 16 位(2 个字节)因此我的答案。如果答案中有错误或者首先是错误的,请告诉我。我会立即删除它以免混淆OP
  • @LittleChild C 中 int 的大小取决于您的编译器设置和目标体系结构。它绝对可以是 32 位的,而且 OP 似乎表明,在他的情况下,它是
  • 符合标准 (C99 §5.2.4.2.1) 的 int最小 大小为 16 位 (15+1sign)。但该标准仅将价值表示作为最低合规要求。今天几乎每个非嵌入式 C 编译器都使用至少 32 位的int,一些是 64 位的。 Wiki 可能只列出了标准的最低要求。
猜你喜欢
  • 2023-03-19
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2016-04-28
  • 2018-07-15
  • 1970-01-01
  • 2016-06-06
  • 1970-01-01
相关资源
最近更新 更多