I am having trouble figuring out how to store client handles without blocking the server. I am following the concurrent server model detailed in "The Socket Networking API" by Stevens.
My program creates tic tac toe matches between players.
The structure of the program is this: The server handles both TCP/UDP connections. The client program can either query or connect to the server. If the client queries, the UDP socket handles the query by returning a list of the handles of already connected clients.
If the client connects, the TCP socket handles the connection by 1. Asking the client for a handle and 2. Storing their handle. If there are two clients who are connected, a separate process is spawned to create a match between them (but this is not relevant now).
In my program, I am multiplexing the TCP/UDP socket with select()
. My current issue is how to deal with asking and storing client handles without blocking.
I have considered:
- creating another thread to deal with asking and receiving client handle.
Keeping a list of of connected client sockets and add them to fd_set data structure and multiplex between them in addition to the TCP/UDP sockets.
Spawning another process to deal with asking/receiving handles, but this is not probable since I am storing the handles in a global linked list data structure so that the server can return a list when queried. Communicating back to parent would be too cumbersome.
*The code below has not been tested yet and is incomplete since I have not figured out how to resolve this issue.
game_head = NULL; game_tail = game_head;
/* Creating TCP listening socket */
tcp_listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(TCP_PORT);
bind(tcp_listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
listen(tcp_listenfd, LISTENQ);
/* Creating UDP socket */
udpfd = socket(AF_INET, SOCK_DGRAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(UDP_PORT);
bind(udpfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
/* Signal handling (also possibly handle SIGCHLD)*/
signal(SIGINT, sighandler);
signal(SIGUSR2, sighandler);
FD_ZERO(&rset);
maxfdp1 = max(tcp_listenfd, udpfd) + 1;
while(1) {
if (terminate)
terminate_program();
FD_SET(tcp_listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue;
else
perror("select error");
}
if (FD_ISSET(tcp_listenfd, &rset)) {
len = sizeof(cliaddr);
tcp_connfd = accept(tcp_listenfd, (struct sockaddr *) &cliaddr, &len);
close(tcp_connfd);
}
if (FD_ISSET(udpfd, &rset)) {
}
}