【问题标题】:How to send int over the socket?如何通过套接字发送 int?
【发布时间】:2023-04-02 18:35:01
【问题描述】:

我正在学习使用 C++ 进行非常基本的套接字编程 我被困在我试图发送随机生成的 int 的部分 在插座上。

服务器.cpp

int code = rand();
send(connfd, (char*)code, sizeof(int), 0);

client.cpp

int code = 0;
recv(connfd, (char*)code, sizeof(int), 0);

我做错了什么?

【问题讨论】:

  • 编译器是怎么说的?
  • C++?那你为什么要标记C呢?
  • code 不是地址,甚至不会通过将其转换为地址类型(指向char 的指针)而成为地址。

标签: c++ sockets


【解决方案1】:

对于初学者:

  1. 您没有检查任何一个调用的返回值。套接字是臭名昭著的(本质上)容易出错。

  2. 假设所有字节都将一起发送和接收 - 但 TCP 很容易出现分段、分段、部分发送以及各种你永远不应该假设你会在一次调用中接收到所有发送的东西。这使得检查返回值变得更加重要!

  3. 你做的那个演员:(char*)code 不正确。更适合做(char*)&code,但它不识别部分接收。

假设您使用的是 TCP 套接字:

发送:

int data = rand();
char* tosend = (char*)&data;
int remaining = sizeof(data);
int result = 0;
int sent = 0;
while (remaining > 0) {
    result = send(connfd, tosend+sent, remaining, 0);
    if (result > 0) {
        remaining -= result;
        sent += remaining;
    }
    else if (result < 0) {
        printf("ERROR!\n");
        // probably a good idea to close socket
        break;
    }
}

接收:

int value = 0;
char* recv_buffer = (char*)&value;
int remaining = sizeof(int);
int received = 0
int result = 0;
while (remaining > 0) {
    result = recv(connfd, recv_buffer+received, remaining, 0);
    if (result > 0) {
        remaining -= result;
        received += result;
    }
    else if (result == 0) {
        printf("Remote side closed his end of the connection before all data was received\n");
        // probably a good idea to close socket
        break;
    }
    else if (result < 0) {
        printf("ERROR!\n");
        // probably a good idea to close socket
        break;
    }
}

对于 UDP 套接字,一些关于错误检查、向/从内存缓冲区转换的原则保持不变。但是对于 UDP,你不应该做“循环”的事情,因为 UDP 是一个数据报协议。

【讨论】:

  • @Galik:只需将char buffer[sizeof(int)] = {0}; char* recv_buffer = buffer; 替换为char* recv_buffer = (char*) &amp;value; 并删除此value = *(int*)buffer;
  • @Galik - 是的。错字。固定。
  • @Galik - 我理解别名(对齐)的事情。你是对的。这在 x86 上是安全的,大多数编译器会将堆栈变量对齐到整数地址边界。我会把它改成一个 memcpy 是正确的。
  • @selbie 我认为对齐只是混叠问题的一部分。另一部分是优化。据我了解,编译器的优化器总是假设不同的类型不会相互别名。如果他们这样做,这可能会导致 UB。这就是为什么您总是必须使用 char 来为其他类型设置别名,而不是相反。
  • @Galik - 现在的编译器在优化方面比以前智能得多了。编译器应该能够推断它可以进行快速复制,因为源/目标地址是堆栈上的变量并且具有正确的对齐方式。在任何情况下,只有少数情况下编写考虑到这种对齐的代码是一种实际的优化(例如游戏和带闪烁灯的路由器设备)。
猜你喜欢
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 2012-12-18
  • 2016-01-31
  • 1970-01-01
  • 2021-09-15
  • 2018-01-22
  • 2014-04-29
相关资源
最近更新 更多