Create a buffer and extract your protocol messages from it. If the buffer does not contain the complete message, then recv () until it is complete. Here's a simple C implementation for buffering a socket (slightly tested, compiled on MS VS2008):
#include <winsock2.h> #include <string.h> typedef struct buffsock { SOCKET s; char* buf; size_t maxlen; size_t curlen; } buffsock_t; void buffsock_init(buffsock_t* bs,SOCKET s,size_t maxlen) { bs->s = s; bs->buf = malloc(maxlen); bs->maxlen = maxlen; bs->curlen = 0; } void buffsock_free(buffsock_t* bs) { free(bs->buf); bs->buf = NULL; bs->maxlen = 0; bs->curlen = 0; bs->s = INVALID_SOCKET; } /* Attempt to fill internal buffer. * Returns 0 if socket closed. * Returns number of additional bytes in buffer otherwise. */ int buffsock_fill(buffsock_t* bs) { int bytes; bytes = recv(bs->s,bs->buf + bs->curlen,bs->maxlen - bs->curlen,0); if(bytes == SOCKET_ERROR) return -1; bs->curlen += bytes; return bytes; } /* Return up to <bytes> from buffered socket. * If return value 0 socket was closed. * If return value >0 and <bytes socket received partial message. */ int buffsock_bytes(buffsock_t* bs,size_t bytes,void* msg) { while(bs->curlen < bytes) { int result; result = buffsock_fill(bs); if(result == -1) return -1; /* error on socket */ if(result == 0) break; } if(bytes > bs->curlen) bytes = bs->curlen; memcpy(msg,bs->buf,bytes); bs->curlen -= bytes; memmove(bs->buf,bs->buf + bytes,bs->curlen); return bytes; } /* Implmementation of a protocol with two big-endian bytes indicating * msg size followed by <size> bytes of message. * Returns -1 if error on socket. * Returns -2 if partial message recv'd (shouldn't happen as long as * internal buffer is bigger than max message size). * Returns -3 if user buffer not big enough to hold message. * Returns size of message otherwise. */ int get_protocol_message(buffsock_t* bs,void* msg,size_t maxlen) { int bytes; u_short len; bytes = buffsock_bytes(bs,sizeof(u_short),&len); if(bytes == 0) return 0; /* socket closed, no more messages */ if(bytes == -1) return -1; /* error on socket */ if(bytes < sizeof(u_short)) return -2; /* partial message */ len = ntohs(len); if(len > maxlen) return -3; /* message exceeds user buffer */ bytes = buffsock_bytes(bs,len,msg); if(bytes < len) return -2; /* partial message */ return bytes; }
Use it as follows:
int len; char msg[256]; buffsock_t bs; buffsock_init(&bs,sock,1024); len = get_protocol_message(&bs,msg,sizeof(msg));
The TCP / IP key has no concept of message boundaries, so recv () can return 1 to the number of bytes requested. The resulting buffer may contain several or even partial messages.
This code simply adds the received data to the buffer. The protocol requests bytes from the buffer, and the buffer is populated from the socket. as bytes are deleted, the remaining buffered data is shifted to the beginning of the buffer.
In this case, two bytes are requested, converted to length, then the remaining bytes are requested. If the request cannot be satisfied, more data appears.
Hope this helps.