Сокет Беркли: системный вызов recv
//server side
void* s2(void *arg){
info *s = (info*)arg;
char buffer[MAXS];
int k;
sockaddr_in addr;
socklen_t aSize = sizeof(sockaddr_in);
int sfd = accept(s->fd,(sockaddr*)&addr,(socklen_t*)&aSize);
if(sfd<0){
s->current--;
pthread_exit(0);
}
while(1){
k = recv(sfd,buffer,MAXS,0);
cout<<buffer<<"\n";
//1. k ==0 socket has been closed by client
//2. k==-1 error in recv
//3. recv quit
if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break;
sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to string using sprintf()
send(sfd,buffer,strlen(buffer),0); //send buffer to client
}
close(sfd);
if(s->limit==s->current)
FD_SET(s->fd,&sfds);
s->current--; //decreament the client number
pthread_exit(0);
}
//client side
1. send(sockfd,"sadhdag",8,0);
2. send(sockfd,"ss",3,0);
Сервер recv sadhdag
в первом звонке в recv .
Во втором звонке на recv сервер recv
ss
dag
сторона сервера:
функция s2 запускается потоком, а аргумент передается с информацией о сокете, соединение там принимается, и send и recv вызываются на вновь принятом клиенте.
Почему это происходит? или как этого избежать?
2 ответа
Вы игнорируете счет, возвращенный recv()
, Вопреки предложениям в комментариях, нет необходимости memset()
буфер до нуля до recv()
, но необходимо использовать этот буфер только до этого количества. Например:
printf("%s", buffer);
это неправильно, и
printf("%.*s", count, buffer);
правильно.
NB
if((k==-1)||(!strncmp(buffer,"quit",4))||(k==0))break;
тоже не правильно. Так должно быть
if((k==-1)||(k==0)||(k >= 4 && !strncmp(buffer,"quit",4))) break;
Недопустимо смотреть в буфер вообще, если k
положительный, и нельзя сравнивать четыре символа в нем, если в нем нет четырех символов.
Вы забыли на самом деле реализовать какой-либо протокол или логику уровня приложения любого рода. Это подводит итог:
k = recv(sfd,buffer,MAXS,0);
cout<<buffer<<"\n";
Этот код предполагает, что вы заканчиваете свои сообщения новой строкой:
sprintf(buffer,"%d\n",(int)strlen(buffer)); //Convert length to string using sprintf()
send(sfd,buffer,strlen(buffer),0); //send buffer to client
Если так, то где же код для анализа на другом конце? Вы отбрасываете возвращенную длину, так что вы даже не знаете, какие символы проверять на новую строку.
TCP является протоколом потока байтов, который не сохраняет границы сообщений уровня приложения. Если вы хотите использовать его для отправки строк или других сообщений уровня приложения, вы должны указать и реализовать протокол уровня приложения, чтобы сделать это.
Ты звонишь recv
чтобы получить необработанные данные TCP, вы выводите их, как если бы это была строка. Если вы собираетесь определить и реализовать протокол для отправки и получения строк по TCP, вам действительно нужно это сделать. Вы не можете просто представить, что это происходит по волшебству.
Если вы хотите получать завершенные новой строкой сообщения в строки в стиле C, вы, безусловно, можете это сделать. Но для этого нужно написать код.