【问题标题】:transfer integer over a socket in C通过 C 中的套接字传输整数
【发布时间】:2012-02-04 11:08:31
【问题描述】:

在 C 中通过套接字传输int 的适当方法是什么?
到目前为止,我正在做的是:

int n = 4;
int tmp = htonl(n);
write(socket, &tmp, sizeof(tmp));

int tmp,n;
read(socket, &tmp, sizeof(tmp));
n = ntohl(tmp);

但是,收到的整数有时为 0。并非总是如此,但假设 5 次中有 2 次。它从来不是其他值,总是 0。为什么?

更新:读取的返回值为-1,错误为:

Resource temporarily unavailable

【问题讨论】:

  • 你检查了read的返回值,看看它是否真的填满了缓冲区?
  • 您提供的代码片段是正确的。无论您遇到什么问题,都存在于您没有发布的代码中。
  • 如果接收到0,则读取返回为-1。当收到实际整数时,读取的返回值为 4。我想这没问题,但仍然 - 我该如何解决? ://
  • 也许从read 中查找-1 的含义?这意味着您没有阅读。
  • 你在socket上设置O_NONBLOCK了吗?如果是这样,则此错误表明数据尚未到达。请稍后再试。

标签: c sockets int


【解决方案1】:

首先,sizeof(int) 在您的发送方和接收方机器上可能会有所不同。所以我建议你使用stdint.h中的int32_t之类的东西。

此外,不能保证read(..,..,sizeof(int)) 将准确读取sizeof(int) 字节 - 它什么也不能读取,或者它可以读取更少的字节。所以,正确的变体应该是这样的:

int send_int(int num, int fd)
{
    int32_t conv = htonl(num);
    char *data = (char*)&conv;
    int left = sizeof(conv);
    int rc;
    do {
        rc = write(fd, data, left);
        if (rc < 0) {
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                // use select() or epoll() to wait for the socket to be writable again
            }
            else if (errno != EINTR) {
                return -1;
            }
        }
        else {
            data += rc;
            left -= rc;
        }
    }
    while (left > 0);
    return 0;
}

int receive_int(int *num, int fd)
{
    int32_t ret;
    char *data = (char*)&ret;
    int left = sizeof(ret);
    int rc;
    do {
        rc = read(fd, data, left);
        if (rc <= 0) { /* instead of ret */
            if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
                // use select() or epoll() to wait for the socket to be readable again
            }
            else if (errno != EINTR) {
                return -1;
            }
        }
        else {
            data += rc;
            left -= rc;
        }
    }
    while (left > 0);
    *num = ntohl(ret);
    return 0;
}

【讨论】:

  • >更新:读取的返回值为-1。你使用非阻塞 IO 吗?
  • 我认为receive 函数是完全错误的。恕我直言,您使用 ret 而不是实际上从未使用过的 rc
  • 另外,除非 read 返回 -1,否则您永远不应该查看 errno。当返回 0 时您正在检查它,这将导致一个非常难以追踪的错误
  • @garlix 是对的。是的!在 receive_int() 中,它应该是 'if (rc
【解决方案2】:

这应该没有任何问题,试试这个:

在发送方(服务器)端:

int number_to_send = 10000; // Put your value
int converted_number = htonl(number_to_send);

// Write the number to the opened socket
write(client_socket, &converted_number, sizeof(converted_number));

在接收方(客户端):

int received_int = 0;

return_status = read(client_socket, &received_int, sizeof(received_int));
if (return_status > 0) {
   fprintf(stdout, "Received int = %d\n", ntohl(received_int));
}
else {
   // Handling erros here
}

希望这会有所帮助。

【讨论】:

  • 这应该是公认的答案!谢谢! +1 htonlntohl
  • 但这不处理部分读取或写入! read 可以一次返回一个字节的结果。
  • @D.Shawley 你是对的。这个答案和问题有同样的问题,什么也解决不了。出于这个原因,您应该对其投反对票。
【解决方案3】:

由于没有人提到sprintf

您可以使用它将任何变量转换为char*并发送

if(strcmp(buf,"movUP") == 0)
{
    char* msg = calloc(1, 20);
    pos.y += 0.0001f;
    sprintf(msg,"NEW::POS::Y=%.4f", pos.y);
    sendto(master, msg, 20, 0, (struct sockaddr*)&client, addrlen);
}

测试

movUP
NEW::POS::Y=0.0001
movUP
NEW::POS::Y=0.0002
movUP
NEW::POS::Y=0.0003
movUP
NEW::POS::Y=0.0004

使用%d 表示整数,%f 表示浮点数

转回为整数,请使用atoi(char*)
转换回为浮点数,使用atof(char*)

在转换之前,一定要使用strstr()获取浮点值only,从"0"开始

    float myPos; // floating variable that stores Object's Position in the World
    ...
    ....
    memset(buf, 0, MAXBUFFER); // clears the previous buffer
    recvfrom(master, buf, MAXBUFFER, 0, (struct sockaddr*)&server, &addrlen);
    char* newY = strstr(buf, "0");// NEW::POS::Y=0.0001 --->> 0.000100
    myPos = atof(newY); // new object's position by the server
    printf("My New Position is %.4f\n", myPos); // Out: My New Position is 0.0011 -> 0.0012 -> 0.0013 -> 0.0014.

对于整数(不是位),您可以使用相同的技术,然后将其相乘

float f = 0.000002f; // that is supposed to be 2 integer value
int i = (int)(f*1000000); // now, i = 2

以上方法完全安全

如果您想要更可靠的转换,您可以使用strncpymemcpy 并从给定索引开始剪切字符串,假设您已经知道传入缓冲区,但在我个人看来,我不知道' 真的不推荐它,特别是在像这样的 connectionless 套接字中,大量计算和要求缓冲区长度,如果您不完全了解自己在做什么,有时不容易调试。

注意 1:当您等待一个服务器 move/position 命令或任何 如果您打算使用 1st 方法,则为数量变量。

注意 2:您可以发送 integerfloat转换它vice反之亦然,无需剪切相乘

也许新的游戏网络开发者会发现这个答案也很有用,因为除了char*UDP sendto()、recvfrom() 之外,我们无法发送或接收。

【讨论】:

    【解决方案4】:

    我也遇到了同样的问题,浪费了 30 分钟试图找出我做错了什么。但是,最后,我找到了解决方案。从documentation 我们可以看到htonl()ntohl() 函数使用32 位无符号整数。因此,要解决此问题,您必须使用来自&lt;stdint.h&gt;unsigned __int32uint32_t

    所以代码将如下所示:

    #include <stdint.h>
    
    uint32_t n = 4;
    uint32_t tmp = htonl(n);
    write(socket, &tmp, sizeof(tmp));
    

    和:

    #include <stdint.h>
    
    uint32_t tmp,n;
    read(socket, &tmp, sizeof(tmp));
    n = ntohl(tmp);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多