my question is can I receive a half message with the code below?
If I want to send a message like: "MESSAGE\n"
Can that happen I receive only M character if the channel is slowly?
and the code part:
fd.fd = c->socket;
fd.events = POLLIN;
bzero(received, sizeof(received));
result = poll(&fd, 1, time);
if(result > 0)
{
i = SSL_read ( (SSL *)c->sslHandle, (char*)received, INCOMING_BUFFERSIZE);
result = SSL_get_error(c->sslHandle, i);
...
}
Because I though I receive nothing until the the "\n" symbol is not received.
How can make sure I accept message only with \n at end of that.
thanks the help,
Tamas
EDIT: the version I am using is 1.0.1c
The socket is stream-based which means that you get a stream of bytes, not a message. Consequently with one recv() call you can get from 1 to all bytes of the data you've sent. You need to put the data to some intermediate buffer and analyze the buffer for some markers (\n in your case).
Related
I'm building a multi-client<->server messaging application over TCP.
I created a non blocking server using epoll to multiplex linux file descriptors.
When a fd receives data, I read() /or/ recv() into buf.
I know that I need to either specify a data length* at the start of the transmission, or use a delimiter** at the end of the transmission to segregate the messages.
*using a data length:
char *buffer_ptr = buffer;
do {
switch (recvd_bytes = recv(new_socket, buffer_ptr, rem_bytes, 0)) {
case -1: return SOCKET_ERR;
case 0: return CLOSE_SOCKET;
default: break;
}
buffer_ptr += recvd_bytes;
rem_bytes -= recvd_bytes;
} while (rem_bytes != 0);
**using a delimiter:
void get_all_buf(int sock, std::string & inStr)
{
int n = 1, total = 0, found = 0;
char c;
char temp[1024*1024];
// Keep reading up to a '\n'
while (!found) {
n = recv(sock, &temp[total], sizeof(temp) - total - 1, 0);
if (n == -1) {
/* Error, check 'errno' for more details */
break;
}
total += n;
temp[total] = '\0';
found = (strchr(temp, '\n') != 0);
}
inStr = temp;
}
My question: Is it OK to loop over recv() until one of those conditions is met? What if a client sends a bogus message length or no delimiter or there is packet loss? Wont I be stuck looping recv() in my program forever?
Is it OK to loop over recv() until one of those conditions is met?
Probably not, at least not for production-quality code. As you suggested, the problem with looping until you get the full message is that it leaves your thread at the mercy of the client -- if a client decides to only send part of the message and then wait for a long time (or even forever) without sending the last part, then your thread will be blocked (or looping) indefinitely and unable to serve any other purpose -- usually not what you want.
What if a client sends a bogus message length
Then you're in trouble (although if you've chosen a maximum-message-size you can detect obviously bogus message-lengths that are larger than that size, and defend yourself by e.g. forcibly closing the connection)
or there is packet loss?
If there is a reasonably small amount of packet loss, the TCP layer will automatically retransmit the data, so your program won't notice the difference (other than the message officially "arriving" a bit later than it otherwise would have). If there is really bad packet loss (e.g. someone pulled the Ethernet cable out of the wall for 5 minutes), then the rest of the message might be delayed for several minutes or more (until connectivity recovers, or the TCP layer gives up and closes the TCP connection), trapping your thread in the loop.
So what is the industrial-grade, evil-client-and-awful-network-proof solution to this dilemma, so that your server can remain responsive to other clients even when a particular client is not behaving itself?
The answer is this: don't depend on receiving the entire message all at once. Instead, you need to set up a simple state-machine for each client, such that you can recv() as many (or as few) bytes from that client's TCP socket as it cares to send to you at any particular time, and save those bytes to a local (per-client) buffer that is associated with that client, and then go back to your normal event loop even though you haven't received the entire message yet. Keep careful track of how many valid received-bytes-of-data you currently have on-hand from each client, and after each recv() call has returned, check to see if the associated per-client incoming-data-buffer contains an entire message yet, or not -- if it does, parse the message, act on it, then remove it from the buffer. Lather, rinse, and repeat.
I am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket. The file is being sent, and the client receives the "END_OF_MESSAGE" string, however, when I use strcmp to compare the received information to "END_OF_MESSAGE", it never says that they match. I have tried strncmp and memcmp but am confused as to why strcmp does not tell me the strings match.
Code snippets:
Server:
char endMessage[MESSAGESIZE] = "END_OF_MESSAGE";
if ((send(clntSocket, endMessage, sizeof endMessage, 0))!= sizeof endMessage) DieWithError("Sending failed");
The above code snippet does get sent.
Client:
if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)
DieWithError("recv() failed or connection closed prematurely");
totalBytesRcvd += bytesRcvd; /* Keep tally of total bytes */
echoBuffer[bytesRcvd] = '\0'; /* Terminate the string! */
if (!(strcmp(echoBuffer, "END_OF_MESSAGE")==0)){
printf(echoBuffer); /* Print the echo buffer */
printf("\n");
}else{
break; //break out of while loop
}
the strcmp of the echoBuffer and "END_OF_MESSAGE" never returns 0, even though "END_OF_MESSAGE" is what I am sending from the server..I have tried strncmp to compare the first 3 characters ("END") to no avail.
Note: when I print out the echoBuffer, the very last one does print out END_OF_MESSAGE which is just adding to my confusion.
Does anyone have any insights into what I am doing wrong?
Thank you.
am sending a file through TCP, and have the server sending a message containing "END_OF_MESSAGE" to alert the client that they have received the whole file and can close the socket.
Why? Just close the socket. That will tell the client exactly the same thing..
What you're attempting is fraught with difficulty. What happens if the file contains END_OF_MESSAGE? You're going to need an escape convention, and an escape for the escape, and inspect all the data when both sending and receiving.
The actual problem that you're seeing is that END_OF_MESSAGE can arrive along with the last bit of the file, so it isn't at the start of the buffer.
But it's all pointless. Just close the socket.
I'm in the making of a TCP client-server program that sends data from the server to the client (this works fine) and then echos it back to the server (doesn't work fine). when using the recv function, the first time I receive data works well but after that a lot of garbage comes in, the data itself comes as well but in the middle of a lot of garbage, both the recv/send return values are always correct. besides that the first time I start the testing of this program after starting the computer is much better (usually works). Does anyone have a idea about the why's? I believe some buffer fills up or the recv stops being a blocking function somehow...
Thanks in advance...
this is the Client's code:
for(i=0;i<FIRSTSENDING;i++)
//the buffer is a chained-list with 4 fields per struct ( x,y,z,time )
{
for(j=0;j<NUMBEROFVARIABLES;j++)
{
while(head->data[j][0]!='b'); //the data has a 'b' at first and 'e'
in the end.
b1 = send(t,head->data[j],strlen(head->data[j]),0);
}
while(head->general[0]!='b');
b1 = send(t,head->general,strlen(head->general),0);
temp = head;
head = head->next;
free(temp);
}
the code for the server is:
for(i=0;i<FIRSTSENDING;i++)
{
for(j=0;j<NUMBEROFVARIABLES;j++)
{
newDatagram->data[j][0]=0;
a = recv(s,reci, LENGTHVARAIBLE , 0);
strcpy(newDatagram->data[j],reci);
newDatagram->data[j][LENGTHVARAIBLE] = 0;
}
newDatagram->general[0]=0;
a = recv(s,reci, LENGTHTIME , 0);
strcpy(newDatagram->general,reci);
newDatagram->general[LENGTHTIME] = 0;
_ftime(&timebuffer);
//fixing the time and sending it
timer=(double)(timebuffer.millitm)/1000+timebuffer.time;
newDatagram->general[LENGTHTIME-1]=0;
pointerTime = &newDatagram->general[1];
if(newDatagram->general[0]=='b')
{
attol=std::stod(pointerTime);
if((timer-attol)>delay1)
delay1=timer-attol;
}
}
delay1=delay1/10*15*1000; //adding 10 percent and making milli the right delay
delay=(int)(delay1);
delay=delay% 100000;
nextDelay=delay;
printf("The first delay is: %d in milliseconds\n",delay); //This is an incriment of 10% to the delay.
the code finds the max delay for those runs and shows it.
a = recv(s,reci, LENGTHVARAIBLE , 0);
strcpy(newDatagram->data[j],reci);
This is not correct: strcpy expects the buffer to be a null-terminated string, but you do not send the terminating null byte. So strcpy reads more data from the buffer than recv fills in. Here is where the garbage comes from.
And even if you send the terminating null byte, you cannot guarantee that recv reads the whole message at once, or that it doesn't merge several messages in a single one (there are no any message boundaries in stream sockets).
You should use exactly a bytes after each recv (and maybe use memcpy instead of strcpy). To determine where a message ends, you can either send the zero byte and look for this byte at receiving side (note that you can get more than one message in a single recv call), or prepend each message with a fixed-length header containing the length of message.
I have a socket that is receiving streaming stock tick data. However, I seem to get a lot of truncated messages, or what appears to be truncated messages. Here is how I am receiving data:
if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv()");
exit(1);
}
else {
buf[numbytes] = '\0';
// Process data
}
Can recv() receive just a partial message of what was sent?
My feeling is I might need another loop around the recv() call that receives until a complete message is sent. I know that a libcurl implementation I have (not possible to use libcurl here I would think) has an outer loop:
// Read the response (sum total bytes read in tot_bytes)
for(tot_bytes=0; ; tot_bytes += iolen)
{
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf + tot_bytes, sizeof_buf - tot_bytes, &iolen);
if(CURLE_OK != res) {
// printf( "## %d", res );
break;
}
}
Do I need an recv() loop similar to the libcurl example (that verifiably works)?
We can also pass the flag to recv to wait until all the message has arrived. It works when you know the number of bytes to receive. You can pass the command like this.
numbytes = recv(sockfd, buf, MAXDATASIZE-1, MSG_WAITALL);
You're right, you need a loop. recv only retrieves the data that's currently available; once any data has been read, it doesn't wait for more to appear before it returns.
The manual page says "The receive calls normally return any data available, up to the requested amount, rather than waiting for receipt of the full amount requested."
TCP does not respect message boundaries. That means that recv() is not guaranteed to get the entire message, exactly as you hypothesize. And that is indeed why you need a loop around your recv(). (That's also why upper-layer protocols like HTTP either close the socket, or prepend a length indicator, so the recipient knows exactly when to stop reading from the socket.)
can recv() receive just a partial message of what was sent?
Yes, indeed, if you use TCP. I think this can help you.
Handling partial return from recv() TCP in C
I have two programs that use socket programming to communicate. Initially I will specify the no. of hops as to how many time they have to exchange messages between each other. Each time it receives a message, it will append its id to it. Hence the string grows in size every time. My program is working fine for 8000 hops, but after it crosses 8000, although program p1 sends a string of length 16388, p2 identifies that there are only 16385 in the socket ready to be read. I use ioctl() to determine the amount of characters ready to recv() in the socket, and then recv it in a char * variable...
Is it because there is a delay in the send () in p1 and recv() in p2 , that p2 identifies only 16385 characters in the socket ?
For ex:
If P1 sends length(16388)
P2 receives only the following length(16385)
Say I'm trying to send you 8 pumpkins. I put 6 of them on the table. You think, "I'm expecting 8 pumpkins, not 6. I'll wait until he puts the last two on the table." I think, "I don't want too many pumpkins 'in flight' at once. I'll wait until he takes 2 of these 6 before I put the last 2 on the table." We're stuck. We're each waiting for the other. We'll wait forever.
You are not permitted to wait until more bytes are received before accepting the bytes that have already been received. The reason for this is simple: No network protocol can allow each side to wait for the other. Since TCP permits the sending side to wait in this context, it cannot permit the receiving side to wait as well.
So accept the bytes as they are received. Don't wait for the other side to send all of them before accepting any of them. Otherwise, what happens if the other side is waiting for you to accept the first one before it sends any more?
You're probably hitting a kernel buffer limit. You can probably increase SO_RCVBUF on the receiver and it will work as you expect: SIOCINQ will eventually return the full size of the unread data.
But you shouldn't do that to ensure proper Functioning. messing with buffers should only be done when you want to tweak performance.
You should restructure the code so that you never have to ask the kernel how many bytes are available. Just read up to a reasonable limit(like 4096) and deal with one application-level message being broken up in multiple pieces. If you need message lengths/boundaries then you MUST implement them yourself on top of TCP.
Here's some silly code to read a message with a length header:
int ret, len = 0, have_read;
have_read = 0;
while (have_read < sizeof(len)) {
// This will likely always return sizeof(len) the first time.
ret = read(fd, ((char*)&len) + have_read, sizeof(len) - have_read);
if (ret <= 0) {
// Handle error.
}
have_read += ret;
}
char* buf = malloc(len);
if (!buf) {
// Handle error.
}
have_read = 0;
while (have_read < len) {
ret = read(fd, buf + have_read, len - have_read);
if (ret <= 0) {
// Handle error.
}
have_read += ret;
}
// Handle message in buf.