2

I am trying to write a TCP server that responds to a client whenever a message, guaranteed to end with "\n" is received. I have seen other posts like this one that seem to look at each individual character to see if it is a new line, but this seems like it defeats the purpose of reading data into a buffer. Is there a better way to achieve this?

Community
  • 1
  • 1
Christopher Shroba
  • 7,006
  • 8
  • 40
  • 68
  • I don't see why it defeats the purpose of reading the data into a buffer. If the protocol doesn't give you the length of the line up front, then you probably have to read one character at a time, or run the risk of reading beyond the first newline and therefore reading part of a second message. – Jonathan Leffler Jan 30 '15 at 06:15
  • On second thought, could I use fscanf to read a string ending with "\n"? Would that work with a socket? – Christopher Shroba Jan 30 '15 at 06:24
  • How are you going to do that? What's the declaration of your string variable (or how do you allocate it dynamically), and what is the `fscanf()` format you're going to use? (And are you planning to use [`fdopen()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/fdopen.html) to associate the socket file descriptor with a file stream, since there isn't a `dscanf()` analog to [`dprintf()`](http://pubs.opengroup.org/onlinepubs/9699919799/functions/dprintf.html), somewhat to my surprise?) – Jonathan Leffler Jan 30 '15 at 06:28
  • Check this [I/O for tcp sockets](https://github.com/Mr-Io/cserverframework#light-c-server-framework) from my repository. It is optimized for network programming. Among other things, input is buffered to reduce `read` system calls (something similar to what `stdio` does) – MrIo Apr 24 '23 at 18:28

1 Answers1

1

The other way to do it is to handle the buffering yourself, e.g.:

std::string nextCommand;

while(1)
{
   char buf[1024];
   int numBytesRead = recv(mySocket, buf, sizeof(buf), 0);
   if (numBytesRead > 0)
   {
      for (int i=0; i<numBytesRead; i++)
      {
         char c = buf[i];
         if (c == '\n')
         {
            if (nextCommand.length() > 0)
            {
               printf("Next command is [%s]\n", nextCommand.c_str());
               nextCommand = "";
            }
         }
         else nextCommand += c;
      }
   }
   else
   {
      printf("Socket closed or socket error!\n");
      break;
   }
}

(Note that for simplicity I'm using a C++ std::string to hold the data in my example code; since you're using C, you'd need to find an alternate way to store the incoming string. If you can guarantee a maximum command length, you could just use a fixed-size char array and a counter variable; if you need to handle unlimited command sizes, then you'd need to come up with some sort of data structure that can grow as necessary, e.g. by dynamically allocating a larger buffer with realloc() or by using a linked list or something)

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234