Linux下socket异步通讯聊天程序

2023-11-02

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


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Linux下socket异步通讯聊天程序 的相关文章

  • linux AIO (异步IO) 那点事儿

    在高性能的服务器编程中 IO 模型理所当然的是重中之重 需要谨慎选型的 对于网络套接字 我们可以采用epoll 的方式来轮询 尽管epoll也有一些缺陷 但总体来说还是很高效的 尤其来大量套接字的场景下 但对于Regular File 来说
  • 【Linux学习】epoll详解

    什么是epoll epoll是什么 按照man手册的说法 是为处理大批量句柄而作了改进的poll 当然 这不是2 6内核才有的 它是在2 5 44内核中被引进的 epoll 4 is a new API introduced in Linu
  • linux网络编程实现投票功能

    投票系统 1 说明 写了一个投票系统 过程是先配置好服务器 在写一个网上投票功能 要实现网上投票功能 其实功能实现还是很简单的 麻烦一点的在于过程比较繁杂 要做的东西还是挺多的 2 过程 第一步 配置httpd服务器 先配置好httpd服务
  • ipv6 socket bind 失败 - accept_dad

    file proc sys net ipv6 conf interface accept dad variable net ipv6 conf interface accept dad Official reference Whether
  • whois命令常见用法

    whois命令常见用法 whois命令简介 安装whois Windows使用whois Linux安装whois whois常见用法 Linux下whois查询域名注册信息 whois命令简介 whois就是一个用来查询域名是否已经被注册
  • C++在线五子棋对战(网页版)项目:websocket协议

    目标 认识理解websocket协议 websocket切换过程和websocket协议格式 认识和学会使用websocketpp库常用接口 了解websocketpp库搭建服务器流程 认识和学会使用websocketpp库bin接口 最后
  • 使用sersync实现数据实时同步

    使用sersync实现数据实时同步 sersync诞生过程 部署前提 配置rsync服务端 部署sersync 配置sersync的path变量 修改sersync配置文件 sersync常用参数 使用服务文件实现开机自启动 实时同步服务d
  • 【Linux网络(C++)】——网络套接字(TCP/UDP编程模型)多进程,多线程,线程池服务器开发(画图解析)

    目录 一 套接字基本概念 IP地址 TCP和UDP协议 端口号 端口号vs 进程pid 网络字节序 本地字节序转换成网络字节序 网络字节序转换为本地字节序 二 套接字的基本操作 socket的创建 域 domain 类型 type 协议 P
  • Linux网络通信总结

    网络IO之阻塞 非阻塞 同步 异步 单播 多播 组播 广播 多路复用POLL SELECT epoll 超时 read write accept connect 超时 实现 1 用select来设置超时机制 2 使用setsockopt 函
  • 基于tcpdump实例讲解TCP/IP协议

    前言 虽然网络编程的socket大家很多都会操作 但是很多还是不熟悉socket编程中 底层TCP IP协议的交互过程 本文会一个简单的客户端程序和服务端程序的交互过程 使用tcpdump抓包 实例讲解客户端和服务端的TCP IP交互细节
  • 基于epoll的聊天室程序

    epoll相对于poll和select这两个多路复用的I O模型更加的高效 epoll的函数很简单 麻烦的地方在于水平出发和边沿触发 用张图来说明下 ET 边沿 只是在状态反转时触发 比如从不可读到可读 而LT 水平 就是如果可读 就会一直
  • Linux下Socket编程

    什么是Socket Socket接口是TCP IP网络的API Socket接口定义了许多函数或例程 程式员能够用他们来研发TCP IP网络上的应用程式 要学Internet上的TCP IP网络编程 必须理解Socket接口 Socket接
  • linux下异步RPC的阶段性总结-非阻塞SOCKET客户端

    尽可能使用非阻塞socket int flags s flags fcntl fd F GETFL 0 if flags 1 close fd return 1 flags O NONBLOCK s fcntl fd F SETFL fla
  • linux c socket之异步IO

    cpp view plain copy File UDPEchoClient TimeOut c Author 云守护 include
  • 【网络】——UDP复习笔记

    目录 1 UDP报文结构 2 UDP缓冲区 3 UDP特点 4 课后题 1 UDP报文结构 2 UDP缓冲区 UDP没有真正意义上的发送缓冲区 应用层调用sendto 函数直接将数据应用层的数据拷贝给传输层 传输层再构建UDP报头 然后再交
  • 高并发的epoll+多线程

    epoll是linux下高并发服务器的完美方案 因为是基于事件触发的 所以比select快的不只是一个数量级 单线程epoll 触发量可达到15000 但是加上业务后 因为大多数业务都与数据库打交道 所以就会存在阻塞的情况 这个时候就必须用
  • 【IP协议(一)】——IP数据报格式及其含义,IP数据报的切分

    个人主页 努力学习的少年 版权 本文由 努力学习的少年 原创 在CSDN首发 需要转载请联系博主 如果文章对你有帮助 欢迎关注 点赞 收藏 一键三连 和订阅专栏哦 IP数据报格式 版本 占4位 指ip协议的版本 首部长度 表示IP数据报中报
  • 【网络自定向下学习】——TCP报文段的详细解析

    个人主页 努力学习的少年 版权 本文由 努力学习的少年 原创 在CSDN首发 需要转载请联系博主 如果文章对你有帮助 欢迎关注 点赞 收藏 一键三连 和订阅专栏哦 目录 一 Tcp报文段的结构 二 首部长度 三 窗口大小 四 序列号和确认序
  • Http协议详解

    引入 超文本传输协议 HTTP HyperText Transfer Protocol 是互联网上应用最为广泛的一种网络协议 所有的WWW文件都必须遵守这个标准 设计HTTP最初的目的是为了提供一种发布和接收HTML页面的方法 1960年美
  • 超级详细Tcpdump 的用法

    1 抓取回环网口的包 tcpdump i lo 2 防止包截断 tcpdump s0 3 以数字显示主机及端口 tcpdump n 第一种是关于类型的关键字 主要包括host net port 例如 host 210 27 48 2 指明

随机推荐