views:

492

answers:

4

I have a Linux file descriptor (from socket), and I want to read one line. How to do it in C++?

+1  A: 

Pseudocode:

char newline = '\n';
file fd;
initialize(fd);
string line;
char c;
while( newline != (c = readchar(fd)) ) {
 line.append(c);
}

Something like that.

echo
This is usually good enough, but sometimes i get reaallly long lines, and reading one char at a time is too slow.
Łukasz Lew
+2  A: 

I you are reading from a TCP socket you can't assume when the end of line will be reached. Therfore you'll need something like that:

std::string line;
char buf[1024];
int n = 0;
while(n = read(fd, buf, 1024))
{
   const int pos = std::find(buf, buf + n, '\n')
   if(pos != std::string::npos)
   {
       if (pos < 1024-1 && buf[pos + 1] == '\n')
          break;
   }
   line += buf;
}

line += buf;

Assuming you are using "\n\n" as a delimiter. (I didn't test that code snippet ;-) )

On a UDP socket, that is another story. The emiter may send a paquet containing a whole line. The receiver is garanted to receive the paquet as a single unit .. If it receives it , as UDP is not as reliable as TCP of course.

yves Baumes
It's about TCP, yes. The problem is that the socket is interactive.I have to sent one line, then I get few lines. I can recognize the end with double newline "\n\n".
Łukasz Lew
... so I can't read ahead 1024 characters because there might be not so many. man 2 read shows that POSIX read have 3 arguments, so I don't know what read are you referring to.
Łukasz Lew
as I told you I didn't test it. I only write 'at the fly' . The code is easy to understand and adapt. By the way I've updated it to take in account your line delimiters: "\n\n"
yves Baumes
Łukasz: What do you mean "read ahead"? `read()` returns as soon as any data is available. Just call `read()` with a large buffer; it will not wait for the whole buffer to fill.
Artelius
Aaah, so you are assuming that the read is non-blocking ? Is it?
Łukasz Lew
reading 1024 characters at a time is not a problem. As long as the place holder is wide enough and that you don't look over what is transmitted by read() call. That is the meaning of the read() return value: the n variable in my exemple.
yves Baumes
No, a non-blocking read is one that returns even if *no* data is available. However, even in blocking mode, read() will return as soon as data arrives. From the man page: "On success, the number of bytes read is returned (zero indicates end of file), and the file position is advanced by this number. It is not an error if this number is smaller than the number of bytes requested; this may happen for example because fewer bytes are actually available right now"
Artelius
Great. Thanks for all the effort in explaining it to me.
Łukasz Lew
Nie ma sprawy ;)
Artelius
@Artelius : thnaks to you for great explanation! With a better english than mine . :-)
yves Baumes
A: 
Anders Hedström
A: 

Here is a tested, quite efficient code:

bool ReadLine (int fd, string* line) {
  // We read-ahead, so we store in static buffer 
  // what we already read, but not yet returned by ReadLine.
  static string buffer; 

  // Do the real reading from fd until buffer has '\n'.
  string::iterator pos;
  while ((pos = find (buffer.begin(), buffer.end(), '\n')) == buffer.end ()) {
    char buf [1025];
    int n = read (fd, buf, 1024);
    if (n == -1) {    // handle errors
      *line = buffer;
      buffer = "";
      return false;
    }
    buf [n] = 0;
    buffer += buf;
  }

  // Split the buffer around '\n' found and return first part.
  *line = string (buffer.begin(), pos);
  buffer = string (pos + 1, buffer.end());
  return true;
}

It's also useful to setup signal SIGPIPE ignoring in reading and writing (and handle errors as shown above):

signal (SIGPIPE, SIG_IGN);
Łukasz Lew