2014-07-02 33 views
8

Mam aplikację klient-serwer.Wiele wywołań send() jest połączonych w jedno wywołanie recv()

Klient wysyła ciąg, po którym następuje liczba całkowita za pomocą dwóch różnych połączeń send(). Te dwa dane powinny być przechowywane na dwóch różnych zmiennych na serwerze.

Problem polega na tym, że obie zmienne wysłane są odbierane w rozmowie recv(). Dlatego dwa ciągi wysyłane przez dwa różne send() s są powiązane i przechowywane w buforze pierwszego recv().

server.c:

printf("Incoming connection from client %s:%i accepted\n",inet_ntoa(clientSocketAddress.sin_addr),ntohs(clientSocketAddress.sin_port)); 


memset(buffer,0,sizeof(buffer)); 
int sizeofMessage; 
if ((recv(clientSocket,buffer,MAXBUFFERSIZE,0)==sizeofMessage)<0) 
{ 
    printf("recv failed."); 
    closesocket(serverSocket); 
    clearWinsock(); 
    return EXIT_FAILURE; 
} 

char* Name=buffer; 
printf("Name: %s\n",Name); 

if ((recv(clientSocket,buffer,MAXBUFFERSIZE,0))<0) 
{ 
    printf("bind failed."); 

    closesocket(serverSocket); 
    clearWinsock(); 
    return EXIT_FAILURE; 
} 

int integer=ntohs(atoi(buffer)); 
printf("integer: %i\n",intero); 

client.c:

if (send(clientSocket,Name,strlen(Name),0)!=strlen(Name)) 
{ 
    printf("send failed"); 

    closesocket(clientSocket); 
    clearWinsock(); 
    return EXIT_FAILURE; 
} 

printf("client send: %s",Name); 

int age=35; 
itoa(htons(age),buffer,10); 
sizeofBuffer=strlen(buffer); 
if (send(clientSocket,buffer,sizeofBuffer,0)!=sizeofBuffer) 
{ 
    printf("bind failed."); 

    closesocket(clientSocket); 
    clearWinsock(); 
    return EXIT_FAILURE; 
} 

Jak mogę to naprawić? Co ja robię źle?

Odpowiedz

7

TCP to protokół przesyłania strumieniowego. W ogóle nie jest świadomy jakichkolwiek granic "wiadomości". Nie dodaje takich informacji w zależności od pojedynczych wywołań do send().

Z powodu tych faktów. Każdy numer send() s po stronie nadawcy może prowadzić do dowolnej liczby recv() s (do liczby wysłanych bajtów) po stronie odbiorcy.

Aby obejść to zachowanie, zdefiniuj i zaimplementuj protokół poziomu aplikacji, aby rozróżnić różne "wiadomości", które zostały wysłane.

Nie można polegać na recv()/send() odbieraniu/wysyłaniu tyle bajtów, ile te dwie funkcje otrzymały polecenie odebrania/wysłania. Jest to niezbędna konieczność sprawdzenia ich wartości zwracanej, aby dowiedzieć się, ile bajtów te funkcje faktycznie otrzymały/wysłały i przechwytywały je, dopóki wszystkie dane, które miały zostać odebrane/wysłane, nie zostały odebrane/wysłane.

Do przykładów jak ten „zapętlenie” można zrobić

1

Tak działa TCP. Traktuj to jako strumień bajtów. Umieść na nim podstawowy protokół - ogranicz wiadomości do aplikacji o znanej wartości bajtu lub dodaj wiadomości z polem długości.

Albo przełącz na UDP, który daje ci semantykę datagramu, której szukasz, jeśli możesz tolerować/odzyskać od sporadycznego utraty pakietów.

+0

" oddziela wiadomości z pewną znaną wartością bajtów "tylko dla wyjaśnienia, to się nazywa protokół, niektórzy używają czegoś takiego jak STXyourmessageETXXOR gdzie STX (start) w HEX to 2, ETX (END) w HEX to 3, a XOR jest bitowo operacja^dla STXyourmessageE TX, wynik = STX^y -> wynik^= u ... gdzie XOR reprezentuje cyfrę do weryfikacji –