Linux下C编写基本的多线程socket服务器
不想多说什么,会搜这些东西的都是想看代码的吧。
一开始不熟悉多线程的时候还在想怎么来控制一个线程的结束,后来发现原来有pthread_exit()函数可以直接在线程函数内部调用结束这个线程。
开始还想初始化一个pthread_t thread_fd[MAX]数组来存储开启的线程,然后用一个栈存储那些未分配的数组元素(thread_fd[index]=0)的index,跟缓存的思维相似,不过实在是想多了。
废话不多说,直接上代码,服务器和客户端都已经编译通过,正常运行,有基本的容错能力,不过也只是最基本的。
服务器:
1 /* 2 * multi_thread_socket_server.c 3 * 4 * Created on: Mar 14, 2014 5 * Author: nerohwang 6 */ 7 #include<stdlib.h> 8 #include<pthread.h> 9 #include<sys/socket.h> 10 #include<sys/types.h> //pthread_t , pthread_attr_t and so on. 11 #include<stdio.h> 12 #include<netinet/in.h> //structure sockaddr_in 13 #include<arpa/inet.h> //Func : htonl; htons; ntohl; ntohs 14 #include<assert.h> //Func :assert 15 #include<string.h> //Func :memset 16 #include<unistd.h> //Func :close,write,read 17 #define SOCK_PORT 9988 18 #define BUFFER_LENGTH 1024 19 #define MAX_CONN_LIMIT 512 //MAX connection limit 20 21 static void Data_handle(void * sock_fd); //Only can be seen in the file 22 23 int main() 24 { 25 int sockfd_server; 26 int sockfd; 27 int fd_temp; 28 struct sockaddr_in s_addr_in; 29 struct sockaddr_in s_addr_client; 30 int client_length; 31 32 sockfd_server = socket(AF_INET,SOCK_STREAM,0); //ipv4,TCP 33 assert(sockfd_server != -1); 34 35 //before bind(), set the attr of structure sockaddr. 36 memset(&s_addr_in,0,sizeof(s_addr_in)); 37 s_addr_in.sin_family = AF_INET; 38 s_addr_in.sin_addr.s_addr = htonl(INADDR_ANY); //trans addr from uint32_t host byte order to network byte order. 39 s_addr_in.sin_port = htons(SOCK_PORT); //trans port from uint16_t host byte order to network byte order. 40 fd_temp = bind(sockfd_server,(struct scokaddr *)(&s_addr_in),sizeof(s_addr_in)); 41 if(fd_temp == -1) 42 { 43 fprintf(stderr,"bind error!\n"); 44 exit(1); 45 } 46 47 fd_temp = listen(sockfd_server,MAX_CONN_LIMIT); 48 if(fd_temp == -1) 49 { 50 fprintf(stderr,"listen error!\n"); 51 exit(1); 52 } 53 54 while(1) 55 { 56 printf("waiting for new connection...\n"); 57 pthread_t thread_id; 58 client_length = sizeof(s_addr_client); 59 60 //Block here. Until server accpets a new connection. 61 sockfd = accept(sockfd_server,(struct sockaddr_*)(&s_addr_client),(socklen_t *)(&client_length)); 62 if(sockfd == -1) 63 { 64 fprintf(stderr,"Accept error!\n"); 65 continue; //ignore current socket ,continue while loop. 66 } 67 printf("A new connection occurs!\n"); 68 if(pthread_create(&thread_id,NULL,(void *)(&Data_handle),(void *)(&sockfd)) == -1) 69 { 70 fprintf(stderr,"pthread_create error!\n"); 71 break; //break while loop 72 } 73 } 74 75 //Clear 76 int ret = shutdown(sockfd_server,SHUT_WR); //shut down the all or part of a full-duplex connection. 77 assert(ret != -1); 78 79 printf("Server shuts down\n"); 80 return 0; 81 } 82 83 static void Data_handle(void * sock_fd) 84 { 85 int fd = *((int *)sock_fd); 86 int i_recvBytes; 87 char data_recv[BUFFER_LENGTH]; 88 const char * data_send = "Server has received your request!\n"; 89 90 while(1) 91 { 92 printf("waiting for request...\n"); 93 //Reset data. 94 memset(data_recv,0,BUFFER_LENGTH); 95 96 i_recvBytes = read(fd,data_recv,BUFFER_LENGTH); 97 if(i_recvBytes == 0) 98 { 99 printf("Maybe the client has closed\n"); 100 break; 101 } 102 if(i_recvBytes == -1) 103 { 104 fprintf(stderr,"read error!\n"); 105 break; 106 } 107 if(strcmp(data_recv,"quit")==0) 108 { 109 printf("Quit command!\n"); 110 break; //Break the while loop. 111 } 112 printf("read from client : %s\n",data_recv); 113 if(write(fd,data_send,strlen(data_send)) == -1) 114 { 115 break; 116 } 117 } 118 119 //Clear 120 printf("terminating current client_connection...\n"); 121 close(fd); //close a file descriptor. 122 pthread_exit(NULL); //terminate calling thread! 123 }
外加客户端:
1 /* 2 * socket_client.c 3 * 4 * Created on: Mar 15, 2014 5 * Author: nerohwang 6 */ 7 #include<stdlib.h> 8 #include<sys/socket.h> 9 #include<sys/types.h> //pthread_t , pthread_attr_t and so on. 10 #include<stdio.h> 11 #include<netinet/in.h> //structure sockaddr_in 12 #include<arpa/inet.h> //Func : htonl; htons; ntohl; ntohs 13 #include<assert.h> //Func :assert 14 #include<string.h> //Func :memset 15 #include<unistd.h> //Func :close,write,read 16 #define SOCK_PORT 9988 17 #define BUFFER_LENGTH 1024 18 int main() 19 { 20 int sockfd; 21 int tempfd; 22 struct sockaddr_in s_addr_in; 23 char data_send[BUFFER_LENGTH]; 24 char data_recv[BUFFER_LENGTH]; 25 memset(data_send,0,BUFFER_LENGTH); 26 memset(data_recv,0,BUFFER_LENGTH); 27 28 sockfd = socket(AF_INET,SOCK_STREAM,0); //ipv4,TCP 29 if(sockfd == -1) 30 { 31 fprintf(stderr,"socket error!\n"); 32 exit(1); 33 } 34 35 //before func connect, set the attr of structure sockaddr. 36 memset(&s_addr_in,0,sizeof(s_addr_in)); 37 s_addr_in.sin_addr.s_addr = inet_addr("127.0.0.1"); //trans char * to in_addr_t 38 s_addr_in.sin_family = AF_INET; 39 s_addr_in.sin_port = htons(SOCK_PORT); 40 41 tempfd = connect(sockfd,(struct sockaddr *)(&s_addr_in),sizeof(s_addr_in)); 42 if(tempfd == -1) 43 { 44 fprintf(stderr,"Connect error! \n"); 45 exit(1); 46 } 47 48 while(1) 49 { 50 printf("Please input something you wanna say(input \"quit\" to quit):\n"); 51 gets(data_send); 52 //scanf("%[^\n]",data_send); //or you can also use this 53 tempfd = write(sockfd,data_send,BUFFER_LENGTH); 54 if(tempfd == -1) 55 { 56 fprintf(stderr,"write error\n"); 57 exit(0); 58 } 59 60 if(strcmp(data_send,"quit") == 0) //quit,write the quit request and shutdown client 61 { 62 break; 63 } 64 else 65 { 66 tempfd = read(sockfd,data_recv,BUFFER_LENGTH); 67 assert(tempfd != -1); 68 printf("%s\n",data_recv); 69 memset(data_send,0,BUFFER_LENGTH); 70 memset(data_recv,0,BUFFER_LENGTH); 71 } 72 } 73 74 int ret = shutdown(sockfd,SHUT_WR); //or you can use func close()--<unistd.h> to close the fd 75 assert(ret != -1); 76 return 0; 77 }