├── chapter3 ├── Readme ├── clientsock.h ├── errexit.c ├── Makefile ├── PrintAllServByPort.c ├── TCPdaytime.c ├── UDPtimed.c ├── TCPdaytimed.c ├── clientsock.c ├── UDPtime.c └── passivesock.c ├── chapter5 ├── Readme ├── Makefile ├── errexit.c ├── TCPclient.c └── TCPservice.c ├── chapter6 ├── Readme ├── Makefile ├── errexit.c ├── TCPclient.c └── TCPservice.c ├── chapter9 ├── Readme ├── Makefile ├── errexit.c ├── TCPclient.c └── EpollServer.c ├── chapter8 ├── Readme ├── Makefile ├── errexit.c ├── clientsock.c ├── MultiConnnectClient.c └── PoolServer.c └── README.md /chapter3/Readme: -------------------------------------------------------------------------------- 1 | Example of simple TCP and UDP server 2 | -------------------------------------------------------------------------------- /chapter5/Readme: -------------------------------------------------------------------------------- 1 | Example of multi-process TCP server 2 | -------------------------------------------------------------------------------- /chapter6/Readme: -------------------------------------------------------------------------------- 1 | Example of multi-thread TCP server 2 | -------------------------------------------------------------------------------- /chapter9/Readme: -------------------------------------------------------------------------------- 1 | Example of epoll TCP server with thread pool 2 | -------------------------------------------------------------------------------- /chapter8/Readme: -------------------------------------------------------------------------------- 1 | Example of multi-thread TCP server with thread pool 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | TCP-IP-Network-basic-examples 2 | ============================= 3 | 4 | 《TCP/IP网络编程技术基础》书上例子的测试代码。原书无配套光盘,所有代码参照书中提供内容,补充了部分书中未实现的代码,并修正原书中的错误。 5 | (TCP/IP网络编程技术基础,王雷,北京交通大学出版社) 6 | -------------------------------------------------------------------------------- /chapter5/Makefile: -------------------------------------------------------------------------------- 1 | all: TCPservice TCPclient 2 | 3 | TCPservice: TCPservice.o errexit.o 4 | gcc -o $@ $^ 5 | 6 | TCPclient: TCPclient.o errexit.o 7 | gcc -o $@ $^ 8 | 9 | %.o: %.c 10 | gcc -c -g -o $@ $< 11 | 12 | clean: 13 | rm *.o TCPservice TCPclient 14 | -------------------------------------------------------------------------------- /chapter6/Makefile: -------------------------------------------------------------------------------- 1 | all: TCPservice TCPclient 2 | 3 | TCPservice: TCPservice.o errexit.o 4 | gcc -o $@ $^ -lpthread 5 | 6 | TCPclient: TCPclient.o errexit.o 7 | gcc -o $@ $^ 8 | 9 | %.o: %.c 10 | gcc -c -g -o $@ $< 11 | 12 | clean: 13 | rm -f *.o TCPservice TCPclient 14 | -------------------------------------------------------------------------------- /chapter9/Makefile: -------------------------------------------------------------------------------- 1 | all: EpollServer TCPclient 2 | 3 | EpollServer : EpollServer.o errexit.o 4 | gcc -o $@ $^ -lpthread 5 | 6 | TCPclient : TCPclient.o errexit.o 7 | gcc -o $@ $^ 8 | 9 | %.o : %.c 10 | gcc -c -g -o $@ $< 11 | 12 | clean : 13 | rm -f *.o EpollServer TCPclient 14 | -------------------------------------------------------------------------------- /chapter3/clientsock.h: -------------------------------------------------------------------------------- 1 | #ifndef _CLIENT_SOCK_H_ 2 | #define _CLIENT_SOCK_H_ 3 | 4 | #define DEFARG(name, defval) ((#name[0]) ? (name + 0) : defval) 5 | #define clientsock(host, service, transport, sockaddr_in) \ 6 | _clientsock(host, service, transport, DEFARG(sockaddr_in, NULL)) 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /chapter3/errexit.c: -------------------------------------------------------------------------------- 1 | // va_list 2 | #include 3 | #include 4 | #include 5 | 6 | // Print error information 7 | int errexit(const char* format, ...) 8 | { 9 | va_list args; 10 | va_start(args, format); 11 | vfprintf(stderr, format, args); 12 | va_end(args); 13 | exit(1); 14 | } 15 | 16 | -------------------------------------------------------------------------------- /chapter8/Makefile: -------------------------------------------------------------------------------- 1 | all: PoolServer MultiConnnectClient 2 | 3 | PoolServer : PoolServer.o errexit.o 4 | gcc -o $@ $^ -lpthread 5 | 6 | MultiConnnectClient : MultiConnnectClient.o errexit.o clientsock.o 7 | gcc -o $@ $^ 8 | 9 | PoolServer.o : PoolServer.c 10 | gcc -c -g -o $@ $< -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast 11 | 12 | %.o : %.c 13 | gcc -c -g -o $@ $< 14 | 15 | clean : 16 | rm -f *.o PoolServer MultiConnnectClient 17 | -------------------------------------------------------------------------------- /chapter5/errexit.c: -------------------------------------------------------------------------------- 1 | // va_list 2 | #include 3 | #include 4 | #include 5 | 6 | // Print error information 7 | int errexit(const char* format, ...) 8 | { 9 | va_list args; 10 | va_start(args, format); 11 | vfprintf(stderr, format, args); 12 | va_end(args); 13 | exit(1); 14 | } 15 | 16 | // Print work information 17 | void echo(const char* format, ...) 18 | { 19 | va_list args; 20 | va_start(args, format); 21 | vfprintf(stderr, format, args); 22 | va_end(args); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /chapter6/errexit.c: -------------------------------------------------------------------------------- 1 | // va_list 2 | #include 3 | #include 4 | #include 5 | 6 | // Print error information 7 | int errexit(const char* format, ...) 8 | { 9 | va_list args; 10 | va_start(args, format); 11 | vfprintf(stderr, format, args); 12 | va_end(args); 13 | exit(1); 14 | } 15 | 16 | // Print work information 17 | void echo(const char* format, ...) 18 | { 19 | va_list args; 20 | va_start(args, format); 21 | vfprintf(stderr, format, args); 22 | va_end(args); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /chapter8/errexit.c: -------------------------------------------------------------------------------- 1 | // va_list 2 | #include 3 | #include 4 | #include 5 | 6 | // Print error information 7 | int errexit(const char* format, ...) 8 | { 9 | va_list args; 10 | va_start(args, format); 11 | vfprintf(stderr, format, args); 12 | va_end(args); 13 | exit(1); 14 | } 15 | 16 | // Print work information 17 | void echo(const char* format, ...) 18 | { 19 | va_list args; 20 | va_start(args, format); 21 | vfprintf(stderr, format, args); 22 | va_end(args); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /chapter9/errexit.c: -------------------------------------------------------------------------------- 1 | // va_list 2 | #include 3 | #include 4 | #include 5 | 6 | // Print error information 7 | int errexit(const char* format, ...) 8 | { 9 | va_list args; 10 | va_start(args, format); 11 | vfprintf(stderr, format, args); 12 | va_end(args); 13 | exit(1); 14 | } 15 | 16 | // Print work information 17 | void echo(const char* format, ...) 18 | { 19 | va_list args; 20 | va_start(args, format); 21 | vfprintf(stderr, format, args); 22 | va_end(args); 23 | } 24 | 25 | -------------------------------------------------------------------------------- /chapter3/Makefile: -------------------------------------------------------------------------------- 1 | all: TCPdaytimed TCPdaytime UDPtimed UDPtime PrintAllServByPort 2 | 3 | TCPdaytimed : TCPdaytimed.o passivesock.o errexit.o 4 | gcc -o $@ $^ 5 | 6 | TCPdaytime : TCPdaytime.o clientsock.o errexit.o 7 | gcc -o $@ $^ 8 | 9 | UDPtimed : UDPtimed.o passivesock.o errexit.o 10 | gcc -o $@ $^ 11 | 12 | UDPtime : UDPtime.o clientsock.o errexit.o 13 | gcc -o $@ $^ 14 | 15 | PrintAllServByPort: PrintAllServByPort.o 16 | gcc -o $@ $^ 17 | 18 | %.o : %.c 19 | gcc -c -g -o $@ $< 20 | 21 | clean : 22 | rm -f *.o TCPdaytimed TCPdaytime UDPtimed UDPtime PrintAllServByPort 23 | -------------------------------------------------------------------------------- /chapter3/PrintAllServByPort.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main(int argc, char *argv[]) 7 | { 8 | struct servent* server_info; 9 | int i, j; 10 | for(i=0; i < 65536; i++) 11 | { 12 | server_info = getservbyport(i, NULL); 13 | // Print server_info 14 | if(server_info != NULL) 15 | { 16 | printf("server_info->s_name: %s\n", server_info->s_name); 17 | for(j=0; server_info->s_aliases[j] != NULL; j++) 18 | { 19 | printf("server_info->s_aliases: %s\n", server_info->s_aliases[j]); 20 | } 21 | printf("server_info->s_port: %u\n", ntohs((unsigned short) server_info->s_port)); 22 | printf("server_info->s_prot: %s\n", server_info->s_proto); 23 | printf("\n"); 24 | } 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /chapter3/TCPdaytime.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | //#include 5 | // struct sockaddr_in 6 | //#include 7 | // inet_addr() 8 | //#include 9 | // system call 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | extern int errno; 17 | #define BUFFSIZE 128 18 | 19 | // Print error information 20 | int errexit(const char* format, ...); 21 | 22 | 23 | // Handle socket session 24 | void TCPdaytime(const char* host, const char* service) 25 | { 26 | char buf[BUFFSIZE + 1]; 27 | // Client-end socket descriptor, receive lenth 28 | int s, n; 29 | // Create passive TCP socket 30 | s = clientsock(host, service, "TCP", NULL); 31 | fprintf(stderr, "[CLIENT] socket %d created.\n", s); 32 | sleep(1); 33 | while((n = recv(s, buf, BUFFSIZE, 0)) > 0) 34 | { 35 | fprintf(stderr, "[CLIENT] %d data read: \n", n); 36 | // Add end of string symbol 37 | buf[n] = '\0'; 38 | // Show received data to stdout 39 | (void) fputs(buf, stderr); 40 | } 41 | fprintf(stderr, "[CLIENT] data receive finish. \n"); 42 | } 43 | 44 | // Main function 45 | int main(int argc,char* argv[]) 46 | { 47 | // was "localhost" 48 | char *host = "127.0.0.1"; 49 | // was "daytime" 50 | char *service = "10086"; 51 | switch (argc) 52 | { 53 | case 1: 54 | break; 55 | case 2: 56 | host = argv[1]; 57 | break; 58 | case 3: 59 | host = argv[1]; 60 | service = argv[2]; 61 | break; 62 | default: 63 | errexit("usage: TCPdaytime [host [port]]\n"); 64 | } 65 | TCPdaytime(host, service); 66 | } 67 | 68 | -------------------------------------------------------------------------------- /chapter3/UDPtimed.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // system socket define 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | extern int errno; 13 | 14 | // Time difference between Unit time and Internet time 15 | #define UNIXEPOCH 2208988800UL 16 | 17 | // Print error information 18 | int errexit(const char* format, ...); 19 | int passivesock(const char* service, const char* transport, int qlen); 20 | 21 | // Create passive UDP socket 22 | int passiveUDP(const char *service) 23 | { 24 | return passivesock(service, "UDP", 0); 25 | } 26 | 27 | // Main function 28 | int main(int argc, char *argv[]) 29 | { 30 | // Serice-end socket address 31 | struct sockaddr_in fsin; 32 | // Service name (port number), was "time" 33 | char *service = "10010"; 34 | // Store client request, we don't care about the real request content, 35 | char buf[1]; 36 | // and always reply the system time to client. only 1 byte buffer needed. 37 | // Service-end socket descriptor 38 | int sock; 39 | // Current time 40 | time_t now; 41 | // Service-end socket struct length 42 | unsigned int alen; 43 | switch (argc) 44 | { 45 | case 1: 46 | break; 47 | case 2: 48 | service = argv[1]; 49 | break; 50 | default: 51 | errexit("usage: UDPtimed [port]\n"); 52 | } 53 | sock = passiveUDP(service); 54 | while(1) 55 | { 56 | alen = sizeof(fsin); 57 | if (recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&fsin, &alen) < 0) 58 | errexit("recvfrom: %s \n", strerror(errno)); 59 | // Force convert time() to void type, thus it won't report warning 60 | (void) time(&now); 61 | // Convert to internet time 62 | now = htonl((unsigned long)(now + UNIXEPOCH)); 63 | (void) sendto(sock, (char*)&now, sizeof(now), 0, (struct sockaddr*)&fsin, sizeof(fsin)); 64 | } 65 | } 66 | 67 | -------------------------------------------------------------------------------- /chapter8/clientsock.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // system call 8 | #include 9 | // inet_addr() 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | extern int errno; 17 | 18 | // Create client TCP socket 19 | unsigned int portbase = 10000; 20 | int clientsock(const char* host, const char* service, const char* transport, struct sockaddr_in* fsin) 21 | { 22 | struct servent *pse; 23 | struct protoent *ppe; 24 | struct sockaddr_in *sin; 25 | if (fsin == NULL) 26 | // Service address 27 | sin = malloc(sizeof(struct sockaddr_in)); 28 | else 29 | sin = fsin; 30 | int s, type; 31 | memset(sin, 0, sizeof(*sin)); 32 | // assign sin_family 33 | sin->sin_family = AF_INET; 34 | // assign sin_addr 35 | sin->sin_addr.s_addr = inet_addr(host); 36 | //echo("[CLIENT] Debug: service host : %lu (%s) \n", (unsigned long)sin->sin_addr.s_addr, host); 37 | // assign sin_port 38 | if (pse = getservbyname(service, transport)) 39 | sin->sin_port = htons(ntohs((unsigned short)pse->s_port) + portbase); 40 | else if((sin->sin_port = htons((unsigned short)atoi(service))) == 0) 41 | errexit("can't get \"%s\" service entry\n", service); 42 | //echo("[CLIENT] Debug: service port : %u (%s) \n", sin->sin_port, service); 43 | // protocol 44 | if ((ppe = getprotobyname(transport)) == 0) 45 | errexit("can't get \"%s\" protocol entry\n", transport); 46 | if (strcmp(transport, "udp") == 0 || strcmp(transport, "UDP") == 0) 47 | type = SOCK_DGRAM; 48 | else 49 | type = SOCK_STREAM; 50 | s = socket(PF_INET, type, ppe->p_proto); 51 | if (s < 0) 52 | errexit("can't create socket: %s\n", strerror(errno)); 53 | if (type == SOCK_STREAM) 54 | { 55 | //echo("[CLIENT] Debug: connecting to service %s.. \n", service); 56 | if (connect(s, (struct sockaddr*)sin, sizeof(*sin)) != 0) 57 | errexit("can't connect to service: %s\n", strerror(errno)); 58 | //echo("[CLIENT] Debug: service %s connected. \n", service); 59 | } 60 | if (fsin == NULL) 61 | free(sin); 62 | return s; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /chapter3/TCPdaytimed.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // system call 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | extern int errno; 14 | 15 | // Print error information 16 | int errexit(const char* format, ...); 17 | int passivesock(const char* service, const char* transport, int qlen); 18 | 19 | // Create passive TCP socket 20 | int passiveTCP(const char* service) 21 | { 22 | return passivesock(service, "TCP", 1); 23 | } 24 | 25 | // Handle temporary socket session 26 | void TCPdaytimed(int fd) 27 | { 28 | // Store time string 29 | char *pts; 30 | // Current time 31 | time_t now; 32 | (void) time(&now); 33 | pts = ctime(&now); 34 | (void) send(fd, pts, strlen(pts), 0); 35 | } 36 | 37 | // Main function 38 | int main(int argc,char* argv[]) 39 | { 40 | // Service-end socket 41 | struct sockaddr_in fsin; 42 | // was "daytime" 43 | char *service = "10086"; 44 | // permanent socket descriptor and temporary socket descriptor 45 | int msock, ssock; 46 | // socket length 47 | unsigned int alen; 48 | switch (argc) 49 | { 50 | case 1: 51 | break; 52 | case 2: 53 | service = argv[1]; 54 | break; 55 | default: 56 | errexit("[SERVICE] usage: TCPdaytimed [port]\n"); 57 | } 58 | fprintf(stderr, "[SERVICE] creating passive socket..\n"); 59 | // Create passive TCP socket 60 | msock = passiveTCP(service); 61 | fprintf(stderr, "[SERVICE] passive socket %d created.\n", msock); 62 | while(1) 63 | { 64 | alen = sizeof(fsin); 65 | // connect to first client, create temporary socket 66 | fprintf(stderr, "[SERVICE] waiting for client..\n"); 67 | ssock = accept(msock, (struct sockaddr*)&fsin, &alen); 68 | if (ssock < 0) 69 | errexit("accept failed: %s\n", strerror(errno)); 70 | fprintf(stderr, "[SERVICE] temporary socket %d created.\n", ssock); 71 | // Use temporary socket interact with client 72 | TCPdaytimed(ssock); 73 | (void) close(ssock); 74 | } 75 | return 0; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /chapter3/clientsock.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // system call 8 | #include 9 | // inet_addr() 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | extern int errno; 17 | 18 | // Create client TCP socket 19 | unsigned int portbase = 10000; 20 | int clientsock(const char* host, const char* service, const char* transport, struct sockaddr_in* fsin) 21 | { 22 | struct servent *pse; 23 | struct protoent *ppe; 24 | struct sockaddr_in *sin; 25 | if (fsin == NULL) 26 | // Service address 27 | sin = malloc(sizeof(struct sockaddr_in)); 28 | else 29 | sin = fsin; 30 | int s, type; 31 | memset(sin, 0, sizeof(*sin)); 32 | // assign sin_family 33 | sin->sin_family = AF_INET; 34 | // assign sin_addr 35 | sin->sin_addr.s_addr = inet_addr(host); 36 | fprintf(stderr, "[CLIENT] service host : %lu (%s) \n", (unsigned long)sin->sin_addr.s_addr, host); 37 | // assign sin_port 38 | if (pse = getservbyname(service, transport)) 39 | sin->sin_port = htons(ntohs((unsigned short)pse->s_port) + portbase); 40 | else if((sin->sin_port = htons((unsigned short)atoi(service))) == 0) 41 | errexit("can't get \"%s\" service entry\n", service); 42 | fprintf(stderr, "[CLIENT] service port : %u (%s) \n", sin->sin_port, service); 43 | // protocol 44 | if ((ppe = getprotobyname(transport)) == 0) 45 | errexit("can't get \"%s\" protocol entry\n", transport); 46 | if (strcmp(transport, "udp") == 0 || strcmp(transport, "UDP") == 0) 47 | type = SOCK_DGRAM; 48 | else 49 | type = SOCK_STREAM; 50 | s = socket(PF_INET, type, ppe->p_proto); 51 | if (s < 0) 52 | errexit("can't create socket: %s\n", strerror(errno)); 53 | if (type == SOCK_STREAM) 54 | { 55 | fprintf(stderr, "[CLIENT] connecting to service %s.. \n", service); 56 | if (connect(s, (struct sockaddr*)sin, sizeof(*sin)) != 0) 57 | errexit("can't connect to service: %s\n", strerror(errno)); 58 | fprintf(stderr, "[CLIENT] service %s connected. \n", service); 59 | } 60 | if (fsin == NULL) 61 | free(sin); 62 | return s; 63 | } 64 | 65 | -------------------------------------------------------------------------------- /chapter3/UDPtime.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // system socket define 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // ctime(), without this headfile, we'll get a warning while compile and a segment fault when running 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | // unix system call, e.g. write(), read() 14 | #include 15 | 16 | // Time difference between Unit time and Internet time 17 | #define UNIXEPOCH 2208988800UL 18 | #define BUFSIZE 64 19 | #define MSG "what time is it ?\n" 20 | extern int errno; 21 | 22 | // Print error information 23 | int errexit(const char* format, ...); 24 | 25 | int connectUDP(const char *host, const char *service, struct sockaddr_in* sin) 26 | { 27 | return clientsock(host, service, "UDP", sin); 28 | } 29 | 30 | // Main function 31 | int main(int argc, char *argv[]) 32 | { 33 | // Service IP, was "localhost" 34 | char *host = "127.0.0.1"; 35 | // Sercice name/port, was "time" 36 | char *service = "10010"; 37 | // Store replied time 38 | time_t now; 39 | // Socket descriptor and read data length 40 | int s, n; 41 | switch(argc) 42 | { 43 | case 1: 44 | break; 45 | case 2: 46 | host = argv[1]; 47 | break; 48 | case 3: 49 | host = argv[1]; 50 | service = argv[2]; 51 | break; 52 | default: 53 | errexit("usage: UDPtime [host [port]]\n"); 54 | } 55 | 56 | // Service-end socket address 57 | struct sockaddr_in sin; 58 | // conncet to service 59 | s = connectUDP(host, service, &sin); 60 | 61 | fprintf(stderr, "[CLIENT] sending message to service..\n"); 62 | // write to service by socket 63 | (void) sendto(s, MSG, strlen(MSG), 0, (struct sockaddr*)&sin, sizeof(sin)); 64 | 65 | fprintf(stderr, "[CLIENT] message sent to service, waiting for respond..\n"); 66 | // wait and read a package from socket 67 | int recvlen = sizeof(sin); 68 | n = recvfrom(s, (char*)&now, sizeof(now), 0, (struct sockaddr*)&sin, &recvlen); 69 | if (n < 0) 70 | errexit("read failed: %s\n", strerror(errno)); 71 | 72 | // Convert to host byte order 73 | now = ntohl((unsigned long)now); 74 | // Convert to host time 75 | now -= UNIXEPOCH; 76 | fprintf(stderr, "[CLIENT] now time is : %s\n", ctime(&now)); 77 | 78 | return 0; 79 | } 80 | 81 | -------------------------------------------------------------------------------- /chapter3/passivesock.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // system socket define 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // Network related functions, e.g. gethostbyname() 8 | #include 9 | // va_list 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | extern int errno; 16 | 17 | // Allow test multi-service on the machine using different port 18 | unsigned int portbase = 1024; 19 | int passivesock(const char* service, const char* transport, int qlen) 20 | { 21 | // Store service entry return from getservbyname() 22 | struct servent *pse; 23 | // Store protocol entry return from getprotobyname() 24 | struct protoent *ppe; 25 | // Service-end socket 26 | struct sockaddr_in sin; 27 | // Service-end socket descriptor and service type 28 | int s, type; 29 | memset(&sin, 0, sizeof(sin)); 30 | // TCP/IP suite 31 | sin.sin_family = AF_INET; 32 | // Use any local IP, need translate to internet byte order 33 | sin.sin_addr.s_addr = INADDR_ANY; 34 | // Get port number 35 | // service is service name 36 | if (pse = getservbyname(service, transport)) 37 | sin.sin_port = htons(ntohs((unsigned short)pse->s_port) + portbase); 38 | // service is port number 39 | else if((sin.sin_port = htons((unsigned short)atoi(service))) == 0) 40 | errexit("can't get \"%s\" service entry\n", service); 41 | // Get protocol number 42 | if ((ppe = getprotobyname(transport)) == 0) 43 | errexit("can't get \"%s\" protocol entry\n", transport); 44 | // Tranport type 45 | if (strcmp(transport, "udp") == 0 || strcmp(transport, "UDP") == 0) 46 | type = SOCK_DGRAM; 47 | else 48 | type = SOCK_STREAM; 49 | fprintf(stderr, "[SERVICE] transport: %s, protocol: %d, port: %u, type: %d\n", \ 50 | transport, ppe->p_proto, sin.sin_port, type); 51 | // Create socket 52 | s = socket(PF_INET, type, ppe->p_proto); 53 | if (s < 0) 54 | errexit("can't create socket: %s \n", strerror(errno)); 55 | // Bind socket to service-end address 56 | if (bind(s, (struct sockaddr*)&sin, sizeof(sin)) < 0) 57 | errexit("can't bind to %s port: %s \n", service, strerror(errno)); 58 | // For TCP socket, convert it to passive mode 59 | if (type == SOCK_STREAM && listen(s, qlen) < 0) 60 | errexit("can't listen on %s port: %s \n", service, strerror(errno)); 61 | return s; 62 | } 63 | 64 | -------------------------------------------------------------------------------- /chapter8/MultiConnnectClient.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAXLINE 10 11 | #define MAXBTYE 4096 12 | 13 | int clientsock(const char* host, const char* service, const char* transport, struct sockaddr_in* fsin); 14 | ssize_t readn(int fd, void* vptr, size_t n); 15 | 16 | int connectTCP(const char* host, const char* port) 17 | { 18 | return clientsock(host, port, "TCP", NULL); 19 | } 20 | 21 | int main(int argc,char* argv[]) 22 | { 23 | int i, j, fd; 24 | pid_t pid; 25 | ssize_t n; 26 | char request[MAXLINE], reply[MAXBTYE]; 27 | char *hostname = "127.0.0.1"; 28 | char *port = "10011"; 29 | int nchildren = 10; 30 | int nloops = 500; 31 | int nbytes = 4000; 32 | if (argc != 6) 33 | echo("usage : client <#children> <#loops/child> <#bytes/request>\n"); 34 | else 35 | { 36 | hostname = argv[1]; 37 | port = argv[2]; 38 | nchildren = atoi(argv[3]); 39 | nloops = atoi(argv[4]); 40 | nbytes = atoi(argv[5]); 41 | } 42 | snprintf(request, sizeof(request), "%d", nbytes); 43 | for (i = 0; i < nchildren; ++i) 44 | { 45 | if ((pid = fork()) == 0) 46 | { 47 | for (j = 0; j < nloops; ++j) 48 | { 49 | fd = connectTCP(hostname, port); 50 | //echo("[CLIENT] Debug: sending request %d bytes.\n", nbytes); 51 | send(fd, request, strlen(request), 0); 52 | //echo("[CLIENT] Debug: request sended.\n"); 53 | if ((n = readn(fd, reply, nbytes)) != nbytes) 54 | echo("[CLIENT] Error: request %d bytes, received %d bytes\n", nbytes, n); 55 | //echo("[CLIENT] Debug: received %d bytes reply.\n", n); 56 | close(fd); 57 | } 58 | echo("[CLIENT] child %d done.\n", i); 59 | exit(0); 60 | } 61 | while(wait(NULL) > 0) 62 | ; 63 | if (errno != ECHILD) 64 | errexit("[CLIENT] wait failed.\n"); 65 | } 66 | return 0; 67 | } 68 | 69 | ssize_t readn(int fd, void* vptr, size_t n) 70 | { 71 | size_t nleft; 72 | ssize_t nread; 73 | char* ptr; 74 | ptr = vptr; 75 | nleft = n; 76 | // read as much as possible each time, until reach n bytes 77 | while (nleft > 0) 78 | { 79 | if ((nread = recv(fd, ptr, nleft, 0)) < 0) 80 | { 81 | if (errno == EINTR) 82 | nread = 0; 83 | else 84 | return -1; 85 | } 86 | nleft -= nread; 87 | ptr += nread; 88 | } 89 | if (n - nleft < 0) 90 | echo("[CLIENT] Error: readn error.\n"); 91 | return (n - nleft); 92 | } 93 | 94 | -------------------------------------------------------------------------------- /chapter5/TCPclient.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // inet_ntoa() 8 | #include 9 | // system call 10 | #include 11 | // struct hostent and gethostbyname() 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | extern int errno; 18 | #define BUFFSIZE 128 19 | #define PORT 10088 20 | 21 | // Print error information 22 | int errexit(const char* format, ...); 23 | // Print work information 24 | int echo(const char* format, ...); 25 | 26 | char* getMessage(char* buffer, int len, FILE* fp) 27 | { 28 | echo(">> Input message: "); 29 | return fgets(buffer, len, fp); 30 | } 31 | 32 | // Handle socket session 33 | void process(FILE *fp, int sockfd) 34 | { 35 | char sendline[BUFFSIZE], recvline[BUFFSIZE]; 36 | int numbytes; 37 | echo(">> Input name: "); 38 | if (fgets(sendline, BUFFSIZE, fp) == NULL) 39 | { 40 | echo("[CLIENT] exit.\n"); 41 | return; 42 | } 43 | send(sockfd, sendline, strlen(sendline), 0); 44 | while (getMessage(sendline, BUFFSIZE, fp) != NULL) 45 | { 46 | send(sockfd, sendline, strlen(sendline), 0); 47 | if ((numbytes = recv(sockfd, recvline, BUFFSIZE, 0)) == 0) 48 | { 49 | echo("[CLIENT] server terminated.\n"); 50 | return; 51 | } 52 | recvline[numbytes] = '\0'; 53 | echo("Received: %s\n", recvline); 54 | } 55 | echo("[CLIENT] exit.\n"); 56 | } 57 | 58 | // Main function 59 | int main(int argc,char* argv[]) 60 | { 61 | int sock; 62 | struct hostent *hent; 63 | struct sockaddr_in server; 64 | char *host = "127.0.0.1"; 65 | unsigned short port = PORT; 66 | switch (argc) 67 | { 68 | case 1: 69 | break; 70 | case 2: 71 | host = argv[1]; 72 | break; 73 | case 3: 74 | host = argv[1]; 75 | port = atoi(argv[2]); 76 | break; 77 | default: 78 | errexit("usage: %s [host [port]]\n", argv[0]); 79 | } 80 | // convert decimal IP to binary IP 81 | if ((hent = gethostbyname(host)) == NULL) 82 | errexit("gethostbyname failed.\n"); 83 | if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) 84 | errexit("create socket failed: %s\n", strerror(errno)); 85 | 86 | bzero(&server, sizeof(server)); 87 | server.sin_family = AF_INET; 88 | server.sin_port = htons(port); 89 | server.sin_addr = *((struct in_addr*)hent->h_addr); 90 | echo("[CLIENT] server addr: %s, port: %u\n", inet_ntoa(server.sin_addr), ntohs(server.sin_port)); 91 | 92 | if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) 93 | errexit("connect to server failed: %s\n", strerror(errno)); 94 | 95 | echo("[CLIENT] connected to server %s\n", inet_ntoa(server.sin_addr)); 96 | // Send request to server 97 | process(stdin, sock); 98 | close(sock); 99 | } 100 | 101 | -------------------------------------------------------------------------------- /chapter6/TCPclient.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // inet_ntoa() 8 | #include 9 | // system call 10 | #include 11 | // struct hostent and gethostbyname() 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | extern int errno; 18 | #define BUFFSIZE 128 19 | #define PORT 10087 20 | 21 | // Print error information 22 | int errexit(const char* format, ...); 23 | // Print work information 24 | int echo(const char* format, ...); 25 | 26 | char* getMessage(char* buffer, int len, FILE* fp) 27 | { 28 | echo(">> Input message: "); 29 | return fgets(buffer, len, fp); 30 | } 31 | 32 | // Handle socket session 33 | void process(FILE *fp, int sockfd) 34 | { 35 | char sendline[BUFFSIZE], recvline[BUFFSIZE]; 36 | int numbytes; 37 | echo(">> Input name: "); 38 | if (fgets(sendline, BUFFSIZE, fp) == NULL) 39 | { 40 | echo("[CLIENT] exit.\n"); 41 | return; 42 | } 43 | send(sockfd, sendline, strlen(sendline), 0); 44 | while (getMessage(sendline, BUFFSIZE, fp) != NULL) 45 | { 46 | send(sockfd, sendline, strlen(sendline), 0); 47 | if ((numbytes = recv(sockfd, recvline, BUFFSIZE, 0)) == 0) 48 | { 49 | echo("[CLIENT] server terminated.\n"); 50 | return; 51 | } 52 | recvline[numbytes] = '\0'; 53 | echo("Received: %s\n", recvline); 54 | } 55 | echo("[CLIENT] exit.\n"); 56 | } 57 | 58 | // Main function 59 | int main(int argc,char* argv[]) 60 | { 61 | int sock; 62 | struct hostent *hent; 63 | struct sockaddr_in server; 64 | char *host = "127.0.0.1"; 65 | unsigned short port = PORT; 66 | switch (argc) 67 | { 68 | case 1: 69 | break; 70 | case 2: 71 | host = argv[1]; 72 | break; 73 | case 3: 74 | host = argv[1]; 75 | port = atoi(argv[2]); 76 | break; 77 | default: 78 | errexit("usage: %s [host [port]]\n", argv[0]); 79 | } 80 | // convert decimal IP to binary IP 81 | if ((hent = gethostbyname(host)) == NULL) 82 | errexit("gethostbyname failed.\n"); 83 | if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) 84 | errexit("create socket failed: %s\n", strerror(errno)); 85 | 86 | bzero(&server, sizeof(server)); 87 | server.sin_family = AF_INET; 88 | server.sin_port = htons(port); 89 | server.sin_addr = *((struct in_addr*)hent->h_addr); 90 | echo("[CLIENT] server addr: %s, port: %u\n", inet_ntoa(server.sin_addr), ntohs(server.sin_port)); 91 | 92 | if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) 93 | errexit("connect to server failed: %s\n", strerror(errno)); 94 | 95 | echo("[CLIENT] connected to server %s\n", inet_ntoa(server.sin_addr)); 96 | // Send request to server 97 | process(stdin, sock); 98 | close(sock); 99 | } 100 | 101 | -------------------------------------------------------------------------------- /chapter9/TCPclient.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // inet_ntoa() 8 | #include 9 | // system call 10 | #include 11 | // struct hostent and gethostbyname() 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | extern int errno; 18 | #define BUFFSIZE 128 19 | #define PORT 10012 20 | 21 | // Print error information 22 | int errexit(const char* format, ...); 23 | // Print work information 24 | int echo(const char* format, ...); 25 | 26 | char* getMessage(char* buffer, int len, FILE* fp) 27 | { 28 | echo(">> Input message: "); 29 | return fgets(buffer, len, fp); 30 | } 31 | 32 | int recvFromServer(int sockfd, char* buf, int buf_size) 33 | { 34 | int n, offset = 0; 35 | errno = 0; 36 | while (buf_size - offset > 0 && 37 | (n = recv(sockfd, buf + offset, buf_size - offset, MSG_DONTWAIT)) > 0) 38 | { 39 | offset += n; 40 | } 41 | if (offset == 0 && errno == EAGAIN) 42 | { 43 | echo("[CLIENT] no message received.\n"); 44 | return -1; 45 | } 46 | else 47 | { 48 | return offset; 49 | } 50 | } 51 | 52 | // Handle socket session 53 | void process(FILE *fp, int sockfd) 54 | { 55 | char sendline[BUFFSIZE], recvline[BUFFSIZE]; 56 | int numbytes; 57 | while (getMessage(sendline, BUFFSIZE, fp) != NULL) 58 | { 59 | send(sockfd, sendline, strlen(sendline), 0); 60 | sleep(1); 61 | if ((numbytes = recvFromServer(sockfd, recvline, BUFFSIZE)) == 0) 62 | { 63 | echo("[CLIENT] server terminated.\n"); 64 | return; 65 | } 66 | else if (numbytes > 0) 67 | { 68 | recvline[numbytes] = '\0'; 69 | echo("Received: %s\n", recvline); 70 | } 71 | } 72 | echo("[CLIENT] exit.\n"); 73 | } 74 | 75 | // Main function 76 | int main(int argc,char* argv[]) 77 | { 78 | int sock; 79 | struct hostent *hent; 80 | struct sockaddr_in server; 81 | char *host = "127.0.0.1"; 82 | unsigned short port = PORT; 83 | switch (argc) 84 | { 85 | case 1: 86 | break; 87 | case 2: 88 | host = argv[1]; 89 | break; 90 | case 3: 91 | host = argv[1]; 92 | port = atoi(argv[2]); 93 | break; 94 | default: 95 | errexit("usage: %s [host [port]]\n", argv[0]); 96 | } 97 | // convert decimal IP to binary IP 98 | if ((hent = gethostbyname(host)) == NULL) 99 | errexit("gethostbyname failed.\n"); 100 | if ((sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) 101 | errexit("create socket failed: %s\n", strerror(errno)); 102 | 103 | bzero(&server, sizeof(server)); 104 | server.sin_family = AF_INET; 105 | server.sin_port = htons(port); 106 | server.sin_addr = *((struct in_addr*)hent->h_addr); 107 | echo("[CLIENT] server addr: %s, port: %u\n", inet_ntoa(server.sin_addr), ntohs(server.sin_port)); 108 | 109 | if (connect(sock, (struct sockaddr*)&server, sizeof(server)) < 0) 110 | errexit("connect to server failed: %s\n", strerror(errno)); 111 | 112 | echo("[CLIENT] connected to server %s\n", inet_ntoa(server.sin_addr)); 113 | // Send request to server 114 | process(stdin, sock); 115 | close(sock); 116 | } 117 | 118 | -------------------------------------------------------------------------------- /chapter5/TCPservice.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // inet_addr() 8 | #include 9 | // system call 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | extern int errno; 18 | 19 | #define PORT 10088 20 | #define QLEN 10 21 | #define BUFSIZE 1024 22 | 23 | // Print error information 24 | int errexit(const char* format, ...); 25 | // Print work information 26 | int echo(const char* format, ...); 27 | 28 | // SIGCHLD handler 29 | void sig_child(int sig) 30 | { 31 | pid_t pid; 32 | int stat; 33 | while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) 34 | echo("[SERVICE] Child %d terminated\n", pid); 35 | return; 36 | } 37 | 38 | // Handle request from client 39 | void processClient(int connectfd, struct sockaddr_in client) 40 | { 41 | int num, i; 42 | char recvbuf[BUFSIZE], sendbuf[BUFSIZE], clientName[BUFSIZE]; 43 | int len; 44 | echo("[SERVICE] Accept a connect from %s.\n", inet_ntoa(client.sin_addr)); 45 | num = recv(connectfd, clientName, BUFSIZE, 0); 46 | // Receive nothing, close socket 47 | if (num == 0) 48 | { 49 | close(connectfd); 50 | echo("[SERVICE] Client disconnected.\n"); 51 | return; 52 | } 53 | // [num -1] to cut of the last '\n' received from client 54 | clientName[num - 1] = '\0'; 55 | echo("[SERVICE] Client name is: %s.\n", clientName); 56 | while (num = recv(connectfd, recvbuf, BUFSIZE, 0)) 57 | { 58 | // receive every thing, end with '\n' 59 | recvbuf[num] = '\0'; 60 | echo("[SERVICE] Received client (%s) message: %s", clientName, recvbuf); 61 | // Revert the char order 62 | for (i = 0; i < num - 1; i++) 63 | { 64 | // subtract 2 to leave along the '\0' and '\n' 65 | sendbuf[i] = recvbuf[num - i - 2]; 66 | } 67 | // The real data have only [num - 1] length 68 | sendbuf[num - 1] = '\0'; 69 | len = strlen(sendbuf); 70 | // Send respond to client 71 | send(connectfd, sendbuf, len, 0); 72 | } 73 | close(connectfd); 74 | } 75 | 76 | int passivesock(struct sockaddr_in* server) 77 | { 78 | int listenfd; 79 | if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 80 | errexit("can't create socket: %s \n", strerror(errno)); 81 | 82 | // Allow socket reuse local addr and port 83 | int opt = SO_REUSEADDR; 84 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 85 | 86 | // Initialize socket addr 87 | bzero(server, sizeof(*server)); 88 | server->sin_family = AF_INET; 89 | server->sin_port = htons((unsigned short)PORT); 90 | // here htonl() is optional 91 | server->sin_addr.s_addr = htonl(INADDR_ANY); 92 | 93 | // Bind socket to service-end address 94 | if (bind(listenfd, (struct sockaddr*)server, sizeof(*server)) < 0) 95 | errexit("can't bind to %s port: %s \n", PORT, strerror(errno)); 96 | // For TCP socket, convert it to passive mode 97 | if (listen(listenfd, QLEN) < 0) 98 | errexit("can't listen on %s port: %s \n", PORT, strerror(errno)); 99 | 100 | return listenfd; 101 | } 102 | 103 | // Main function 104 | int main(int argc,char* argv[]) 105 | { 106 | // Main socket and servant socket 107 | int listenfd, connectfd; 108 | pid_t pid; 109 | // Service-end socket addr 110 | struct sockaddr_in server; 111 | // Client-end socket addr 112 | struct sockaddr_in client; 113 | socklen_t ssize = sizeof(struct sockaddr_in); 114 | 115 | echo("[SERVICE] creating passive socket..\n"); 116 | listenfd = passivesock(&server); 117 | echo("[SERVICE] passive socket %d created.\n", listenfd); 118 | 119 | // Install signal hander 120 | signal(SIGCHLD, sig_child); 121 | 122 | while(1) 123 | { 124 | // connect to first client, create temporary socket 125 | echo("[SERVICE] waiting for client..\n"); 126 | if ((connectfd = accept(listenfd, (struct sockaddr*)&client, &ssize)) < 0) 127 | errexit("accept failed: %s\n", strerror(errno)); 128 | echo("[SERVICE] servant socket %d created.\n", connectfd); 129 | pid = fork(); 130 | // Parent process 131 | if (pid > 0) 132 | { 133 | (void) close(connectfd); 134 | continue; 135 | } 136 | // Child process 137 | else if (pid == 0) 138 | { 139 | (void) close(listenfd); 140 | // Use servant socket interact with client 141 | processClient(connectfd, client); 142 | exit(0); 143 | } 144 | else 145 | { 146 | errexit("fork failed: %s\n", strerror(errno)); 147 | } 148 | } 149 | close(listenfd); 150 | return 0; 151 | } 152 | 153 | -------------------------------------------------------------------------------- /chapter6/TCPservice.c: -------------------------------------------------------------------------------- 1 | // system types 2 | #include 3 | // socket API 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // inet_addr() 8 | #include 9 | // system call 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | extern int errno; 17 | 18 | #define PORT 10087 19 | #define QLEN 10 20 | #define BUFSIZE 1024 21 | 22 | // Print error information 23 | int errexit(const char* format, ...); 24 | // Print work information 25 | int echo(const char* format, ...); 26 | 27 | // Client info struct 28 | typedef struct ARG { 29 | int connectfd; 30 | struct sockaddr_in client; 31 | }ARG; 32 | 33 | // Handle request from client 34 | void processClient(int connectfd, struct sockaddr_in client) 35 | { 36 | int num, i; 37 | char recvbuf[BUFSIZE], sendbuf[BUFSIZE], clientName[BUFSIZE]; 38 | int len; 39 | echo("[SERVICE] Accept a connect from %s.\n", inet_ntoa(client.sin_addr)); 40 | num = recv(connectfd, clientName, BUFSIZE, 0); 41 | // Receive nothing, close socket 42 | if (num == 0) 43 | { 44 | close(connectfd); 45 | echo("[SERVICE] Client disconnected.\n"); 46 | return; 47 | } 48 | // [num -1] to cut of the last '\n' received from client 49 | clientName[num - 1] = '\0'; 50 | echo("[SERVICE] Client name is: %s.\n", clientName); 51 | while (num = recv(connectfd, recvbuf, BUFSIZE, 0)) 52 | { 53 | // receive every thing, end with '\n' 54 | recvbuf[num] = '\0'; 55 | echo("[SERVICE] Received client (%s) message: %s", clientName, recvbuf); 56 | // Revert the char order 57 | for (i = 0; i < num - 1; i++) 58 | { 59 | // subtract 2 to leave along the '\0' and '\n' 60 | sendbuf[i] = recvbuf[num - i - 2]; 61 | } 62 | // The real data have only [num - 1] length 63 | sendbuf[num - 1] = '\0'; 64 | len = strlen(sendbuf); 65 | // Send respond to client 66 | send(connectfd, sendbuf, len, 0); 67 | } 68 | close(connectfd); 69 | } 70 | 71 | void* startRoutine(void* arg) 72 | { 73 | ARG* info = (ARG*)arg; 74 | processClient(info->connectfd, info->client); 75 | // Release arg 76 | free(info); 77 | echo("[SERVICE] thread %d terminated\n", pthread_self()); 78 | pthread_exit(NULL); 79 | } 80 | 81 | int passivesock(struct sockaddr_in* server) 82 | { 83 | int listenfd; 84 | if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) 85 | errexit("can't create socket: %s \n", strerror(errno)); 86 | 87 | // Allow socket reuse local addr and port 88 | int opt = SO_REUSEADDR; 89 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); 90 | 91 | // Initialize socket addr 92 | bzero(server, sizeof(*server)); 93 | server->sin_family = AF_INET; 94 | server->sin_port = htons((unsigned short)PORT); 95 | // here htonl() is optional 96 | server->sin_addr.s_addr = htonl(INADDR_ANY); 97 | 98 | // Bind socket to service-end address 99 | if (bind(listenfd, (struct sockaddr*)server, sizeof(*server)) < 0) 100 | errexit("can't bind to %s port: %s \n", PORT, strerror(errno)); 101 | // For TCP socket, convert it to passive mode 102 | if (listen(listenfd, QLEN) < 0) 103 | errexit("can't listen on %s port: %s \n", PORT, strerror(errno)); 104 | 105 | return listenfd; 106 | } 107 | 108 | // Main function 109 | int main(int argc,char* argv[]) 110 | { 111 | // Main socket and servant socket 112 | int listenfd, connectfd; 113 | pthread_t thread; 114 | ARG *arg; 115 | // Service-end socket addr 116 | struct sockaddr_in server; 117 | // Client-end socket addr 118 | struct sockaddr_in client; 119 | socklen_t ssize = sizeof(struct sockaddr_in); 120 | 121 | echo("[SERVICE] creating passive socket..\n"); 122 | listenfd = passivesock(&server); 123 | echo("[SERVICE] passive socket %d created.\n", listenfd); 124 | 125 | while(1) 126 | { 127 | // connect to first client, create temporary socket 128 | echo("[SERVICE] waiting for client..\n"); 129 | if ((connectfd = accept(listenfd, (struct sockaddr*)&client, &ssize)) < 0) 130 | errexit("accept failed: %s\n", strerror(errno)); 131 | echo("[SERVICE] servant socket %d created.\n", connectfd); 132 | // Initial client information struct 133 | arg = malloc(sizeof(ARG)); 134 | arg->connectfd = connectfd; 135 | //NOTE: threads sharing the memory, client variable cannot reuse 136 | // deep copy 137 | memcpy(&arg->client, &client, sizeof(client)); 138 | 139 | if (pthread_create(&thread, NULL, startRoutine, (void*)arg)) 140 | errexit("create thread failed: %s\n", strerror(errno)); 141 | } 142 | close(listenfd); 143 | return 0; 144 | } 145 | 146 | -------------------------------------------------------------------------------- /chapter8/PoolServer.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | // struct sockaddr_in 12 | #include 13 | #include 14 | 15 | #define PORT 10011 16 | #define LISTENQ 1024 17 | // Max received message bytes 18 | #define MAXLINE 10 19 | // Max reply message bytes 20 | #define MAXBTYE 4096 21 | // Max accepted client at the same time 22 | #define MAXCLIENT 32 23 | 24 | typedef struct 25 | { 26 | // thread id 27 | pthread_t thread_tid; 28 | // connected client count 29 | long thread_count; 30 | } Thread; 31 | 32 | // thread array (thread pool) 33 | Thread *tptr; 34 | // client socket descriptor array 35 | int clifd[MAXCLIENT], iget, iput; 36 | // socket descriptor in main thread 37 | int listenfd; 38 | // total thread count 39 | int nthreads; 40 | pthread_mutex_t clifd_mutex = PTHREAD_MUTEX_INITIALIZER; 41 | pthread_cond_t clifd_cond = PTHREAD_COND_INITIALIZER; 42 | 43 | // print user and system cpu time 44 | void pr_cpu_time(void); 45 | // handle connection 46 | void web_child(int); 47 | // SIGINT handler 48 | void sig_int(int); 49 | // thread main function 50 | void* thread_main(void*); 51 | // create sub-thread in thread pool 52 | void thread_make(int); 53 | // write buf content to socket 54 | ssize_t written(int, const void*, size_t); 55 | 56 | int main(int argc,char* argv[]) 57 | { 58 | int i, navail, maxfd, nsel, connfd, rc; 59 | socklen_t clilen; 60 | // host info of server 61 | struct sockaddr_in servaddr; 62 | // host info of client 63 | struct sockaddr_in cliaddr; 64 | // value to enable SOL_SOCKET 65 | const int ON = 1; 66 | 67 | // initialize server socket 68 | listenfd = socket(PF_INET, SOCK_STREAM, 0); 69 | bzero(&servaddr, sizeof(servaddr)); 70 | servaddr.sin_family = AF_INET; 71 | servaddr.sin_addr.s_addr = htonl(INADDR_ANY); 72 | servaddr.sin_port = htons(PORT); 73 | setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &ON, sizeof(ON)); 74 | bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)); 75 | listen(listenfd, LISTENQ); 76 | 77 | // initialize thread pool 78 | // number of threads in the pool 79 | nthreads = 10; 80 | tptr = calloc(nthreads, sizeof(Thread)); 81 | iget = iput = 0; 82 | for (i = 0; i < nthreads; ++i) 83 | { 84 | thread_make(i); 85 | } 86 | 87 | // register signal SIGINT 88 | signal(SIGINT, sig_int); 89 | 90 | // wait for client connection 91 | for (;;) 92 | { 93 | connfd = accept(listenfd, (struct sockaddr*)&cliaddr, &clilen); 94 | echo("[SERVICE] accept a connect from %s.\n", inet_ntoa(cliaddr.sin_addr)); 95 | // protect clifd[] and iput/iget 96 | pthread_mutex_lock(&clifd_mutex); 97 | //echo("[SERVER] get lock, thread = [main]\n"); 98 | // iput point to next idle position 99 | clifd[iput] = connfd; 100 | if (++iput == MAXCLIENT) 101 | iput = 0; 102 | // the queue overflowed 103 | if (iput == iget) 104 | errexit("[SERVER] Error: too much clients !"); 105 | pthread_cond_signal(&clifd_cond); 106 | pthread_mutex_unlock(&clifd_mutex); 107 | } 108 | 109 | return 0; 110 | } 111 | 112 | void thread_make(int i) 113 | { 114 | pthread_create(&tptr[i].thread_tid, NULL, &thread_main, (void*)i); 115 | } 116 | 117 | void* thread_main(void* arg) 118 | { 119 | int connfd; 120 | int t_id = (int)arg; 121 | echo("[SERVER] thread %d strating..\n", t_id); 122 | for (;;) 123 | { 124 | pthread_mutex_lock(&clifd_mutex); 125 | //echo("[SERVER] get lock, thread = [%d]\n", t_id); 126 | // the connection queue is empty 127 | while (iget == iput) 128 | pthread_cond_wait(&clifd_cond, &clifd_mutex); 129 | //echo("[SERVER] thread [%d] wake up.\n", t_id); 130 | connfd = clifd[iget]; 131 | if (++iget == MAXCLIENT) 132 | iget = 0; 133 | pthread_mutex_unlock(&clifd_mutex); 134 | 135 | // increase task count 136 | tptr[t_id].thread_count++; 137 | // handle the request 138 | web_child(connfd); 139 | // close this connection 140 | close(connfd); 141 | } 142 | } 143 | 144 | void sig_int(int signo) 145 | { 146 | int i; 147 | pr_cpu_time(); 148 | for (i = 0; i < nthreads; ++i) 149 | { 150 | echo("[SERVER] thread %d, %ld connections\n", i, tptr[i].thread_count); 151 | } 152 | exit(0); 153 | } 154 | 155 | void pr_cpu_time(void) 156 | { 157 | double user, sys; 158 | struct rusage myusage, childusage; 159 | if (getrusage(RUSAGE_SELF, &myusage) < 0) 160 | { 161 | echo("[SERVER] Error: getrusage(RUSAGE_SELF) failed, %s\n", strerror(errno)); 162 | return; 163 | } 164 | if (getrusage(RUSAGE_CHILDREN, &childusage) < 0) 165 | { 166 | echo("[SERVER] Error: getrusage(RUSAGE_CHILDREN) failed, %s\n", strerror(errno)); 167 | return; 168 | } 169 | user = (double)myusage.ru_utime.tv_sec + myusage.ru_utime.tv_usec/1000000.0; 170 | user += (double)childusage.ru_utime.tv_sec + childusage.ru_utime.tv_usec/1000000.0; 171 | sys = (double)myusage.ru_stime.tv_sec + myusage.ru_stime.tv_usec/1000000.0; 172 | sys += (double)childusage.ru_stime.tv_sec + childusage.ru_stime.tv_usec/1000000.0; 173 | // show total user time and system time 174 | echo("[SERVER] user time=%g, sys time=%g\n", user, sys); 175 | } 176 | 177 | void web_child(int sockfd) 178 | { 179 | int ntowrite, n; 180 | ssize_t nread; 181 | // result array contain random charactors 182 | char line[MAXLINE], result[MAXBTYE]; 183 | for (;;) 184 | { 185 | if ((nread = recv(sockfd, line, MAXLINE, 0)) == 0) 186 | { 187 | echo("[SERVER] connection closed by client.\n"); 188 | return; 189 | } 190 | echo("[SERVER] received from client [%s].\n", line); 191 | ntowrite = atol(line); 192 | if ((ntowrite <= 0) || (ntowrite > MAXBTYE)) 193 | { 194 | echo("[SERVER] client request for %d bytes.\n", ntowrite); 195 | return; 196 | } 197 | //echo("[SERVER] send to client [%s].\n", result); 198 | if ((n = written(sockfd, result, ntowrite)) != ntowrite) 199 | echo("[SERVER] Error: expect write %d bytes, actually write %d bytes.\n", ntowrite, n); 200 | //echo("[SERVER] Debug: wrote %d bytes to client.\n", n); 201 | } 202 | } 203 | 204 | ssize_t written(int fd, const void* vptr, size_t n) 205 | { 206 | size_t nleft; 207 | ssize_t nwritten; 208 | const char* ptr; 209 | ptr = vptr; 210 | nleft = n; 211 | while (nleft > 0) 212 | { 213 | // send as much as possible each time from buf, until reach n bytes 214 | if ((nwritten = send(fd, ptr, nleft, 0)) <= 0) 215 | { 216 | if (nwritten < 0 && errno == EINTR) 217 | nwritten = 0; 218 | else 219 | return -1; 220 | } 221 | nleft -= nwritten; 222 | ptr += nwritten; 223 | } 224 | return (n - nleft); 225 | } 226 | 227 | -------------------------------------------------------------------------------- /chapter9/EpollServer.c: -------------------------------------------------------------------------------- 1 | // socket interface 2 | #include 3 | // epoll interface 4 | #include 5 | // struct sockaddr_in 6 | #include 7 | // IP addr convertion 8 | #include 9 | // File descriptor controller 10 | #include 11 | #include 12 | #include 13 | #include 14 | // bzero() 15 | #include 16 | // malloc(), free() 17 | #include 18 | #include 19 | extern int errno; 20 | 21 | // maximum received data byte 22 | #define MAXBTYE 10 23 | #define OPEN_MAX 100 24 | #define LISTENQ 20 25 | #define SERV_PORT 10012 26 | #define INFTIM 1000 27 | #define LOCAL_ADDR "127.0.0.1" 28 | #define TIMEOUT 500 29 | 30 | // task item in thread pool 31 | struct task 32 | { 33 | // file descriptor or user_data 34 | epoll_data_t data; 35 | // next task 36 | struct task* next; 37 | }; 38 | 39 | // for data transporting 40 | struct user_data 41 | { 42 | int fd; 43 | // real received data size 44 | unsigned int n_size; 45 | // content received 46 | char line[MAXBTYE]; 47 | }; 48 | 49 | void *readtask(void *args); 50 | void *writetask(void *args); 51 | 52 | // epoll descriptor from epoll_create() 53 | int epfd; 54 | // register epoll_ctl() 55 | struct epoll_event ev; 56 | // store queued events from epoll_wait() 57 | struct epoll_event events[LISTENQ]; 58 | // mutex lock to protect readhead/readtail 59 | pthread_mutex_t r_mutex; 60 | pthread_cond_t r_condl; 61 | // mutex lock to protect writehead/writetail 62 | pthread_mutex_t w_mutex; 63 | pthread_cond_t w_condl; 64 | struct task *readhead = NULL, *readtail = NULL; 65 | struct task *writehead = NULL, *writetail = NULL; 66 | 67 | void setnonblocking(int sock) 68 | { 69 | int opts; 70 | if ((opts = fcntl(sock, F_GETFL)) < 0) 71 | errexit("GETFL %d failed", sock); 72 | opts = opts | O_NONBLOCK; 73 | if (fcntl(sock, F_SETFL, opts) < 0) 74 | errexit("SETFL %d failed", sock); 75 | } 76 | 77 | int main(int argc,char* argv[]) 78 | { 79 | // nfds is number of events (number of returned fd) 80 | int i, maxi, nfds; 81 | int listenfd, connfd; 82 | // read task threads 83 | pthread_t tid1, tid2; 84 | // write back threads 85 | pthread_t tid3, tid4; 86 | // task node 87 | struct task *new_task = NULL; 88 | socklen_t clilen; 89 | struct sockaddr_in clientaddr; 90 | struct sockaddr_in serveraddr; 91 | 92 | pthread_mutex_init(&r_mutex, NULL); 93 | pthread_cond_init(&r_condl, NULL); 94 | pthread_mutex_init(&w_mutex, NULL); 95 | pthread_cond_init(&w_condl, NULL); 96 | 97 | // threads for reading thread pool 98 | pthread_create(&tid1, NULL, readtask, NULL); 99 | pthread_create(&tid2, NULL, readtask, NULL); 100 | // threads for respond to client 101 | pthread_create(&tid3, NULL, writetask, NULL); 102 | pthread_create(&tid4, NULL, writetask, NULL); 103 | 104 | // epoll descriptor, for handling accept 105 | epfd = epoll_create(256); 106 | listenfd = socket(PF_INET, SOCK_STREAM, 0); 107 | // set the descriptor as non-blocking 108 | setnonblocking(listenfd); 109 | // event related descriptor 110 | ev.data.fd = listenfd; 111 | // monitor in message, edge trigger 112 | ev.events = EPOLLIN | EPOLLET; 113 | // register epoll event 114 | epoll_ctl(epfd, EPOLL_CTL_ADD, listenfd, &ev); 115 | 116 | bzero(&serveraddr, sizeof(serveraddr)); 117 | serveraddr.sin_family = AF_INET; 118 | char *local_addr = LOCAL_ADDR; 119 | inet_aton(local_addr, &(serveraddr.sin_addr)); 120 | serveraddr.sin_port = htons(SERV_PORT); 121 | bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)); 122 | listen(listenfd, LISTENQ); 123 | 124 | maxi = 0; 125 | for(;;) 126 | { 127 | // waiting for epoll event 128 | nfds = epoll_wait(epfd, events, LISTENQ, TIMEOUT); 129 | // In case of edge trigger, must go over each event 130 | for (i = 0; i < nfds; ++i) 131 | { 132 | // Get new connection 133 | if (events[i].data.fd == listenfd) 134 | { 135 | // accept the client connection 136 | connfd = accept(listenfd, (struct sockaddr*)&clientaddr, &clilen); 137 | if (connfd < 0) 138 | errexit("connfd < 0"); 139 | setnonblocking(connfd); 140 | echo("[SERVER] connect from %s \n", inet_ntoa(clientaddr.sin_addr)); 141 | ev.data.fd = connfd; 142 | // monitor in message, edge trigger 143 | ev.events = EPOLLIN | EPOLLET; 144 | // add fd to epoll queue 145 | epoll_ctl(epfd, EPOLL_CTL_ADD, connfd, &ev); 146 | } 147 | // Received data 148 | else if (events[i].events & EPOLLIN) 149 | { 150 | if (events[i].data.fd < 0) 151 | continue; 152 | echo("[SERVER] put task %d to read queue\n", events[i].data.fd); 153 | new_task = malloc(sizeof(struct task)); 154 | new_task->data.fd = events[i].data.fd; 155 | new_task->next = NULL; 156 | //echo("[SERVER] thread %d epollin before lock\n", pthread_self()); 157 | // protect task queue (readhead/readtail) 158 | pthread_mutex_lock(&r_mutex); 159 | //echo("[SERVER] thread %d epollin after lock\n", pthread_self()); 160 | // the queue is empty 161 | if (readhead == NULL) 162 | { 163 | readhead = new_task; 164 | readtail = new_task; 165 | } 166 | // queue is not empty 167 | else 168 | { 169 | readtail->next = new_task; 170 | readtail = new_task; 171 | } 172 | // trigger readtask thread 173 | pthread_cond_broadcast(&r_condl); 174 | //echo("[SERVER] thread %d epollin before unlock\n", pthread_self()); 175 | pthread_mutex_unlock(&r_mutex); 176 | //echo("[SERVER] thread %d epollin after unlock\n", pthread_self()); 177 | } 178 | // Have data to send 179 | else if (events[i].events & EPOLLOUT) 180 | { 181 | if (events[i].data.ptr == NULL) 182 | continue; 183 | echo("[SERVER] put task %d to write queue\n", ((struct task*)events[i].data.ptr)->data.fd); 184 | new_task = malloc(sizeof(struct task)); 185 | new_task->data.ptr = (struct user_data*)events[i].data.ptr; 186 | new_task->next = NULL; 187 | //echo("[SERVER] thread %d epollout before lock\n", pthread_self()); 188 | pthread_mutex_lock(&w_mutex); 189 | //echo("[SERVER] thread %d epollout after lock\n", pthread_self()); 190 | // the queue is empty 191 | if (writehead == NULL) 192 | { 193 | writehead = new_task; 194 | writetail = new_task; 195 | } 196 | // queue is not empty 197 | else 198 | { 199 | writetail->next = new_task; 200 | writetail = new_task; 201 | } 202 | // trigger writetask thread 203 | pthread_cond_broadcast(&w_condl); 204 | //echo("[SERVER] thread %d epollout before unlock\n", pthread_self()); 205 | pthread_mutex_unlock(&w_mutex); 206 | //echo("[SERVER] thread %d epollout after unlock\n", pthread_self()); 207 | } 208 | else 209 | { 210 | echo("[SERVER] Error: unknown epoll event"); 211 | } 212 | } 213 | } 214 | 215 | return 0; 216 | } 217 | 218 | void *readtask(void *args) 219 | { 220 | int fd = -1; 221 | int n, i; 222 | struct user_data* data = NULL; 223 | while(1) 224 | { 225 | //echo("[SERVER] thread %d readtask before lock\n", pthread_self()); 226 | // protect task queue (readhead/readtail) 227 | pthread_mutex_lock(&r_mutex); 228 | //echo("[SERVER] thread %d readtask after lock\n", pthread_self()); 229 | while(readhead == NULL) 230 | // if condl false, will unlock mutex 231 | pthread_cond_wait(&r_condl, &r_mutex); 232 | 233 | fd = readhead->data.fd; 234 | struct task* tmp = readhead; 235 | readhead = readhead->next; 236 | free(tmp); 237 | 238 | //echo("[SERVER] thread %d readtask before unlock\n", pthread_self()); 239 | pthread_mutex_unlock(&r_mutex); 240 | //echo("[SERVER] thread %d readtask after unlock\n", pthread_self()); 241 | 242 | echo("[SERVER] readtask %d handling %d\n", pthread_self(), fd); 243 | data = malloc(sizeof(struct user_data)); 244 | data->fd = fd; 245 | if ((n = recv(fd, data->line, MAXBTYE, 0)) < 0) 246 | { 247 | if (errno == ECONNRESET) 248 | close(fd); 249 | echo("[SERVER] Error: readline failed: %s\n", strerror(errno)); 250 | if (data != NULL) 251 | free(data); 252 | } 253 | else if (n == 0) 254 | { 255 | close(fd); 256 | echo("[SERVER] Error: client closed connection.\n"); 257 | if (data != NULL) 258 | free(data); 259 | } 260 | else 261 | { 262 | data->n_size = n; 263 | for (i = 0; i < n; ++i) 264 | { 265 | if (data->line[i] == '\n' || data->line[i] > 128) 266 | { 267 | data->line[i] = '\0'; 268 | data->n_size = i + 1; 269 | } 270 | } 271 | echo("[SERVER] readtask %d received %d : [%d] %s\n", pthread_self(), fd, data->n_size, data->line); 272 | if (data->line[0] != '\0') 273 | { 274 | // modify monitored event to EPOLLOUT, wait next loop to send respond 275 | ev.data.ptr = data; 276 | // Modify event to EPOLLOUT 277 | ev.events = EPOLLOUT | EPOLLET; 278 | // modify moditored fd event 279 | epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev); 280 | } 281 | } 282 | } 283 | } 284 | 285 | void *writetask(void *args) 286 | { 287 | unsigned int n; 288 | // data to wirte back to client 289 | struct user_data *rdata = NULL; 290 | while(1) 291 | { 292 | //echo("[SERVER] thread %d writetask before lock\n", pthread_self()); 293 | pthread_mutex_lock(&w_mutex); 294 | //echo("[SERVER] thread %d writetask after lock\n", pthread_self()); 295 | while(writehead == NULL) 296 | // if condl false, will unlock mutex 297 | pthread_cond_wait(&w_condl, &w_mutex); 298 | 299 | rdata = (struct user_data*)writehead->data.ptr; 300 | struct task* tmp = writehead; 301 | writehead = writehead->next; 302 | free(tmp); 303 | 304 | //echo("[SERVER] thread %d writetask before unlock\n", pthread_self()); 305 | pthread_mutex_unlock(&w_mutex); 306 | //echo("[SERVER] thread %d writetask after unlock\n", pthread_self()); 307 | 308 | echo("[SERVER] writetask %d sending %d : [%d] %s\n", pthread_self(), rdata->fd, rdata->n_size, rdata->line); 309 | // send responce to client 310 | if ((n = send(rdata->fd, rdata->line, rdata->n_size, 0)) < 0) 311 | { 312 | if (errno == ECONNRESET) 313 | close(rdata->fd); 314 | echo("[SERVER] Error: send responce failed: %s\n", strerror(errno)); 315 | } 316 | else if (n == 0) 317 | { 318 | close(rdata->fd); 319 | echo("[SERVER] Error: client closed connection."); 320 | } 321 | else 322 | { 323 | // modify monitored event to EPOLLIN, wait next loop to receive data 324 | ev.data.fd = rdata->fd; 325 | // monitor in message, edge trigger 326 | ev.events = EPOLLIN | EPOLLET; 327 | // modify moditored fd event 328 | epoll_ctl(epfd, EPOLL_CTL_MOD, rdata->fd, &ev); 329 | } 330 | // delete data 331 | free(rdata); 332 | } 333 | } 334 | 335 | --------------------------------------------------------------------------------