передать целое число через сокет в C - PullRequest
8 голосов
/ 04 февраля 2012

Как правильно передать int через сокет в C?
Что я делаю до сих пор:

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

и

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

Однако полученное целое число иногда равно 0. Не всегда, но, скажем, 2 из 5 раз. Это никогда не какое-то другое значение, всегда 0. Почему?

ОБНОВЛЕНИЕ: возвращаемое значение из чтения равно -1, и ошибка:

Resource temporarily unavailable

Ответы [ 3 ]

10 голосов
/ 04 февраля 2012

Это должно работать без проблем, попробуйте следующее:

На стороне отправителя (сервера):

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
}

Надеюсь, это поможет.

9 голосов
/ 04 февраля 2012

Прежде всего, sizeof(int) может отличаться на вашем устройстве отправителя и получателя.Поэтому я бы порекомендовал вам использовать что-то вроде int32_t из stdint.h.

. Кроме того, не гарантируется, что 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;
}
0 голосов
/ 09 марта 2018

Поскольку никто не упомянул 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);
}

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

Используйте %d для целых чисел, %f для чисел с плавающей запятой

в преобразование обратно в целое число, используйте atoi(char*)
в преобразование назад до числа с плавающей запятой, используйте atof(char*)

перед преобразованием, обязательно используйте 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.

Для целых чисел ( не позиций), вы можете использовать ту же технику и просто умножить ее, как

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

, описанные выше методы полностью безопасны

Если выесли вы хотите более точное преобразование, вы можете использовать strncpy или memcpy и вырезать строку, начиная с заданного индекса, с некоторой длиной, предполагая, что вы уже знаете входящий буфер, но, по моему личному мнению, я не очень рекомендую этоособенно в сокетах без соединения , подобных этому, много вычислений и вызовов для длины буфера, не легко отладитьУж иногда, если вы не совсем понимаете, что делаете.

Примечание 1 : будьте осторожны, чтобы не включали нули в вашем буфере , когда вы ожидаете сервер move / position или любую количественную переменную, если вы планируете использовать 1-й метод.

Примечание 2 : Вы можете просто отправить целое число или с плавающей точкой , преобразовать его и наоборот без необходимости вырезать или умножить это.

Пусть новые разработчики игровых сетей найдут этот ответ полезным, так как мыне может отправлять или получать, кроме char* с UDP sendto (), recvfrom ().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...