基于TCP协议用多线程实现并发服务器,实现思路、算法和demo

来源:互联网 发布:麒麟970 知乎 编辑:程序博客网 时间:2024/06/11 10:56

基本的思路:用主线程负责client的连接, 然后当有客户端来连接的时候,创建子进程。在子进程里面实现数据的接收。

1.myhead.h

先把一些要用的API的头文件都写进来。
[cpp] view plain copy
  1. #ifndef _MYHEAD_H_  
  2. #define _MYHEAD_H_  
  3.   
  4. #include <stdio.h>  
  5. #include <sys/types.h>  
  6. #include <sys/socket.h>  
  7. #include <netinet/in.h>  
  8. #include <string.h>  
  9. #include <unistd.h>  
  10. #include <sys/wait.h>  
  11. #include <pthread.h>  
  12.   
  13. #define MYPORT 6667         //1024以下的是保留的端口号,用大于1024的;  
  14. //#define MYADDR "192.168.1.102"         //把这行注释掉,可以在调用客户端程序时,输入服务器运行的IP来连接服务器 ./client 192.168.1.233  
  15.   
  16. #endif  

2.server.c

[cpp] view plain copy
  1. #include "myhead.h"  
  2.   
  3. void *read_msg(void *argc);  
  4.   
  5. int main()  
  6. {  
  7.     int ret = 0;  
  8.     int socketfd = 0;                               //局部变量保存在栈空间,而栈空间是脏的==》里面还是保存的是上一次这个区域里面保存的值;  
  9.     int clientfd = 0;  
  10.       
  11.     pid_t pid = 0;  
  12.     pthread_t th = 0;  
  13.       
  14.       
  15.     struct sockaddr_in sock_server = {0};           //变量类型保存在netinet/in.h里面的;  
  16.     struct sockaddr_in sock_client = {0};           //保存连接的客户端那边的信息;  
  17.       
  18.     socklen_t len = sizeof(struct sockaddr);  
  19.       
  20.     //第一步:创建套接字;  
  21.     socketfd = socket(AF_INET,SOCK_STREAM,0);  
  22.     if(socketfd == -1)      //入口检查  
  23.     {  
  24.         perror("socket");    //打印错误信息  
  25.         return -1;  
  26.     }  
  27.     printf("socket success...\n");                  //确保前面的代码是运行正确的;  
  28.       
  29.     //第二步:给套接字绑定必要的信息;  
  30.     sock_server.sin_family = AF_INET;               //给服务程序绑定地址族;  
  31.     sock_server.sin_port = htons(MYPORT);           //给服务器程序设定个端口号;  
  32. //  sock_server.sin_addr.s_addr = inet_addr(MYADDR);//给服务程序绑定IP地址;  
  33.     sock_server.sin_addr.s_addr = htonl(INADDR_ANY);//绑定任意ip地址;这样就能够实现像之前说的./client 192.168.1.233这样使用  
  34.       
  35.     ret = bind(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));  
  36.     if(ret == -1)  
  37.     {  
  38.         perror("bind");  
  39.         return -1;  
  40.     }  
  41.     printf("bind success..\n");  
  42.       
  43.     //第三步:listen监听!  
  44.     ret = listen(socketfd,10);  
  45.     if(ret == -1)  
  46.     {  
  47.         perror("listen");  
  48.         return -1;  
  49.     }  
  50.     printf("listen success...\n");  
  51.       
  52. //这里的第四步accept放到下面的while(1)里面,有许多client要连接到服务器中来      
  53. //  clientfd = accept(socketfd,(struct sockaddr *)&sock_client,&len);  
  54. //  if(clientfd == -1)  
  55. //  {  
  56. //      perror("accept");  
  57. //      return -1;  
  58. //  }  
  59. //  printf("accept success...clinet fd = %d\n",clientfd);  
  60.       
  61.     while(1)  
  62.     {  
  63.         clientfd = accept(socketfd,(struct sockaddr *)&sock_client,&len);  
  64.         if(clientfd == -1)  
  65.         {  
  66.             perror("accept");  
  67.             return -1;  
  68.         }  
  69.         printf("accept success... clientfd = %d\n",clientfd);   //客户端连接进来,  
  70.         ret = pthread_create(&th,NULL,read_msg,&clientfd);      //执行read_msg这个函数。传递clientfd,要知道从哪一个客户端来读取数据;  
  71.         if(ret != 0)  
  72.         {  
  73.             perror("pthread_create");  
  74.             return -1;  
  75.         }  
  76.     }  
  77.     close(socketfd);  
  78.       
  79.     return 0;  
  80. }  
  81.   
  82. void *read_msg(void *argc)  
  83. {  
  84.     //argc首先是void类型的指针,经过(int *)argc强制转化为int *的指针,接下来要从argc所指向的地址里面取值;  
  85.     //===>*((int *)argc);===>经过以上的操作就将pthread_create()里面传递的参数,赋值给fd;  
  86.       
  87.     int fd = *((int *)argc);  
  88.     printf("fd = %d\n",fd);     //验证fd是否等于main函数里面的cleintfd;    4  
  89.       
  90.     char recvbuff[20] = {0};   //用来保存接收的信息  
  91.     int recvcnt = 0;              //用来存recv函数的返回值  
  92.       
  93.     while(1)  
  94.     {  
  95.         bzero(recvbuff,sizeof(recvbuff));     //先清空recvbuff里面的内容。  
  96.         recvcnt = read(fd,recvbuff,sizeof(recvbuff));    //从recvbuff中读取,sizeof(recvbuff)大小的内容到为文件描述符fd的文件中  
  97.         if(recvcnt == -1)  
  98.         {  
  99.             perror("recv");  
  100.             return NULL;  
  101.         }  
  102.         else if(recvcnt == 0)             
  103.         {  
  104.             printf("The Client is closed!\n");  
  105.             break;  
  106.         }  
  107.         else  
  108.         {  
  109.             printf("Recv from Client %d bytes,data:%s\n",recvcnt,recvbuff);  //打印接收到的信息  
  110.         }  
  111.         if(strcmp(recvbuff,"end") == 0)  
  112.         {  
  113.             break;  
  114.         }  
  115.     }  
  116.     close(fd);  
  117.       
  118.     return NULL;  
  119. }  

3.client.c

[cpp] view plain copy
  1. #include "myhead.h"  
  2.   
  3. //int main()  
  4. int main(int argc,char **argv)  
  5. {  
  6.     //参数入口检查;  
  7.     if(argc != 2)              //usage: ./client 192.168.1.233  
  8.     {  
  9.         perror("argc");  
  10.         return -1;  
  11.     }  
  12.     int socketfd = 0;  
  13.     int ret = 0;  
  14.       
  15.     struct sockaddr_in sock_server = {0};  
  16.       
  17.     socketfd = socket(AF_INET,SOCK_STREAM,0);        //第一步还是创建套接字  
  18.     if(-1 == socketfd)  
  19.     {  
  20.         perror("socket");  
  21.         return -1;  
  22.     }  
  23.     printf("socket success...\n");  
  24.       
  25.     //用sock_server提醒你们这边连接的是服务器端的IP地址和端口号;  
  26.     sock_server.sin_family = AF_INET;  
  27.     sock_server.sin_port = htons(MYPORT);  
  28. //  sock_server.sin_addr.s_addr = inet_addr(MYADDR);  
  29.     sock_server.sin_addr.s_addr = inet_addr(argv[1]);  
  30.       
  31.     ret = connect(socketfd,(struct sockaddr *)&sock_server,sizeof(struct sockaddr));        //连接服务器  
  32.     if(ret == -1)  
  33.     {  
  34.         perror("connect");  
  35.         return -1;  
  36.     }  
  37.       
  38.     char sendbuff[20] = {0};  
  39.     int sendcnt = 0;  
  40.       
  41.     while(1)  
  42.     {  
  43.         //第一步:提示客户输入要发送的数据;  
  44.         printf("Please input a string:\n");  
  45.         scanf("%s",sendbuff);  
  46.           
  47.         //第二步:调用send向套接字发送数据;  
  48. //      sendcnt = send(socketfd,sendbuff,strlen(sendbuff),0);  
  49.         sendcnt = write(socketfd,sendbuff,strlen(sendbuff));  
  50.         if(sendcnt == -1)  
  51.         {  
  52.             perror("send");  
  53.             return -1;  
  54.         }  
  55.         else  
  56.         {  
  57.             printf("Send to Server %d bytes,data:%s\n",sendcnt,sendbuff);  
  58.         }  
  59.         //第三步:判断发送的数据是否是end,如果是,就结束;  
  60.         if(strcmp(sendbuff,"end") == 0)  
  61.         {  
  62.             close(socketfd);  
  63.             break;  
  64.         }  
  65.     }  
  66.           
  67.     return 0;  
  68. }  
分别编译服务器和客户端程序: 
gcc server.c -o server 
gcc client.c -o client 
然后,先运行服务器./server,再运行客户端./client,客户端发消息给服务器,服务器回复,实现基本的一收一发的功能。
阅读全文
0 0
原创粉丝点击