#include <pthread.h>#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <arpa/inet.h>#include <netinet/in.h>#include <sys/wait.h>#include <signal.h>#include <time.h>#include <string.h>#include <errno.h>//--------------------------------------------------------------------// Function prototype//--------------------------------------------------------------------void signal_handler(int signum);void *thread_main(void *arg);//--------------------------------------------------------------------// Main function//--------------------------------------------------------------------int main(int argc, char **argv){ int listening_socket; unsigned short port; int backlog; //------------------------------------------------------------------ // Parse command line arguments //------------------------------------------------------------------ port = (unsigned short) strtol(argv[2], NULL, 10); backlog = (int) strtol(argv[3], NULL, 10); //------------------------------------------------------------------ // step 1, create socket //------------------------------------------------------------------ //int socket(int domain, int type, int protocol); if ((listening_socket = socket(PF_INET, SOCK_STREAM, 0)) < 0) { // failed fprintf(stderr, "[%d]Create new TCP socket failed: %s\n", getpid(), strerror(errno)); exit(1); } fprintf(stderr, "[%d]New TCP socket created, listening_socket = %d\n", getpid(), listening_socket); //------------------------------------------------------------------ // Set SO_REUSEADDR & SO_REUSEPORT options //------------------------------------------------------------------ int optval; optval = 1; //int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) { fprintf(stderr, "[%d]Set socket option SO_REUSEADDR failed: %s\n", getpid(), strerror(errno)); } else { fprintf(stderr, "[%d]Set socket option SO_REUSEADDR successfully.\n", getpid()); }#ifdef SO_REUSEPORT optval = 1; //int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen); if (setsockopt(listening_socket, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval)) < 0) { fprintf(stderr, "[%d]Set socket option SO_REUSEPORT failed: %s\n", getpid(), strerror(errno)); } else { fprintf(stderr, "[%d]Set socket option SO_REUSEPORT successfully.\n", getpid()); }#endif //------------------------------------------------------------------ // step 2, bind //------------------------------------------------------------------ struct sockaddr_in local_ipv4_address;// IPv4 memset(&local_ipv4_address, 0, sizeof(local_ipv4_address)); local_ipv4_address.sin_family = AF_INET;// IPv4 local_ipv4_address.sin_port = htons(port);// Network byte order // int inet_pton(int af, const char *src, void *dst); inet_pton(AF_INET, argv[1], &local_ipv4_address.sin_addr); // Bind all interfaces //local_ipv4_address.sin_addr.s_addr = INADDR_ANY; //int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen); if (bind(listening_socket, (struct sockaddr *) &local_ipv4_address, sizeof(local_ipv4_address)) < 0) { fprintf(stderr, "[%d]Bind to %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno)); close(listening_socket); exit(1); } fprintf(stderr, "[%d]Bound to %s:%d successfully.\n", getpid(), argv[1], port); //------------------------------------------------------------------ // step 3, listen //------------------------------------------------------------------ //int listen(int sockfd, int backlog); if (listen(listening_socket, backlog) < 0) { fprintf(stderr, "[%d]Listen on %s:%d failed: %s\n", getpid(), argv[1], port, strerror(errno)); close(listening_socket); exit(1); } fprintf(stderr, "[%d]Listen on %s:%d successfully.\n", getpid(), argv[1], port); fprintf(stderr, "[%d]Waiting for incomming connections ...\n", getpid()); //------------------------------------------------------------------ // Register signal handler //------------------------------------------------------------------ struct sigaction act, oact;#if 0 struct sigaction { void (*sa_handler) (int); void (*sa_sigaction) (int, siginfo_t *, void *); sigset_t sa_mask; int sa_flags; void (*sa_restorer) (void); };#endif memset(&act, 0, sizeof(act)); act.sa_handler = signal_handler; //int sigemptyset(sigset_t *set); sigemptyset(&act.sa_mask); act.sa_flags = 0; //int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact); sigaction(SIGCHLD, &act, &oact); //------------------------------------------------------------------ // Main loop //------------------------------------------------------------------ for (;;) { //---------------------------------------------------------------- // accept(), create a new_connected_socket //---------------------------------------------------------------- /* * The accept() system call is used with connection-based socket types (SOCK_STREAM, SOCK_SEQPACKET). * * It extracts the first connection request on the queue of pending connections, creates a new connected * socket, and returns a new file descriptor referring to that socket. * * The newly created socket is not in the listening state(in ESTABLISHED state) * * The original socket sockfd is unaffected by this call(still in LISTEN state) */ int new_connected_socket; struct sockaddr_in peer_ipv4_address; socklen_t peer_ipv4_address_length; // peer_ipv4_address_length is a value-result parameter peer_ipv4_address_length = sizeof(peer_ipv4_address); //int accept(int sockfd, struct sockaddr *addr, socklen_t * addrlen); if ((new_connected_socket = accept(listening_socket, (struct sockaddr *) &peer_ipv4_address, &peer_ipv4_address_length)) < 0) { // failed if (errno == EINTR) {// Interrupted by signalcontinue; } else {// TODO: check other error code } fprintf(stderr, "[%d]Accept new connections on socket %d failed: %s\n", getpid(), listening_socket, strerror(errno)); break; } else { // success char peer_ipv4_address_string[] = "ddd.ddd.ddd.ddd"; //const char *inet_ntop(int af, const void *src, char *dst, socklen_t cnt); inet_ntop(AF_INET, &peer_ipv4_address.sin_addr, peer_ipv4_address_string, sizeof(peer_ipv4_address_string)); fprintf(stderr, "[%d]Accepted a new connection %d from %s:%d.\n", getpid(), new_connected_socket, peer_ipv4_address_string, ntohs(peer_ipv4_address.sin_port)); //-------------------------------------------------------------- // create new thread //-------------------------------------------------------------- pthread_t tid; pthread_attr_t attr; int code; //int pthread_attr_init(pthread_attr_t *attr); pthread_attr_init(&attr); //int pthread_attr_setdetachstate(pthread_attr_t * attr, int detach - state); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); //int pthread_create(pthread_t * restrict thread, const pthread_attr_t * restrict attr, void *(*start_routine) (void *), void *restrict arg); if ((code = pthread_create(&tid, &attr, thread_main, (void *) &new_connected_socket)) != 0) {fprintf(stderr, "[%d]Create new thread failed: %s\n", getpid(), strerror(code)); } else {fprintf(stdout, "[%d]New thread created.\n", getpid()); } //int pthread_attr_destroy(pthread_attr_t *attr); pthread_attr_destroy(&attr); } } //------------------------------------------------------------------ // final, close listening_socket //------------------------------------------------------------------ close(listening_socket); return 0;}void signal_handler(int signum){ fprintf(stderr, "[%d]Caught signal %d.\n", getpid(), signum); pid_t pid; int status; //pid_t wait(int *status); if ((pid = wait(&status)) < 0) { // failed fprintf(stderr, "wait() failed: %s\n", strerror(errno)); } else { fprintf(stderr, "[%d]Child process %d terminated, status = 0x%08x\n", getpid(), pid, status); // check status }}void *thread_main(void *arg){ int fd = *(int *) arg; //-------------------------------------------------------------- // Compose current time information //-------------------------------------------------------------- // time_t time(time_t *t); time_t now = time(NULL); struct tm *tm; //struct tm *localtime(const time_t *timep); tm = localtime(&now); char buffer[128];#if 0 struct tm { int tm_sec;/* seconds */ int tm_min;/* minutes */ int tm_hour;/* hours */ int tm_mday;/* day of the month */ int tm_mon;/* month */ int tm_year;/* year */ int tm_wday;/* day of the week */ int tm_yday;/* day in the year */ int tm_isdst;/* daylight saving time */ };#endif memset(buffer, 0, sizeof(buffer)); //int snprintf(char *str, size_t size, const char *format,...); snprintf(buffer, sizeof(buffer) - 1, "Current time: %04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); //-------------------------------------------------------------- // Send current time to client //-------------------------------------------------------------- ssize_t n; //ssize_t write(int listening_socket, const void *buf, size_t count); if ((n = write(fd, buffer, strlen(buffer))) < 0) { fprintf(stderr, "[%d]Send data to client fialed: %s\n", getpid(), strerror(errno)); } else { fprintf(stderr, "[%d]Sent %d bytes (\"%s\" to client successfully.\n", getpid(), n, buffer); } //-------------------------------------------------------------- // close new_connected_socket //-------------------------------------------------------------- close(fd); pthread_exit((void *) 0);}// vim:tabstop=8