• Linux C 网络编程——多线程的聊天室实现(server端)


    server端的主要功能:

           实现多用户群体聊天功能(此程序最多设定为10人。可进行更改),每一个人所发送的消息其它用户均能够收到。用户能够任意的增加或退出(推出以字符串“bye”实现),server也能够进行关闭。

    server端的程序结构:

           总共同拥有三个函数:主函数(main),实现server端的初始化,接受连接;消息处理函数(rcv_snd),接受某一用户的消息。将其进行简单处理之后发送给其它全部的用户;退出函数(quit),可实现server关停。

    这三个函数分别从属于三个线程(准确说是大于等于三个,以下说明原因):main函数的作为诛仙程线程。又创建了一个退出函数所在的线程,以及每次接受到一个连接之后会新创建一个对此连接的消息进行处理的线程(多于三个的原因在此)。


    详细代码实现例如以下:

    1. #include<time.h>  
    2. #include<stdio.h>  
    3. #include<sys/socket.h>  
    4. #include<netinet/in.h>  
    5. #include<string.h>  
    6.   
    7. #define LISTENQ 5  
    8. #define MAXLINE 512  
    9. #define MAXMEM 10  
    10. #define NAMELEN 20  
    11.   
    12. int listenfd,connfd[MAXMEM];//分别记录server端的套接字与连接的多个client的套接字  
    13.   
    14. void quit();//server关闭函数  
    15. void rcv_snd(int n);//server接收并转发消息函数  
    16.   
    17. int main()  
    18. {  
    19.     pthread_t thread;  
    20.     struct sockaddr_in servaddr,cliaddr;  
    21.     socklen_t len;  
    22.     time_t ticks;  
    23.     char buff[MAXLINE];  
    24.   
    25. //调用socket函数创建server端的套接字  
    26.     printf("Socket... ");  
    27.     listenfd=socket(AF_INET,SOCK_STREAM,0);  
    28.     if(listenfd<0)  
    29.     {  
    30.         printf("Socket created failed. ");  
    31.         return -1;  
    32.     }  
    33.   
    34. //调用bind函数使得server端的套接字与地址实现绑定  
    35.     printf("Bind... ");  
    36.     servaddr.sin_family=AF_INET;  
    37.     servaddr.sin_port=htons(6666);  
    38.     servaddr.sin_addr.s_addr=htonl(INADDR_ANY);  
    39.     if(bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr))<0)  
    40.     {  
    41.         printf("Bind failed. ");  
    42.         return -1;  
    43.     }  
    44.   
    45. //调用listen函数,将一个主动连接套接字变为被动的倾听套接字  
    46. //在此过程中完毕tcp的三次握手连接  
    47.     printf("listening... ");  
    48.     listen(listenfd,LISTENQ);  
    49.       
    50. //创建一个线程。对server程序进行管理(关闭)  
    51.     pthread_create(&thread,NULL,(void*)(&quit),NULL);  
    52.   
    53. //记录空暇的client的套接字描写叙述符(-1为空暇)  
    54.     int i=0;  
    55.     for(i=0;i<MAXMEM;i++)  
    56.     {  
    57.         connfd[i]=-1;  
    58.     }  
    59.   
    60.     while(1)  
    61.     {  
    62.         len=sizeof(cliaddr);  
    63.         for(i=0;i<MAXMEM;i++)  
    64.         {  
    65.             if(connfd[i]==-1)  
    66.             {  
    67.                 break;  
    68.             }  
    69.         }  
    70.   
    71. //调用accept从listen接受的连接队列中取得一个连接  
    72.         connfd[i]=accept(listenfd,(struct sockaddr*)&cliaddr,&len);  
    73.   
    74.         ticks=time(NULL);  
    75.         sprintf(buff,"% .24s    ",ctime(&ticks));  
    76.         printf("%s Connect from: %s,port %d ",buff,inet_ntoa(cliaddr.sin_addr.s_addr),ntohs(cliaddr.sin_port));  
    77.   
    78. //针对当前套接字创建一个线程,对当前套接字的消息进行处理  
    79.         pthread_create(malloc(sizeof(pthread_t)),NULL,(void*)(&rcv_snd),(void*)i);  
    80.           
    81.     }  
    82.     return 0;  
    83. }  
    84.   
    85. void quit()  
    86. {  
    87.     char msg[10];  
    88.     while(1)  
    89.     {  
    90.         scanf("%s",msg);  
    91.         if(strcmp("quit",msg)==0)  
    92.         {  
    93.             printf("Byebye... ");  
    94.             close(listenfd);  
    95.             exit(0);  
    96.         }  
    97.     }  
    98. }  
    99.   
    100. void rcv_snd(int n)  
    101. {  
    102.     char* ask="Your name please:";  
    103.     char buff[MAXLINE];  
    104.     char buff1[MAXLINE];  
    105.     char buff2[MAXLINE];  
    106.     char name[NAMELEN];  
    107.     time_t ticks;  
    108.     int i=0;  
    109.     int retval;  
    110.       
    111. //获取此进程相应的套接字用户的名字  
    112.     write(connfd[n],ask,strlen(ask));  
    113.     int len;  
    114.     len=read(connfd[n],name,NAMELEN);  
    115.      if(len>0)  
    116.      {  
    117.          name[len]=0;  
    118.      }  
    119.   
    120. //把当前用户的增加告知全部用户  
    121.     strcpy(buff,name);  
    122.     strcat(buff," join in");  
    123.     for(i=0;i<MAXMEM;i++)  
    124.     {  
    125.         if(connfd[i]!=-1)  
    126.         {  
    127.             write(connfd[i],buff,strlen(buff));  
    128.         }  
    129.     }  
    130.   
    131. //接受当前用户的信息并将其转发给全部的用户  
    132.     while(1)  
    133.     {  
    134.         if((len=read(connfd[n],buff1,MAXLINE))>0)  
    135.         {  
    136.             buff1[len]=0;  
    137.               
    138. //当当前用户的输入信息为“bye”时,当前用户退出  
    139.              if(strcmp("bye",buff)==0)  
    140.              {  
    141.                  close(connfd[n]);  
    142.                  connfd[n]=-1;  
    143.                  pthread_exit(&retval);  
    144.              }  
    145.   
    146.              ticks=time(NULL);  
    147.              sprintf(buff2,"%.24s ",ctime(&ticks));  
    1.          strcpy(buff,name);  
    2.          strcat(buff," ");  
    3.          strcat(buff,buff2);  
    4.          strcat(buff,buff1);  
    5.   
    6.         for(i=0;i<MAXMEM;i++)  
    7.         {  
    8.              if(connfd[i]!=-1)  
    9.              {  
    10.                   write(connfd[i],buff,strlen(buff));  
    11.              }  
    12.         }  
    13.     }  
    14.   
    15. }  
  • 相关阅读:
    vue 动态生成 el-checkbox-group,动态绑定v-model的解决方法
    vue 弹窗内scrollTop取值为0的问题
    软件工程课程学习心得
    《软件工程》学习总结及获奖感言
    软件工程课程心得及小黄衫获奖感想
    Prometheus + Alertmanager 实现企业微信告警
    二进制安装Prometheus
    zabbix机器人告警配置流程
    c++不同平台崩溃解析总结
    c++跨平台开发技术总结
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7133122.html
Copyright © 2020-2023  润新知