Сравнение строк после передачи через сокет TCP в C

Я отправляю файл через TCP, и сервер отправляет сообщение, содержащее «END_OF_MESSAGE», чтобы предупредить клиента о том, что он получил весь файл и может закрыть сокет. Файл отправляется, и клиент получает строку «END_OF_MESSAGE», однако, когда я использую strcmp для сравнения полученной информации с «END_OF_MESSAGE», он никогда не говорит, что они совпадают. Я пробовал strncmp и memcmp, но не понимаю, почему strcmp не говорит мне, что строки совпадают.

Фрагменты кода:

Сервер:

char endMessage[MESSAGESIZE] = "END_OF_MESSAGE";

if ((send(clntSocket, endMessage, sizeof endMessage, 0))!= sizeof endMessage) DieWithError("Sending failed");

Приведенный выше фрагмент кода действительно отправляется.

Клиент:

  if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
        DieWithError("recv() failed or connection closed prematurely");
    totalBytesRcvd += bytesRcvd;   /* Keep tally of total bytes */
    echoBuffer[bytesRcvd] = '\0';  /* Terminate the string! */
    if (!(strcmp(echoBuffer, "END_OF_MESSAGE")==0)){
    printf(echoBuffer);            /* Print the echo buffer */
    printf("\n");
    }else{
      break; //break out of while loop
    }

strcmp эхо-буфера и "END_OF_MESSAGE" никогда не возвращает 0, хотя "END_OF_MESSAGE" - это то, что я отправляю с сервера. Я пробовал strncmp сравнивать первые 3 символа ("END") безрезультатно.

Примечание: когда я распечатываю эхо-буфер, самый последний печатает END_OF_MESSAGE, что только добавляет мне путаницы.

Есть ли у кого-нибудь понимание того, что я делаю неправильно?

Спасибо.


person S.M.    schedule 09.04.2017    source источник
comment
Может MESSAGESIZE > strlen(endMessage) ? (и, скорее всего, полученная вами строка также не завершается нулем)   -  person wildplasser    schedule 09.04.2017
comment
Вы предполагаете, что recv() получает все сообщение "END_OF_MESSAGE\0" и ТОЛЬКО отдельное сообщение за одно чтение. Это никогда не гарантируется в TCP. Возможно, сообщение получено через несколько вызовов recv(). Возможно, буфер содержит некоторые данные файла в начале буфера. Вы должны учитывать такие условия.   -  person Remy Lebeau    schedule 11.04.2017


Ответы (1)


Я отправляю файл через TCP, и сервер отправляет сообщение, содержащее «END_OF_MESSAGE», чтобы предупредить клиента о том, что он получил весь файл и может закрыть сокет.

Почему? Просто закройте сокет. Который скажет клиенту ровно то же самое..

То, что вы пытаетесь сделать, сопряжено с трудностями. Что произойдет, если файл содержит END_OF_MESSAGE? Вам понадобится соглашение о побеге и побег для побега, а также проверка всех данных при отправке и получении.

Фактическая проблема, которую вы видите, заключается в том, что END_OF_MESSAGE может прибыть вместе с последним битом файла, поэтому оно не находится в начале буфера.

Но это все бессмысленно. Просто закройте сокет.

person user207421    schedule 10.04.2017
comment
Проблема с простым закрытием сокета заключается в том, что это не гарантирует, что все байты действительно были получены. Лучший вариант — отправить размер файла перед отправкой данных файла. Таким образом, получатель точно знает, сколько байтов читать и когда прекратить чтение. Даже если вы впоследствии закроете сокет, отправка размера файла позволит получателю узнать, действительно ли он получил все ожидаемые байты или нет. - person Remy Lebeau; 11.04.2017
comment
@RemyLebeau Это именно то, что TCP делает гарантирует. Вы не можете получить FIN до получения всех данных. Это фундаментальное свойство TCP. Это упорядоченный обмен пакетами или поток байтов, завершающийся FIN. Если какие-либо данные пропали до FIN, это будет замечено получателем при получении FIN и вызвано повторной передачей, или соединение в конечном итоге будет сброшено: а не просто чисто разорвано. - person user207421; 12.04.2017
comment
Как только FIN поступает в стек сокетов получателя, он может немедленно сообщить FIN коду приложения (например, если recv() возвращает 0), даже если есть предыдущие данные, ожидающие чтения из буфер сокета. Спецификация TCP может предписывать, что все ожидающие данные должны быть обработаны до того, как будет сообщено о FIN. Но реализации TCP могут не всегда следовать этому правилу. Я видел это раньше. - person Remy Lebeau; 12.04.2017
comment
@RemyLebeau Нет. (a) Он не может буферизовать FIN после любых существующих данных в буфере приема сокета, пока не получит все предыдущие порядковые номера. (b) Он должен доставить все данные в приемный буфер сокета до FIN. Если вы видели иначе, вы видели катастрофическую ошибку. - person user207421; 12.04.2017
comment
Возможно, так должно быть, но я запускал код в производственных системах, где recv() возвращал 0 после отправки FIN, даже если не все данные были считаны (у меня не было не видел, чтобы это произошло в последнее время, хотя). Если это ошибка, то это ошибка самой ОС. Происходит не всегда, но может произойти. Я просто говорю, что неразумно полагаться только на FIN, чтобы сигнализировать о конце данных, если важна целостность данных (обычно это так). - person Remy Lebeau; 12.04.2017
comment
@RemyLebeau Очень трудно поверить. Такого за 30 лет не видел. Это основное нарушение последовательности сегментов TCP. - person user207421; 12.04.2017