Recv () until NUL byte is received?

I am trying to get one packet at a time from the server, since the packets go too fast, and each of them is undefined, calling recv () with the number of bytes read will count the first packet and, possibly, part of the second packet. Since each packet ends with NULL, I thought that reading byte bytes before receiving a NULL byte.

int recvLen = 0; char TB; char recvBuffer[1024]; while (recv(Socket, &TB, 1, 0) > 0 && TB != 0 && recvLen < 1024) { recvBuffer[recvLen] = TB; recvLen++; } 

I do not think this method is effective at all. If the server sent 1024 bytes, recv() will be called 1024 times.

Is there any other recv () method until I get a NULL char or some better method than the one I'm using?


EDIT: I added the packet size for the data sent from the server, but now if the packet is false or even sometimes for no reason, the packets are messed up and the correct data is not received. here is my code

 #define UPLOAD_LEN 2755 int PacketSize, recvLen; char Size[4]; char recvBuffer[UPLOAD_LEN+1]; while(1) { if(recv(Socket,Size,4,0)>0) { Size[4] = '\0'; PacketSize = atoi(Size); if (PacketSize > UPLOAD_LEN || PacketSize <= 0) continue; recvLen = recv(Socket, recvBuffer, PacketSize, 0); } else recvLen = -1; if (recvLen > 0) { recvBuffer[recvLen] = '\0'; ProcessData(recvBuffer); } else { closesocket(Socket); } } 
+4
source share
3 answers

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; /* open a socket */ 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.

+1
source

I never understood why communication protocols never support one of the programmers who are waiting for the opportunity: the exchange of arbitrary blobs sizes with sendings and recv aligned on the borders.

So there is no real shortcut here. You need to keep a constant buffer that contains all the data remaining from the previous call to recv. Keep adding data to the end as you receive it and return to zero zero every time you find it. You will probably have at least a partial next packet, so move it to the beginning of the buffer to serve as your initial state on the next call.

+4
source

There are several ways to do this.

Option # 1: Before sending any information, send an int at the beginning of the packet, which contains the packet size. Read this int, and then allocate the buffer, which is the length of the int you just received. Then you can recv () the whole package in one go.

Option number 2: read at 1024 bytes at a time. recv () will return you the number of bytes read. You can then use strlen () to find out if there are multiple packets in your buffer. It would probably be most appropriate to do this recursively (assuming you could have multiple packets of 1024 bytes); so you break packets based on NULL bytes.

0
source

Source: https://habr.com/ru/post/1340452/


All Articles