Single-Threaded TCP With Select
#include "funcs.h"
#define BIGBUF 50
#define SIGPIPE_ERROR 1
#define CONNECT_ERROR 2
#define INTERRUPT 3
int active;
main()
{
char buf[BIGBUF];
void set_up_signals(void);
void readn (int active, char *buf, int bufsize);
void writen(int active, char *buf, int bufsize);
void connect_to_server(void);
set_up_signals();
connect_to_server();
while(printf("Enter string: "), memset(buf, 0, BIGBUF),
fgets(buf,BIGBUF,stdin), strncmp(buf,"quit", 4))
{
buf[strlen(buf) - 1] = '\0'; /* Get rid of \n */
writen(active,buf,1);
writen(active, buf + 1, BIGBUF - 1);
memset(buf, 0, BIGBUF);
readn(active,buf,BIGBUF);
printf("From server: %s\n", buf);
}
memset(buf, 0, BIGBUF);
strcpy(buf,"quit");
writen(active, buf, 1);
writen(active, buf + 1, BIGBUF - 1);
close(active);
}
void set_up_signals(void)
{
struct sigaction sa;
void pipe_handler(int signum), term_handler(int signum);
sigfillset(&sa.sa_mask);
sa.sa_handler = pipe_handler;
sa.sa_flags = 0;
sigaction(SIGPIPE, &sa, NULL);
sa.sa_handler = term_handler;
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
}
void connect_to_server()
{
struct sockaddr_in sin;
active = socket(PF_INET, SOCK_STREAM, 0);
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(3014);
sin.sin_family = AF_INET;
inet_aton("153.18.17.11", &sin.sin_addr);
if (connect(active, (struct sockaddr *) &sin, sizeof(sin)) == -1)
{
perror("Bad connection.");
exit(CONNECT_ERROR);
}
}
void pipe_handler(int signum)
{
printf("Server disconnected\n");
close(active);
exit(SIGPIPE_ERROR);
}
/************************* Terminal signal handler ************************/
void term_handler(int signum)
{
char buf[BIGBUF] = {'\0'};
memset(buf, 0, BIGBUF);
strcpy(buf, "quit");
writen(active, buf, 1);
writen(active, buf + 1, BIGBUF - 1);
close(active);
exit(INTERRUPT);
}
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) <= 0)
raise(SIGPIPE);
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(fd,mover,nleft)) < 0)
return -1; /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
#include "funcs.h"
#define BUFSIZE 50
#define NOT_USED -1
int readsock;
sigjmp_buf env;
fd_set saveset;
struct timetable
{
int socket;
time_t requesttime;
};
struct timetable reqtimes[100];
main()
{
void readn(int readsock, char *string, int bufsize);
void set_up_SIGPIPE(void);
fd_set readset;
int socket, passive, active, lowwater = 50, i;
char string[50];
int set_up_passive_socket(void);
int socklen = sizeof(int);
set_up_SIGPIPE();
passive = set_up_passive_socket();
FD_ZERO(&saveset);
FD_SET(passive, &saveset);
for (i = 0; i < 100; i++) reqtimes[i].socket = NOT_USED;
for(;;)
{
memcpy(&readset, &saveset, sizeof(fd_set));
select(FD_SETSIZE, &readset, NULL, NULL, NULL);
for (socket = 0; socket < 100; socket++)
{
if (reqtimes[socket].socket == NOT_USED) continue;
if (time(NULL) - reqtimes[socket].requesttime > 10)
{
close(socket);
FD_CLR(socket, &saveset);
reqtimes[socket].socket = NOT_USED;
}
}
if (FD_ISSET(passive, &readset))
{
active = accept(passive, NULL, NULL);
setsockopt(active, SOL_SOCKET, SO_RCVLOWAT, &lowwater, socklen);
reqtimes[active].socket = active;
reqtimes[active].requesttime = time(NULL);
FD_SET(active, &saveset);
}
for(readsock = passive; readsock < FD_SETSIZE ; readsock++)
{
sigsetjmp(env, 1);
if (readsock != passive && FD_ISSET(readsock, &readset))
{
printf("Inside server! Socket is %d.\n", readsock);
memset(string, 0, BUFSIZE);
readn(readsock, string, BUFSIZE);
if (strcmp(string, "quit") == 0)
{
FD_CLR(readsock, &saveset);
close(readsock);
reqtimes[readsock].socket = NOT_USED;
continue;
}
printf("Got %s from client!\n", string);
writen(readsock, string, 1);
writen(readsock, string + 1, BUFSIZE - 1);
}
}
}
}
int set_up_passive_socket(void)
{
struct sockaddr_in sin;
int passive;
sin.sin_family = AF_INET;
sin.sin_port = htons(3014);
sin.sin_addr.s_addr = htonl(INADDR_ANY);
if ((passive = socket(AF_INET,SOCK_STREAM,0)) < 0)
{
perror("Server: socket error!");
exit(1);
}
if (bind(passive, (struct sockaddr *) &sin, sizeof(sin)) < 0)
{
perror("Binding error in server!");
exit(2);
}
if (listen(passive, 5) < 0)
{
perror("Listen error in server!");
exit(3);
}
return passive;
}
void set_up_SIGPIPE(void)
{
void handler(int signum);
struct sigaction sa;
sa.sa_handler = handler;
sa.sa_flags = 0;
sigfillset(&sa.sa_mask);
sigaction(SIGPIPE, &sa, NULL);
}
void handler(int signum)
{
close(readsock);
FD_CLR(readsock, &saveset);
reqtimes[readsock].socket = NOT_USED;
readsock++;
siglongjmp(env, 1);
}
int readn(int fd, char *buf, int bytes)
{
int nleft;
int nread;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nread = read(fd,mover,nleft)) < 0)
if (errno == EAGAIN)
{
errno = 0;
continue;
}
else raise(SIGPIPE);
else if (nread == 0)
raise(SIGPIPE); /**** EOF! ****/
nleft -= nread;
mover += nread;
}
return (bytes - nleft);
}
int writen(int fd, char *buf, int bytes)
{
int nleft;
int nwritten;
char *mover = buf;
nleft = bytes;
while (nleft > 0){
if ((nwritten = write(fd,mover,nleft)) < 0)
raise(SIGPIPE); /**** Error!! ****/
nleft -= nwritten;
mover += nwritten;
}
return bytes;
}
################################### Output ###############################
$ s&
[1] 25351
[voyager demos]$ c
Enter string: foo
Inside server! Socket is 4.
Got foo from client!
From server: foo
Enter string: whatever
Inside server! Socket is 4.
Got whatever from client!
From server: whatever
Enter string:
[2]+ Stopped c
$ c
Enter string: foo
Inside server! Socket is 5.
Got foo from client!
From server: foo
Enter string: bar
Inside server! Socket is 5.
Got bar from client!
From server: bar
Enter string: quit
Inside server! Socket is 5.
$ jobs
[1]- Running s &
[2]+ Stopped c
$ fg %2
c
foo
Server disconnected