• 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. }  
  • 相关阅读:
    ARP攻击原理与解决
    如何查看数据库各种表oracle
    MyEclipse 8.0注册码
    oracle数据库导入导出
    输出设备已满或不可用, 归档程序无法归档重做日志[oracle解决方法]
    句柄以及对象的比较java
    shutdown immediate 后无法启动实例问题解决
    马云经典语录
    海量数据处理分析_BI
    数据库迁移方案
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/7133122.html
Copyright © 2020-2023  润新知