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?
Asked
Active
Viewed 7,567 times
2
-
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 Answers
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