/* server4_select.c server skeleton SJ */ /* gcc -o server4_select server4_select.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 client2.c to do without */ #define ERRORCHEK(var, value, command) if (var == value) { \ perror(command); \ exit(1); \ } 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; char rbuf[MAXMSG]; /* receive buffer */ char sbuf[MAXMSG*2]; /* send buffer */ char yes='1'; fd_set fds, orig_fds; int fdmax, i; int port = 9876; /* default port */ printf("exit by pressing any key\n"); /* 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"); /* set up file descriptor set */ FD_ZERO(&orig_fds); FD_SET(ssock, &orig_fds); FD_SET(STDIN_FILENO, &orig_fds); /* for keyboard */ fdmax = ssock; while(1) { /* main accept() loop */ /* copy to temporary fds, select() changes the set */ fds = orig_fds; status = select(fdmax+1, &fds, NULL, NULL, NULL); ERRORCHEK(status, -1, "select"); /* quit (cruely) on user input */ if (FD_ISSET(STDIN_FILENO, &fds)) { close(ssock); exit(0); } /* check for new connections */ if (FD_ISSET(ssock, &fds)) { sin_size = sizeof(struct sockaddr_in); /* accept the waiting new connection */ csock = accept(ssock, (struct sockaddr *)&c_addr, &sin_size); if (csock == -1) { perror("accept"); continue; /* do not exit even if a connection failed */ } /* add to active fd set */ FD_SET(csock, &orig_fds); if (csock > fdmax) fdmax = csock; printf("server: new client: %s\n", inet_ntoa(c_addr.sin_addr)); } /* if ssock */ /* iterate over other sockets to find which socket is ready for reading */ for (i = 0; i <= fdmax; i++) { if (FD_ISSET(i, &fds) && (i != ssock)) { numbytes=recv(i, rbuf, MAXMSG-1, 0); if (numbytes > 0) { /* succesfull recv */ /* terminate message to make a string */ rbuf[numbytes] = '\0'; printf("Message was \"%s\"\n", rbuf); /* construct reply */ sprintf(sbuf, "You sent me \"%s\"%s", rbuf, EOL); /* send reply */ numbytes = send(i, sbuf, strlen(sbuf), 0); ERRORCHEK(numbytes, -1, "send"); if (numbytes != strlen(sbuf)) printf("Only %d bytes sent! Should have used repeated send...\n", numbytes); } else { /* closed pipe, or error */ if (numbytes == -1) perror("recv"); close(i); FD_CLR(i, &orig_fds); } /* else */ } /* if ISSET */ } /* for i */ } /* while(1) */ close(ssock); exit(0); } /* main() */