c - Handling multiple recv() calls and all possible scenarios -
i new c , writing tcp server, , wondering how handle recv()'s client send commands server respond to. sake of question, let's header 1st byte, command identifier 2nd byte, , payload length 3rd byte, followed payload (if any).
what best way recv() data? thinking call recv() read in first 3 bytes buffer, check make sure header , command identifiers valid, check payload length , call recv() again payload length length , add of aforementioned buffer. reading beej's networking article (particularly section here: http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html#sonofdataencap), however, advises use "an array big enough 2 [max length] packets" handle situations such getting of next packet.
what best way handle these types of recv()'s? basic question, implement efficiently, handling cases can arise. in advance.
the method beej alluding to, , alastairg mentions, works this:
for each concurrent connection, maintain buffer of read-but-not-yet-processed data. (this buffer beej suggests sizing twice maximum packet length). obviously, buffer starts off empty:
unsigned char recv_buffer[buf_size]; size_t recv_len = 0;
whenever socket readable, read remaining space in buffer, try , process have:
result = recv(sock, recv_buffer + recv_len, buf_size - recv_len, 0); if (result > 0) { recv_len += result; process_buffer(recv_buffer, &recv_len); }
the process_buffer()
try , process data in buffer packet. if buffer doesn't contain full packet yet, returns - otherwise, processes data , removes buffer. example protocol, like:
void process_buffer(unsigned char *buffer, size_t *len) { while (*len >= 3) { /* have @ least 3 bytes, have payload length */ unsigned payload_len = buffer[2]; if (*len < 3 + payload_len) { /* short - haven't recieved whole payload yet */ break; } /* ok - execute command */ do_command(buffer[0], buffer[1], payload_len, &buffer[3]); /* shuffle remaining data in buffer start */ *len -= 3 + payload_len; if (*len > 0) memmove(buffer, buffer + 3 + payload_len, *len); } }
(the do_command()
function check valid header , command byte).
this kind of technique ends being necessary, because any recv()
can return short length - proposed method, happens if payload length 500, next recv()
returns 400 bytes? you'll have save 400 bytes until next time socket becomes readable anyway.
when handle multiple concurrent clients, have 1 recv_buffer
, recv_len
per client, , stuff them per-client struct (which contains other things - client's socket, perhaps source address, current state etc.).
Comments
Post a Comment