Как отправить и получить сокет данных TCP (C / C ++)

Возможный дубликат:
Каков правильный способ чтения из сокета TCP в C / C ++?

Я пытаюсь разработать клиент / сервер TCP. Моя проблема в том, что когда я пытаюсь отправить данные с клиента, я делаю это в одном сообщении.

Но моя проблема возникает, когда я пытаюсь получить данные с определенной структурой, я имею в виду, что первые 8 байт устанавливают дату, следующее 10 имя и неопределенное количество байтов задают текст (этот текст заканчивается на / r / n / г / п)

Клиент отправляет следующее:

char date[8]; char name[10]; char msg[4096]; strcpy(msg,"12/10/12"); //8 bytes strcat(msg,"Kevin Fire"); //10 bytes strcat(msg,"abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde\r\n\r\n"); nbytes_sent = send(sock,(char *)msg,sizeof(msg),0); printf("Bytes_sent: %s -> %i\n",msg,nbytes_sent); 

И сервер пытается проанализировать данные из сокета следующим образом:

 char date[8]; char name[10]; char * text; char buf[1024]; int i=0; for(i=0; i < 8; i++) date[i] = '\0'; for(i=0; i  0){ printf("Date: %s (%i)\n",date,nbytes_read); //cout.flush(); nbytes_read=recv(sclient,(char *)name,sizeof(name),0); if(nbytes_read > 0){ printf("Name: %s (%i)\n",name,nbytes_read); //cout.flush(); nbytes_read=recv(sclient,(char *)buf,sizeof(buf),0); strcpy(text,buf); while(nbytes_read > 0){ nbytes_read=recv(sclient(char*)buf,sizeof(buf),0); strcat(text,buf); } } } printf("Date: %s. Name: %s. Text: %s\n",date,name,text); 

Вот простая функция «получить все»:

 int recv_all(int sockfd, void *buf, size_t len, int flags) { size_t toread = len; char *bufptr = (char*) buf; while (toread > 0) { ssize_t rsz = recv(sockfd, bufptr, toread, flags); if (rsz <= 0) return rsz; /* Error or other end closed cnnection */ toread -= rsz; /* Read less next time */ bufptr += rsz; /* Next buffer position to read into */ } return len; } 

Одна (повторенная) ошибка:

 nbytes_read=recv(sclient,(char *)date,sizeof(date),0); 

recv() не завершает нуль. Это означает, что date не будет иметь нулевой ограничитель, если считывается значение sizeof(date) байтов. Это проблема, когда в качестве аргумента printf() с спецификатором формата "%s" передается строка с нулевым завершающим символом. Если строка не равна нулю, вы можете увидеть символы мусора, появляющиеся после фактических данных строки. Вам нужно прочитать один меньше целевого буфера, а null завершить или использовать спецификатор формата "%*.s" , который не требует нулевого завершения:

 printf("%.*s", n, s); /* Prints first 'n' bytes from 's'. */ 

Обратите внимание, что вы можете инициализировать char[] ко всем нулям вместо использования for :

 char date[8] = ""; 

или вы можете использовать memset() .

Добавление в @ hmjd’s find:

объявленный в var decls, является вашим текстовым указателем …

 char * text; 

тогда позже…

 strcpy(text,buf); while(nbytes_read > 0){ nbytes_read=recv(sclient(char*)buf,sizeof(buf),0); strcat(text,buf); } 

Возможно, попробуйте установить, что «текстовый» указатель на что-то рядом со значением случайного стека также поможет.

Продолжая заграждение, хотя следующее не обязательно взорвется, ваша переменная date :

 char date[8]; 

как на стороне клиента, так и на стороне сервера. Клиентская переменная вообще не используется. Однако переменная сервера:

 nbytes_read=recv(sclient,(char *)date,sizeof(date),0); if(nbytes_read > 0){ 

Проблема в том, что дата, которую вы отправили, на самом деле составляет 8 символов: «12/10/12». Поэтому, даже если вы завершаете нулевой ограничитель в конце своей строки, который вы всегда должны делать независимо (хорошая практика):

 date[ sizeof(date)/sizeof(date[0])-1 ] = 0; 

вы усекаете последний символ своей даты.

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

Наконец, потратить некоторое время на бизнес-конец отладчика, вероятно, сделает вас очень хорошо, особенно на стороне сервера.