Note

The reading method of the examples used in this chapter works perfectly with a client such as the Linux version of the telnet command, as this client sends (by default) line by line, in the TCP communication channel, what is entered. On the other hand, this does not work with the Windows version of the telnet command, as this other client sends character by character as it is entered.

How to resolve the issue?

It must be assumed that a reception of a TCP stream can be fragmented into several pieces of size (all of which are smaller than the buffer passed to the read function). A line must therefore be read through a read loop that puts each piece together until the end of line character is received.

For completeness, it is also necessary to provide for the case where you would start receiving some characters from the next line, which should be preserved and isolated from the previous line.

Without stream support With stream support

In multi-process

See the improved solutions of LAB n°2 question n°2.

In multi-thread

See the improved solutions of LAB n°2 question n°3.

In single-task

See the improved solutions of LAB n°2 question n°4.

In the C language, there is the FILE type defined in stdio.h that offers several possibilities including the following:

  • Using the fgets(char *buffer, int size, FILE *stream) function which reads at most size - 1 characters from stream and places them in the buffer pointed to by buffer. The reading stops after EOF or a newline. If a newline is read, it is placed in the buffer. A null byte '\0' is placed at the end of the line, thereby transforming the buffer's contents into a string. The function returns a pointer to buffer if it succeeds, and NULL on error or if the end of the file is reached before reading at least one character.
  • Using the feof(FILE *stream) function which tests the end-of-file indicator of the stream pointed to by stream, and returns a nonzero value if this indicator is active.
  • Using the fclose(FILE *stream) function which closes the stream as well as the file descriptor hiding behind it.

A file descriptor can be associated with a stream management using the fdopen(int fd, const char *mode) function, which returns a pointer to a FILE if the association was successful. The first argument of the function is the file descriptor. The second argument is a string indicating the mode of use, which must be compatible with the file descriptor's operation.

Example:

#include <stdio.h>

void server_dialog(int fd) {
	FILE *stream;
	char buffer[1024];

	stream=fdopen(fd,"rb");
	if (stream!=NULL) {
		while (!feof(stream)) {
			fgets(buffer,sizeof(buffer),stream);
			write(fd,buffer,strlen(buffer));
		}
	}
}
				

Note:

Even if this method may be enjoyable to use and works very well in single-client and multi-client when using multi-process or multi-thread, it should not be forgotten that stream reading functions such as fgets are, by default, blocking because they use read loops and can therefore pose problems in a multi-client/single-task programming using the select function.