Reputation: 13
I am struggling with TCP networking, especially with partial sending and receiving. I was reading Beej`s tutorial for sockets and I am trying to achieve things he mentioned in paragraph"data encapsulation"-> create communication code invulnerable for partial send/recv. I have a function that sends in loop as long as the whole packet is sent and now I am working on the receiving part. Every time I send something, I create a packet first which contains the packet length, source address, destination address and message itself. These fields are separated from each other using special characters like "$"or"/". It looks like this:
$packet_length/source_addr%dest_addr<message>
Then I have a function that receives first and check whether it got the whole packet or not (finds special chars to create substring which indicates the packet length and then check if the buffer has all data or not). If it received part of packet it gets into loop and calls recv()
as long as it gets the full packet. In theory it should work fine but it`s theory ... During test everything works fine (send the whole packet at once and receives it as well) and I am trying to simulate the condition where I send only half of the packet -> I force the send func to send only 16 bytes of the packet(which is 32 bytes long). On the receiving part I get the message but 22 bytes long(not 16) and with some garbage(random chars). What is going wrong? Where are theses garbage come from? Here is the code:
Sending func:
int sendall( int s, const char *order, const char *from, const char *destination)
{
const char *buf = marshal(order,from, destination).c_str();
// moving the packet(returned by marshal func) to the buf
unsigned int len = strlen(buf);
int total = 0; // sent bytes
int bytesleft = len; // bytes left to send
int n;
while( total < len ) {
n = send( s, buf+total, bytesleft, 0 );
if( n == - 1 ) { break; }
total += n;
bytesleft -= n;
}
return n ==- 1 ?- 1: 0; // returns -1 when fails, 0 - success
}
Receiving func:
int recieveall(int socket){
int n;
n = recv( socket, buf, sizeof(buf), 0 ); // recieves message
string packet(buf);
// searching for the packet length which is placed beetween $ and /
int dollar_sign = packet.find("$");
int slash = packet.find("/");
buf_temp[0] = '\0';
string packet_len = packet.substr(dollar_sign+1, slash-(dollar_sign+1) );
// checking if recieved full packet or a part of it -> comparing bufer length with packet size
// if not calls recieve in a loop untill gets the whole packet
while(strlen(buf) < stoi(packet_len)){
int total = strlen(buf);
int left = stoi(packet_len)-total;
n = recv( socket, buf_temp, left, 0 );
left -= n;
total +=n;
if(total = stoi(packet_len)) {break;}
}
if(buf_temp[0] != '\0'){strcat(buf, buf_temp);} // concat 2 buffers to get the whole message
if(n == 0){return n = 0;}
if(n == -1){return n =-1;}
if(n > 0){return n ;}
}
If it is important the recieveall()
is called in accept loop and I use select() as well. I will appreciate any help or advise.
Upvotes: 1
Views: 3339
Reputation: 310860
recv()
for -1 (error) and zero (end of stream) and take the appropriate (different) action in each case.Upvotes: 4