Linux下socket异步通讯聊天程序

Linux下socket异步通讯聊天程序(转)
original from: http://yangqi.org/linux-socket-asynchronous-im-system/

Posted by yangqi @ 2010年02月17日 [Wed] 22:37
网络课的project 1能用到的资料,程序结构比较清晰,转来学习一下

什么是异步通讯?
就是通讯任意一方可以任意发送消息,有消息来到时会收到系统提示去接收消息。

这里要用到select函数。使用步骤如下:
1、设置一个集合变量,用来存放所有要判断的句柄(file descriptors:即我们建立的每个socket、用open打开的每个文件等)
2、把需要判断的句柄加入到集合里
3、设置判断时间
4、开始等待,即select
5、如果在设定的时间内有任何句柄状态变化了就马上返回,并把句柄设置到集合里

服务器端源代码如下:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <errno.h>  
  4. #include <string.h>  
  5. #include <sys/types.h>  
  6. #include <netinet/in.h>  
  7. #include <sys/socket.h>  
  8. #include <sys/wait.h>  
  9. #include <unistd.h>  
  10. #include <arpa/inet.h>  
  11. #include <sys/time.h>  
  12. #include <sys/types.h>  
  13. #define MAXBUF 1024  
  14. /************关于本文档******************************************** 
  15. *filename: async-server.c 
  16. *purpose: 演示网络异步通讯,这是服务器端程序 
  17. *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
  18. Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
  19. *date time:2007-01-25 21:22 
  20. *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
  21. * 但请遵循GPL 
  22. *Thanks to: Google.com 
  23. *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
  24. * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
  25. *********************************************************************/  
  26. int main(int argc, char **argv)  
  27. {  
  28.     int sockfd, new_fd;  
  29.     socklen_t len;  
  30.     struct sockaddr_in my_addr, their_addr;  
  31.     unsigned int myport, lisnum;  
  32.     char buf[MAXBUF + 1];  
  33.     fd_set rfds;  
  34.     struct timeval tv;  
  35.     int retval, maxfd = -1;  
  36.       
  37.     if (argv[1])  
  38.         myport = atoi(argv[1]);  
  39.     else  
  40.         myport = 7838;  
  41.           
  42.     if (argv[2])  
  43.         lisnum = atoi(argv[2]);  
  44.     else  
  45.         lisnum = 2;  
  46.           
  47.     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1)   
  48.     {  
  49.         perror("socket");  
  50.         exit(1);  
  51.     }  
  52.       
  53.     bzero(&my_addr, sizeof(my_addr));  
  54.     my_addr.sin_family = PF_INET;  
  55.     my_addr.sin_port = htons(myport);  
  56.       
  57.     if (argv[3])  
  58.         my_addr.sin_addr.s_addr = inet_addr(argv[3]);  
  59.     else  
  60.         my_addr.sin_addr.s_addr = INADDR_ANY;  
  61.           
  62.     if (bind(sockfd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr))== -1)   
  63.     {  
  64.         perror("bind");  
  65.         exit(1);  
  66.     }  
  67.       
  68.     if (listen(sockfd, lisnum) == -1)   
  69.     {  
  70.         perror("listen");  
  71.         exit(1);  
  72.     }  
  73.       
  74.     while (1)   
  75.     {  
  76.         printf("\n----等待新的连接到来开始新一轮聊天……\n");  
  77.         len = sizeof(struct sockaddr);  
  78.           
  79.         if ((new_fd =accept(sockfd, (struct sockaddr *) &their_addr,&len)) == -1)   
  80.         {  
  81.             perror("accept");  
  82.             exit(errno);  
  83.         }   
  84.         else  
  85.             printf("server: got connection from %s, port %d, socket %d\n", inet_ntoa(their_addr.sin_addr),ntohs(their_addr.sin_port), new_fd);  
  86.               
  87.         /* 开始处理每个新连接上的数据收发 */  
  88.         printf("\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n");  
  89.         while (1)   
  90.         {  
  91.             /* 把集合清空 */  
  92.             FD_ZERO(&rfds);  
  93.               
  94.             /* 把标准输入句柄0加入到集合中 */  
  95.             FD_SET(0, &rfds);  
  96.             maxfd = 0;  
  97.               
  98.             /* 把当前连接句柄new_fd加入到集合中 */  
  99.             FD_SET(new_fd, &rfds);  
  100.             if (new_fd > maxfd)  
  101.                 maxfd = new_fd;  
  102.                   
  103.             /* 设置最大等待时间 */  
  104.             tv.tv_sec = 1;  
  105.             tv.tv_usec = 0;  
  106.               
  107.             /* 开始等待 */  
  108.             retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  109.             if (retval == -1)   
  110.             {  
  111.                 printf("将退出,select出错! %s", strerror(errno));  
  112.                 break;  
  113.             }   
  114.             else if (retval == 0)   
  115.             {  
  116.                 /* printf("没有任何消息到来,用户也没有按键,继续等待……\n"); */  
  117.                 continue;  
  118.             }   
  119.             else   
  120.             {  
  121.                 if (FD_ISSET(0, &rfds))   
  122.                 {  
  123.                     /* 用户按键了,则读取用户输入的内容发送出去 */  
  124.                     bzero(buf, MAXBUF + 1);  
  125.                     fgets(buf, MAXBUF, stdin);  
  126.                     if (!strncasecmp(buf, "quit", 4))   
  127.                     {  
  128.                         printf("自己请求终止聊天!\n");  
  129.                         break;  
  130.                     }  
  131.                       
  132.                     len = send(new_fd, buf, strlen(buf) - 1, 0);  
  133.                     if (len > 0)  
  134.                         printf("消息:%s\t发送成功,共发送了%d个字节!\n", buf, len);  
  135.                     else   
  136.                     {  
  137.                         printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",buf, errno, strerror(errno));  
  138.                         break;  
  139.                     }  
  140.                 }  
  141.                 if (FD_ISSET(new_fd, &rfds))   
  142.                 {  
  143.                     /* 当前连接的socket上有消息到来则接收对方发过来的消息并显示 */  
  144.                     bzero(buf, MAXBUF + 1);  
  145.                       
  146.                     /* 接收客户端的消息 */  
  147.                     len = recv(new_fd, buf, MAXBUF, 0);  
  148.                       
  149.                     if (len > 0)  
  150.                         printf("接收消息成功:'%s',共%d个字节的数据\n",buf, len);  
  151.                     else   
  152.                     {  
  153.                         if (len < 0)  
  154.                             printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",errno, strerror(errno));  
  155.                         else  
  156.                             printf("对方退出了,聊天终止\n");  
  157.                         break;  
  158.                     }  
  159.                 }  
  160.             }  
  161.         }  
  162.           
  163.         close(new_fd);  
  164.           
  165.         /* 处理每个新连接上的数据收发结束 */  
  166.         printf("还要和其它连接聊天吗?(no->退出)");  
  167.         fflush(stdout);  
  168.         bzero(buf, MAXBUF + 1);  
  169.         fgets(buf, MAXBUF, stdin);  
  170.         if (!strncasecmp(buf, "no", 2))   
  171.         {  
  172.             printf("终止聊天!\n");  
  173.             break;  
  174.         }  
  175.     }  
  176.       
  177.     close(sockfd);  
  178.     return 0;  
  179. }  


客户端源代码如下:
[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <string.h>  
  3. #include <errno.h>  
  4. #include <sys/socket.h>  
  5. #include <resolv.h>  
  6. #include <stdlib.h>  
  7. #include <netinet/in.h>  
  8. #include <arpa/inet.h>  
  9. #include <unistd.h>  
  10. #include <sys/time.h>  
  11. #include <sys/types.h>  
  12. #define MAXBUF 1024  
  13. /************关于本文档******************************************** 
  14. // *filename: ssync-client.c 
  15. *purpose: 演示网络异步通讯,这是客户端程序 
  16. *wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com) 
  17. Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言 
  18. *date time:2007-01-25 21:32 
  19. *Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途 
  20. * 但请遵循GPL 
  21. *Thanks to: Google.com 
  22. *Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力 
  23. * 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献! 
  24. *********************************************************************/  
  25. int main(int argc, char **argv)  
  26. {  
  27.     int sockfd, len;  
  28.     struct sockaddr_in dest;  
  29.     char buffer[MAXBUF + 1];  
  30.     fd_set rfds;  
  31.     struct timeval tv;  
  32.     int retval, maxfd = -1;  
  33.     if (argc != 3)   
  34.     {  
  35.         printf("参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息",argv[0], argv[0]);  
  36.         exit(0);  
  37.     }  
  38.       
  39.     /* 创建一个 socket 用于 tcp 通信 */  
  40.     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)   
  41.     {  
  42.         perror("Socket");  
  43.         exit(errno);  
  44.     }  
  45.       
  46.     /* 初始化服务器端(对方)的地址和端口信息 */  
  47.     bzero(&dest, sizeof(dest));  
  48.     dest.sin_family = AF_INET;  
  49.     dest.sin_port = htons(atoi(argv[2]));  
  50.     if (inet_aton(argv[1], (struct in_addr *) &dest.sin_addr.s_addr) == 0)   
  51.     {  
  52.         perror(argv[1]);  
  53.         exit(errno);  
  54.     }  
  55.       
  56.     /* 连接服务器 */  
  57.     if (connect(sockfd, (struct sockaddr *) &dest, sizeof(dest)) != 0)   
  58.     {  
  59.         perror("Connect ");  
  60.         exit(errno);  
  61.     }  
  62.       
  63.     printf("\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n");  
  64.     while (1)   
  65.     {  
  66.         /* 把集合清空 */  
  67.         FD_ZERO(&rfds);  
  68.           
  69.         /* 把标准输入句柄0加入到集合中 */  
  70.         FD_SET(0, &rfds);  
  71.         maxfd = 0;  
  72.           
  73.         /* 把当前连接句柄sockfd加入到集合中 */  
  74.         FD_SET(sockfd, &rfds);  
  75.         if (sockfd > maxfd)  
  76.             maxfd = sockfd;  
  77.           
  78.         /* 设置最大等待时间 */  
  79.         tv.tv_sec = 1;  
  80.         tv.tv_usec = 0;  
  81.           
  82.         /* 开始等待 */  
  83.         retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);  
  84.         if (retval == -1)   
  85.         {  
  86.             printf("将退出,select出错! %s", strerror(errno));  
  87.             break;  
  88.         } else if (retval == 0)   
  89.         {  
  90.             /* printf("没有任何消息到来,用户也没有按键,继续等待……\n"); */  
  91.             continue;  
  92.         }   
  93.         else   
  94.         {  
  95.             if (FD_ISSET(sockfd, &rfds))   
  96.             {  
  97.                 /* 连接的socket上有消息到来则接收对方发过来的消息并显示 */  
  98.                 bzero(buffer, MAXBUF + 1);  
  99.                   
  100.                 /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */  
  101.                 len = recv(sockfd, buffer, MAXBUF, 0);  
  102.                 if (len > 0)  
  103.                     printf("接收消息成功:'%s',共%d个字节的数据\n",   buffer, len);  
  104.                 else   
  105.                 {  
  106.                     if (len < 0)  
  107.                         printf("消息接收失败!错误代码是%d,错误信息是'%s'\n",errno, strerror(errno));  
  108.                     else  
  109.                         printf("对方退出了,聊天终止!\n");  
  110.                     break;  
  111.                 }  
  112.             }  
  113.               
  114.             if (FD_ISSET(0, &rfds))   
  115.             {  
  116.                 /* 用户按键了,则读取用户输入的内容发送出去 */  
  117.                 bzero(buffer, MAXBUF + 1);  
  118.                 fgets(buffer, MAXBUF, stdin);  
  119.                 if (!strncasecmp(buffer, "quit", 4))   
  120.                 {  
  121.                     printf("自己请求终止聊天!\n");  
  122.                     break;  
  123.                 }  
  124.                   
  125.                 /* 发消息给服务器 */  
  126.                 len = send(sockfd, buffer, strlen(buffer) - 1, 0);  
  127.                 if (len < 0)   
  128.                 {  
  129.                     printf("消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n",buffer, errno, strerror(errno));  
  130.                     break;  
  131.                 }   
  132.                 else  
  133.                     printf("消息:%s\t发送成功,共发送了%d个字节!\n",buffer, len);  
  134.             }  
  135.         }  
  136.     }  
  137.       
  138.     /* 关闭连接 */  
  139.     close(sockfd);  
  140.     return 0;  
  141. }  


FROM:  http://blog.csdn.net/wangweixaut061/article/details/7236900


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值