By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,510 Members | 1,821 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,510 IT Pros & Developers. It's quick & easy.

[C] Problem reading from a socket

P: 5
[Windows, C]

Hi everyone, I'm having a bit of a problem with my TCP server.

I need my server to receive strings in the form of "Fname.", where F is a flag.
The first time a string is received, the output is correct. The second time, the character "." is cut off, and that causes an error.
Sometimes, the server runs with no errors, and that makes me think something is messing with the reading buffer.

Here's that part of the server.

Expand|Select|Wrap|Line Numbers
  1. while (1)
  2. //...
  3. connfd=Accept(listenfd, (SA*) &cliaddr, &cliaddrlen);
  4. //...
  5.  
  6. while(Read(connfd, &command, sizeof(char))>0)
  7. {
  8.  
  9. if(command=='C')
  10. {
  11. memset(&buf, 0, sizeof(buffer));
  12. Read(connfd, buf, sizeof(buffer));
  13. sscanf(buffer, "%s", name);
  14. //....
  15. }
  16. //......if(command=='E') {etc.}
  17.  
  18. }
  19.  
  20. Close(connfd);
  21. exit(0);
  22. }
  23.  
I tried to use recv() and Readn(), but with no results.

Thanks for any suggestion, and sorry for the English.
Aug 30 '10 #1
Share this Question
Share on Google+
9 Replies


Oralloy
Expert 100+
P: 983
@Fabrizio3k,

First off, nothing guarantees that all the bytes you send will be recieved by a single Read.

So, you should provide a record terminator. Line-Feed '\n', is pretty standard. Null '\0' works too. Pick your poison. If you have to be able to send an arbitrary byte string, then you have to transmit the string length before sending the data block (with similar terminator issues on the length string, assuming you use ASCII, and not fixed-length binary).

I know this seems silly, but...

You should always check the number of bytes returned by Read. Nothing guarantees that everything sent with a single write will arrive in a single packet.

So, you can do the cheezy thing and read a byte at a time until your sentinel, which you simply discard.

Does that help?

Expand|Select|Wrap|Line Numbers
  1. char ch;
  2. while (in = Read(connfd, ch, sizeof ch))
  3. {
  4.   if (ch != '\n')
  5.     buffer += ch;
  6.   else
  7.   {
  8.     process buffer...
  9.   }
  10. }
  11.  
  12. // connection was closed, do something rational
  13.  
Good Luck!

If you need more help, shout.
Aug 30 '10 #2

P: 5
Hi Oralloy, thanks for your reply.

The problem is that there should be no record terminator... the server should process the command as soon as it receives the last character of the command (that's not always ".").

I was searching for a non-blocking function in alternative to read() or recv(), instead of setting the whole socket to non-blocking.
Thanks anyway.
Aug 30 '10 #3

Oralloy
Expert 100+
P: 983
@Fabrizio3k,

If there's no record length or record terminator, how do you know when the complete record is recieved?

Cheers!
Oralloy
Aug 30 '10 #4

P: 5
Well, I guess I have to read every single character from the socket until I can't read anymore...
I think setting the server to non blocking and reading single characters one by one could be a solution.
Aug 30 '10 #5

Oralloy
Expert 100+
P: 983
How do you know you're done reading, then?

That's the problem. Without a concrete knowledge of when each message ends, you won't know when to process the request.

You might try waiting one second, but what if the client sends two messages immediately in sequence? Then you're in trouble. Also, what if there's a network delay for some reason? That would throw your protocol for a loop, too.

Am I making any sense?

Cheers,
Oralloy
Aug 30 '10 #6

P: 5
Yes, I know what you mean.
I could separate cases (for example, if the flag is 'E', process immediately, if the flag is 'D', wait until '.', since the format is fixed... but that would ignore any input errors, such as a command finishing with ',' instead of '.')

I'll think about it, anyway.
Thanks again.
Aug 30 '10 #7

Oralloy
Expert 100+
P: 983
Do you have the authority to define this network protocol, or not?

Basically, do you have control of the client program?

Try this on the client side:
Expand|Select|Wrap|Line Numbers
  1. char command = ...
  2. long length;
  3. char *name = ...
  4.  
  5. send(server, &command, sizeof command);
  6.  
  7. length = htonl(strlen(name));
  8. send(server, &length, sizeof length);
  9.  
  10. length = strlen(name);
  11. send(server, name, strlen(name));
  12.  
And on the server side:
Expand|Select|Wrap|Line Numbers
  1. char command;
  2. long length;
  3. char *name;
  4.  
  5. Read(client, &command, sizeof command);
  6. Read(client, &length, sizeof length);
  7.  
  8. length = ntohl(length);
  9. name = new char[1+length];
  10. Read(client, name, length);
  11. name[length] = '\0';
  12.  
I'll leave the error checking to you, though.

Or is that not possible?

Cheers!
Oralloy
Aug 30 '10 #8

P: 5
I think I'll do as you say.
Thanks for the help!
Aug 30 '10 #9

Oralloy
Expert 100+
P: 983
Fabrizio3k,

Good luck!

If you need more help, let us know.

Oralloy.
Aug 30 '10 #10

Post your reply

Sign in to post your reply or Sign up for a free account.