Получение странных символов / символов в winsock

Я узнал о Winsock, и у меня возникла странная проблема при отправке и получении простой строки. Вот мой код (чистый C):

Клиент:



//...
//Declarations and stuff

//----------- SEND SOME DATA -------------------------------------------------

    char string1[] = "string-1";
    int bytes_sent = 0;

    bytes_sent = send(client_socket, string1, strlen(string1), 0);  

    printf("BYTES SENT: %i\n", bytes_sent);
    printf("\n-----------------------------------------------\n\n");

    system("pause");

//...

Сервер:



//...
//Declarations and stuff

//----------- START LISTENING FOR REQUESTS ------------------------------------

    SOCKET ClientSocket;

    #define BUFFER_SIZE 256

    int size;
    struct sockaddr_in client_info;
    char client_ip[16];
    char data_received[BUFFER_SIZE];    
    int bytes_received = 0; 

    listen(ListenSocket, SOMAXCONN);

    while(1){           

        ClientSocket = accept(ListenSocket, (struct sockaddr *)&client_info, &size);        
        strcpy(client_ip, inet_ntoa(client_info.sin_addr));     

        do{

            bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);

            if(bytes_received > 0){
                printf("DATA RECEIVED FROM %s: %s (%i bytes)\n", client_ip, data_received, bytes_received);
            }


        }while(bytes_received > 0);

        printf("\n-----------------------------------------------\n\n");


    }

//...

Проблема в том, что сервер печатает мою строку + какие-то странные символы (см. Рис.).

Странные символы

Я использую потоковый сокет. Пример очень простой, поэтому я не знаю, что может быть не так. Проблема исчезает (сервер печатает строку OK), если я произвольно изменяю строку, размер буфера сервера или и то, и другое. Проблема устраняется, если в вызове send () я использую sizeof () вместо strlen (). Я немного потерялся здесь. Пожалуйста, будьте добры, если я что-то пропустил, это мой самый первый пост здесь. Я могу предоставить весь код (в основном это запуск Winsock и определение сокета).


person SergiGS    schedule 18.01.2013    source источник
comment
Кажется, что с кодом, который вы опубликовали, нет ничего плохого, но это не вся программа, поэтому он легко может быть неправильным в контексте. Похоже, вы хотели опубликовать всю программу, но она была отключена. Кроме того, вы должны сообщить нам, в чем заключается ваша странная проблема - что именно произошло и чем это отличается от того, что вы ожидали?   -  person zwol    schedule 18.01.2013
comment
Подсказка: похоже, вы не отправляете завершающий байт NUL.   -  person    schedule 18.01.2013
comment
@ H2CO3: Скорее всего, проблема. Хотя не обязательно, в зависимости от кода приема.   -  person netcoder    schedule 18.01.2013
comment
@netcoder Ага, в значительной степени.   -  person    schedule 18.01.2013
comment
Можете ли вы также отправить код получения?   -  person netcoder    schedule 18.01.2013
comment
@Zack аааааааааааааааааааааааа, извините, я не закончил его, и он был опубликован, не знаю почему. Кроме того, я попытался добавить изображение, но не могу, как новый пользователь.   -  person SergiGS    schedule 18.01.2013


Ответы (3)


Отправляемые вами данные не содержат завершающего нулевого символа:

bytes_sent = send(client_socket, string1, strlen(string1), 0);

... потому что strlen не считает завершающий нуль. Это не совсем проблема сама по себе, а скорее связано с тем, что на принимающей стороне:

char data_received[BUFFER_SIZE];
// ...
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);

data_received не инициализирован, и вы можете получить до BUFFER_SIZE байт. Это означает, что, поскольку данные, которые вы отправляете, не заканчиваются нулем:

  • # P4 #
    # P5 #
    # P6 #
  • Если bytes_received == BUFFER_SIZE, нет нулевого терминатора, поэтому printf вызовет неопределенное поведение, пытаясь распечатать его, поскольку он не знает, где заканчивается строка, и выйдет за пределы массива.

Самый простой способ исправить это - отправить нулевой терминатор:

bytes_sent = send(client_socket, string1, strlen(string1)+1, 0); // +1 here
bytes_sent = send(client_socket, string1, sizeof(string1), 0);   // same as above

... или получите на байт меньше и поставьте нулевой ограничитель на размер приема:

bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE-1, 0); // -1 here
data_received[bytes_received] = 0;

Я лично выбрал бы первый.

person netcoder    schedule 18.01.2013
comment
Да, хорошее объяснение, почему во всех примерах, которые я видел, все используют просто strlen () ... ну, на стороне сервера никто не печатал данные, поэтому я думаю, они не заботились о нулевом терминаторе - person SergiGS; 18.01.2013
comment
@SergioGimeno: Верно, печать строки - вот в чем разница. Вам не нужно отправлять или получать нулевой терминатор при работе с сокетами, но он вам понадобится, если вы попытаетесь распечатать данные. - person netcoder; 18.01.2013
comment
Все широко используемые интернет-протоколы, о которых я могу думать, либо полностью основаны на тексте и используют терминаторы CRLF (HTTP, SMTP, FTP и т. Д.), Либо они полностью бинарно-безопасны и используют явные поля длины (TCP, SSL). - person zwol; 19.01.2013
comment
Второй вариант -1 из буфера в recv сработал для меня для получения фрагментированных данных. - person jspacek; 23.11.2014

Итак, проблема в том, что вы не отправляете завершающий байт NUL, но вы, кажется, обрабатываете полученную строку как строку C (т. Е. Вы предполагаете, что она завершается NUL). Чтобы исправить это, вместо

bytes_sent = send(client_socket, string1, strlen(string1), 0);

записывать

bytes_sent = send(client_socket, string1, strlen(string1) + 1, 0);

Кроме того, вы упомянули, что «никто не использует strlen(s) + 1» - возможно, потому, что они обращают внимание на количество байтов, полученных на принимающей стороне.

person Community    schedule 18.01.2013

Попробуйте установить длину всех ваших строковых данных, а затем завершить строку на сервере следующим образом:

bzero(data_received, sizeof(data_received));
bytes_received = recv(ClientSocket, data_received, BUFFER_SIZE, 0);
data_received[bytes_received] = '\0';

Если это не решит проблему, возможно, @ H2CO3 поможет вам лучше прочитать то, о чем вы спрашиваете:]

person Alexandre Mulatinho    schedule 18.01.2013
comment
Если bytes_received == BUFFER_SIZE, вы переполнили data_received. Даже если бы вы сделали bytes_received, это нехорошо, он перезапишет последний байт в буфере. - person netcoder; 18.01.2013