在C中通过套接字传输整数

时间:2022-05-01 21:16:16

What is the appropriate way to transfer an int over a socket in C?
What I am doing so far is:

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

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

and

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

However, the integer received is sometimes 0. Not always, but let's say 2 out of 5 times. It is never some other value, always 0. Why?

但是,收到的整数有时为0.并非总是如此,但我要说5次中的2次。它永远不会是其他价值,总是为什么?为什么?

UPDATE: Return value from read is -1 and an error is:

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

Resource temporarily unavailable

3 个解决方案

#1


8  

First of all, sizeof(int) may differ on your sender and receiver machine. So I would recommend you to use something like int32_t from stdint.h.

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

Also, it is not guaranteed that read(..,..,sizeof(int)) will read exactly sizeof(int) bytes - it can read nothing, or it can read less bytes. So, the correct variant will be something more like this:

此外,不保证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;
}

#2


7  

This should work without any problem, try this :

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

On the sender (Server) side :

在发件人(服务器)端:

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));

On the receiver(client) side :

在接收方(客户端)方面:

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
}

Hope this will help.

希望这会有所帮助。

#3


0  

Since no one mentioned sprintf

既然没有人提到过sprintf

you can just convert any variable to char* using it and send

你可以使用它将任何变量转换为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);
}

Test

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

Use %d for integers, %f for floats

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

to convert back to an integer, use atoi(char*)
to convert back to an float, use atof(char*)

要转换回整数,使用atoi(char *)转换回float,使用atof(char *)

before converting, be sure to use strstr() to get the float value only, starting from "0"

在转换之前,一定要使用strstr()来获取浮点值,从“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.

For integers (not positions), you can use the same technique and just multiply it like

对于整数(不是位置),你可以使用相同的技术,只需将其相乘即可

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

the above methods are totally secure

以上方法完全安全

If you want a more solid converting, you can use strncpy or memcpy and cut the string starting from a given index with some length assuming that you already know the incoming buffer, but in my personal view, I don't really recommend it, specifically in connectionless sockets like this one, lots of calculations and calls for buffer length, Not easy to debug sometimes if you're not totally aware of what you're doing.

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

Note 1: Be careful to not include zeros in your buffer when you're waiting for a server move/position command or any quantity variable if you're planning to use the 1st method.

注1:当您等待服务器移动/位置命令或任何数量变量时,如果您计划使用第一种方法,请注意不要在缓冲区中包含零。

Note 2: You can just send your integer or float, convert it and vice versa without needing to cut or multiply it.

注意2:您可以发送整数或浮点数,转换它,反之亦然,无需剪切或乘以它。

May new game networking developers find this answer useful too since we can't send or receive except char* with UDP sendto(), recvfrom().

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

#1


8  

First of all, sizeof(int) may differ on your sender and receiver machine. So I would recommend you to use something like int32_t from stdint.h.

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

Also, it is not guaranteed that read(..,..,sizeof(int)) will read exactly sizeof(int) bytes - it can read nothing, or it can read less bytes. So, the correct variant will be something more like this:

此外,不保证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;
}

#2


7  

This should work without any problem, try this :

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

On the sender (Server) side :

在发件人(服务器)端:

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));

On the receiver(client) side :

在接收方(客户端)方面:

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
}

Hope this will help.

希望这会有所帮助。

#3


0  

Since no one mentioned sprintf

既然没有人提到过sprintf

you can just convert any variable to char* using it and send

你可以使用它将任何变量转换为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);
}

Test

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

Use %d for integers, %f for floats

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

to convert back to an integer, use atoi(char*)
to convert back to an float, use atof(char*)

要转换回整数,使用atoi(char *)转换回float,使用atof(char *)

before converting, be sure to use strstr() to get the float value only, starting from "0"

在转换之前,一定要使用strstr()来获取浮点值,从“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.

For integers (not positions), you can use the same technique and just multiply it like

对于整数(不是位置),你可以使用相同的技术,只需将其相乘即可

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

the above methods are totally secure

以上方法完全安全

If you want a more solid converting, you can use strncpy or memcpy and cut the string starting from a given index with some length assuming that you already know the incoming buffer, but in my personal view, I don't really recommend it, specifically in connectionless sockets like this one, lots of calculations and calls for buffer length, Not easy to debug sometimes if you're not totally aware of what you're doing.

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

Note 1: Be careful to not include zeros in your buffer when you're waiting for a server move/position command or any quantity variable if you're planning to use the 1st method.

注1:当您等待服务器移动/位置命令或任何数量变量时,如果您计划使用第一种方法,请注意不要在缓冲区中包含零。

Note 2: You can just send your integer or float, convert it and vice versa without needing to cut or multiply it.

注意2:您可以发送整数或浮点数,转换它,反之亦然,无需剪切或乘以它。

May new game networking developers find this answer useful too since we can't send or receive except char* with UDP sendto(), recvfrom().

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