I'd like to replicate the following ruby code of a simple forking TCP echo server in C:
require 'socket'
port = 3333
server = TCPServer.new(port)
puts "Starting TCPServer @ port #{port} with PID=#{Process.pid}"
loop do
client = server.accept
pid = fork do
puts "PID = #{Process.pid}"
while (line = client.gets)
client.write(line)
end
client.close_write
exit 0
end
if(pid > 0)
Process.detach(pid)
end
end
I started with http://beej.us/guide/bgnet/examples/server.c and I changed the forking part to:
if (!fork())
{ // this is the child process
FILE *client = fdopen (new_fd, "r+");
close (sockfd); // child doesn't need the listener
char buffer[BUFSIZ];
while (fgets (buffer, BUFSIZ, client))
{
fputs (buffer, stdout);
}
fclose (client);
exit (0);
}
Basically, I'm wrapping the file descriptor of the socket in a FILE structure (fdopen(...)
) in order to get fgets(...)
.
Is this the wrong thing to do to begin with?
This whole approach seems to work if I do nc localhost 3333
(with the compiled server running) and simply type the input on the command line (lines get echoed back). However, if I do cat a_multiline_file.txt|nc localhost 3333
, I only get the first
line back because in that case, all except the first call to fgets()
fail (I tried doing the same fgets
in an infinite loop).
I'm curious to know what the cause of the problem is and how I can do line-by-line reading on a socket correctly.
EDIT:
On JoeManiaci's advice, I added:
perror("Last failure");
after the while loop, which got me "Last failure: Illegal seek" for the second case.
So that makes sense -- seeking doesn't make sense on sockets, and if fgets does not only buffering but seeking too, that makes the fdopen approach out of the question for sockets.
Part 2 of my question remains--how do I do line-oriented reading on sockets correctly in C?