Devember: Improved echo Server

This post is part of the Devember collection, useful for the study of the Socket API.

Devember: Improved echo Server

I abandoned the idea of a recursive server to avoid proliferation of child processes on each new connected client. Now the server benefits of the I/O Multiplexing using the select function to handle the listening socket and the other connected sockets.

// Call the select function
if ((ready = select(maxfd + 1, &rset, NULL, NULL, NULL)) < 0) {
	perror("select");
	return -1;
}

// Check for incoming connections
if (FD_ISSET(listenfd, &rset)) {
	if ((connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen)) < 0) {
		perror("accept");
		return -1;
	}
	// Save connected socket descriptor in the client array
	for (i = 0; i < FD_SETSIZE; i++) {
		if (client[i] < 0) {
			client[i] = connfd;
			break;
		}
	}
	// ...
}

// Serve clients
for (i = 0; i < FD_SETSIZE; i++) {
	if ((sockfd = client[i]) < 0) {
		continue;
	}
	if (FD_ISSET(sockfd, &rset)) {
		if ((n = exso_readln(sockfd, buff, MAXLINE)) < 0) {
			perror("exso_readln");
		}
		else if (n == 0) {
			printf("A client is gone\n");
			close(sockfd);
			FD_CLR(sockfd, &allset);
			client[i] = -1;
		} else {
			if (exso_writen(sockfd, buff, n) < 0) {
				perror("exso_writen");
			}
		}
		// ...
	}
}

Broadcast

Since I have an array of all the connected clients, I turned the server in a chat room. Now every message sent by a client is broadcast to all the other connected clients:

int sockfd;
for (i = 0; i < FD_SETSIZE; i++) {
	if (sockfd == client[i] || client[i] == -1) {
		continue;
	}
	if (exso_writen(client[i], buff, n) < 0) {
		perror("exso_writen");
	}
}

The complete code can be found on this repository.

14 December 2015