/* server4.c server skeleton for ex4 20 */ /* gcc -o server4_fork server4_fork.c -lnsl -lsocket -lresolv */ #include #include #include #include #include #include #include #include #include #include #include /* how many pending connections */ #define BACKLOG 3 /* size of the send/receive buffer */ #define MAXMSG 1000 /* official network end-of-line is CR LF */ #define EOL "\015\012" /* this macro can be used to check errors, see client.c to do without */ #define ERRORCHEK(var, value, command) if (var == value) { \ perror(command); \ exit(1); \ } /* signal handled to clean the child processes by wait() */ void sigchld_handler(int s) { while(wait(NULL) > 0); } int main(int argc, char *argv[]) { int ssock, csock; /* listen on ss, new connection on csock */ struct sockaddr_in own_addr; /* my address information */ struct sockaddr_in c_addr; /* client address information */ unsigned int sin_size = sizeof(struct sockaddr_in); int status, numbytes, childpid; char rbuf[MAXMSG]; /* receive buffer */ char sbuf[MAXMSG*2]; /* send buffer */ char yes='1'; struct sigaction sa; int port = 9876; /* default port */ /* port as optional parameter */ if (argc > 1) port = atoi(argv[1]); /* get socket */ ssock = socket(AF_INET, SOCK_STREAM, 0); ERRORCHEK(ssock, -1, "socket"); /* reuse port immediately */ status = setsockopt(ssock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)); ERRORCHEK(status, -1, "setsockopt"); /* fill in the own address */ own_addr.sin_family = AF_INET; own_addr.sin_port = htons(port); own_addr.sin_addr.s_addr = INADDR_ANY; /* automatically fill with own IP */ memset(&(own_addr.sin_zero), '\0', 8); /* bind to port */ status = bind(ssock, (struct sockaddr *)&own_addr, sin_size); ERRORCHEK(status, -1, "bind"); /* listen the port */ status = listen(ssock, BACKLOG); ERRORCHEK(status, -1, "listen"); /* setup signal handler */ sa.sa_handler = sigchld_handler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; status = sigaction(SIGCHLD, &sa, NULL); ERRORCHEK(status, -1, "sigaction"); while(1) { /* main accept() loop */ sin_size = sizeof(struct sockaddr_in); csock = accept(ssock, (struct sockaddr *)&c_addr, &sin_size); if (csock == -1) { perror("accept"); continue; /* do not exit even if a connection failed */ } printf("server: new client: %s\n", inet_ntoa(c_addr.sin_addr)); /* start new process */ /* remember to check the return value of fork() for errors (-1) */ /* this saves the system is case of exhausted resources */ childpid = fork(); ERRORCHEK(childpid, -1, "fork"); if (childpid == 0) { /* child process */ /* child does not use original server socket */ close(ssock); /* serve until quit was received */ do { numbytes=recv(csock, rbuf, MAXMSG-1, 0); if (numbytes == -1) { perror("recv"); continue; } else if (numbytes == 0) { /* connection closed */ continue; } /* terminate message to make a string */ rbuf[numbytes] = '\0'; printf("Message was \"%s\"\n", rbuf); /* construct reply */ sprintf(sbuf, "You %s:%d sent me \"%s\"%s", inet_ntoa(c_addr.sin_addr), ntohs(c_addr.sin_port), rbuf, EOL); /* send reply */ numbytes = send(csock, sbuf, strlen(sbuf), 0); ERRORCHEK(numbytes, -1, "send"); if (numbytes != strlen(sbuf)) printf("Only %d bytes sent! Should have used repeated send...\n", numbytes); } while (!strstr(rbuf, "quit")); /* after service, close connection and exit */ close(csock); exit(0); /* REMEMBER TO exit() THE CHILD PROCESS IN ALL CASES !!!! */ } else { /* if (childpid) */ /* parent process */ printf("Child process %d was created\n", childpid); /* parent does not need new socket */ close(csock); } /* else */ } /* while(1) */ close(ssock); exit(0); } /* main() */