`
zhaohaolin
  • 浏览: 1024581 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Linux下socket异步通讯聊天程序(转)

 
阅读更多

网络课的project 1能用到的资料,程序结构比较清晰,转来学习一下

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

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

服务器端源代码如下:

?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <sys/types.h>
 
#define MAXBUF 1024
/************关于本文档********************************************
*filename: async-server.c
*purpose: 演示网络异步通讯,这是服务器端程序
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com )
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-25 21:22
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to: Google.com
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
 
int main( int argc, char **argv)
{
     int sockfd, new_fd;
     socklen_t len;
     struct sockaddr_in my_addr, their_addr;
     unsigned int myport, lisnum;
     char buf[MAXBUF + 1];
     fd_set rfds;
     struct timeval tv;
     int retval, maxfd = -1;
 
     if (argv[1])
         myport = atoi (argv[1]);
     else
         myport = 7838;
 
     if (argv[2])
         lisnum = atoi (argv[2]);
     else
         lisnum = 2;
 
     if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
         perror ( "socket" );
         exit (1);
     }
 
     bzero(&my_addr, sizeof (my_addr));
     my_addr.sin_family = PF_INET;
     my_addr.sin_port = htons(myport);
     if (argv[3])
         my_addr.sin_addr.s_addr = inet_addr(argv[3]);
     else
         my_addr.sin_addr.s_addr = INADDR_ANY;
 
     if (bind(sockfd, ( struct sockaddr *) &my_addr, sizeof ( struct sockaddr))
         == -1) {
         perror ( "bind" );
         exit (1);
     }
 
     if (listen(sockfd, lisnum) == -1) {
         perror ( "listen" );
         exit (1);
     }
 
     while (1) {
         printf
             ( "\n----等待新的连接到来开始新一轮聊天……\n" );
         len = sizeof ( struct sockaddr);
         if ((new_fd =
              accept(sockfd, ( struct sockaddr *) &their_addr,
                     &len)) == -1) {
             perror ( "accept" );
             exit ( errno );
         } else
             printf ( "server: got connection from %s, port %d, socket %d\n" ,
                    inet_ntoa(their_addr.sin_addr),
                    ntohs(their_addr.sin_port), new_fd);
 
         /* 开始处理每个新连接上的数据收发 */
         printf
             ( "\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n" );
         while (1) {
             /* 把集合清空 */
             FD_ZERO(&rfds);
             /* 把标准输入句柄0加入到集合中 */
             FD_SET(0, &rfds);
             maxfd = 0;
             /* 把当前连接句柄new_fd加入到集合中 */
             FD_SET(new_fd, &rfds);
             if (new_fd > maxfd)
                 maxfd = new_fd;
             /* 设置最大等待时间 */
             tv.tv_sec = 1;
             tv.tv_usec = 0;
             /* 开始等待 */
             retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
             if (retval == -1) {
                 printf ( "将退出,select出错! %s" , strerror ( errno ));
                 break ;
             } else if (retval == 0) {
                 /* printf
                    ("没有任何消息到来,用户也没有按键,继续等待……\n"); */
                 continue ;
             } else {
                 if (FD_ISSET(0, &rfds)) {
                     /* 用户按键了,则读取用户输入的内容发送出去 */
                     bzero(buf, MAXBUF + 1);
                     fgets (buf, MAXBUF, stdin);
                     if (!strncasecmp(buf, "quit" , 4)) {
                         printf ( "自己请求终止聊天!\n" );
                         break ;
                     }
                     len = send(new_fd, buf, strlen (buf) - 1, 0);
                     if (len > 0)
                         printf
                             ( "消息:%s\t发送成功,共发送了%d个字节!\n" ,
                              buf, len);
                     else {
                         printf
                             ( "消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n" ,
                              buf, errno , strerror ( errno ));
                         break ;
                     }
                 }
                 if (FD_ISSET(new_fd, &rfds)) {
                     /* 当前连接的socket上有消息到来则接收对方发过来的消息并显示 */
                     bzero(buf, MAXBUF + 1);
                     /* 接收客户端的消息 */
                     len = recv(new_fd, buf, MAXBUF, 0);
                     if (len > 0)
                         printf
                             ( "接收消息成功:'%s',共%d个字节的数据\n" ,
                              buf, len);
                     else {
                         if (len < 0)
                             printf
                                 ( "消息接收失败!错误代码是%d,错误信息是'%s'\n" ,
                                  errno , strerror ( errno ));
                         else
                             printf ( "对方退出了,聊天终止\n" );
                         break ;
                     }
                 }
             }
         }
         close(new_fd);
         /* 处理每个新连接上的数据收发结束 */
         printf ( "还要和其它连接聊天吗?(no->退出)" );
         fflush (stdout);
         bzero(buf, MAXBUF + 1);
         fgets (buf, MAXBUF, stdin);
         if (!strncasecmp(buf, "no" , 2)) {
             printf ( "终止聊天!\n" );
             break ;
         }
     }
 
     close(sockfd);
     return 0;
}

客户端源代码如下:

?
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <resolv.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
 
#define MAXBUF 1024
/************关于本文档********************************************
// *filename: ssync-client.c
*purpose: 演示网络异步通讯,这是客户端程序
*wrote by: zhoulifa(zhoulifa@163.com) 周立发(http://zhoulifa.bokee.com )
Linux爱好者 Linux知识传播者 SOHO族 开发者 最擅长C语言
*date time:2007-01-25 21:32
*Note: 任何人可以任意复制代码并运用这些文档,当然包括你的商业用途
* 但请遵循GPL
*Thanks to: Google.com
*Hope:希望越来越多的人贡献自己的力量,为科学技术发展出力
* 科技站在巨人的肩膀上进步更快!感谢有开源前辈的贡献!
*********************************************************************/
int main( int argc, char **argv)
{
     int sockfd, len;
     struct sockaddr_in dest;
     char buffer[MAXBUF + 1];
     fd_set rfds;
     struct timeval tv;
     int retval, maxfd = -1;
 
     if (argc != 3) {
         printf
             ( "参数格式错误!正确用法如下:\n\t\t%s IP地址 端口\n\t比如:\t%s 127.0.0.1 80\n此程序用来从某个 IP 地址的服务器某个端口接收最多 MAXBUF 个字节的消息" ,
              argv[0], argv[0]);
         exit (0);
     }
     /* 创建一个 socket 用于 tcp 通信 */
     if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
         perror ( "Socket" );
         exit ( errno );
     }
 
     /* 初始化服务器端(对方)的地址和端口信息 */
     bzero(&dest, sizeof (dest));
     dest.sin_family = AF_INET;
     dest.sin_port = htons( atoi (argv[2]));
     if (inet_aton(argv[1], ( struct in_addr *) &dest.sin_addr.s_addr) == 0) {
         perror (argv[1]);
         exit ( errno );
     }
 
     /* 连接服务器 */
     if (connect(sockfd, ( struct sockaddr *) &dest, sizeof (dest)) != 0) {
         perror ( "Connect " );
         exit ( errno );
     }
 
     printf
         ( "\n准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方\n" );
     while (1) {
         /* 把集合清空 */
         FD_ZERO(&rfds);
         /* 把标准输入句柄0加入到集合中 */
         FD_SET(0, &rfds);
         maxfd = 0;
         /* 把当前连接句柄sockfd加入到集合中 */
         FD_SET(sockfd, &rfds);
         if (sockfd > maxfd)
             maxfd = sockfd;
         /* 设置最大等待时间 */
         tv.tv_sec = 1;
         tv.tv_usec = 0;
         /* 开始等待 */
         retval = select(maxfd + 1, &rfds, NULL, NULL, &tv);
         if (retval == -1) {
             printf ( "将退出,select出错! %s" , strerror ( errno ));
             break ;
         } else if (retval == 0) {
             /* printf
                ("没有任何消息到来,用户也没有按键,继续等待……\n"); */
             continue ;
         } else {
             if (FD_ISSET(sockfd, &rfds)) {
                 /* 连接的socket上有消息到来则接收对方发过来的消息并显示 */
                 bzero(buffer, MAXBUF + 1);
                 /* 接收对方发过来的消息,最多接收 MAXBUF 个字节 */
                 len = recv(sockfd, buffer, MAXBUF, 0);
                 if (len > 0)
                     printf
                         ( "接收消息成功:'%s',共%d个字节的数据\n" ,
                          buffer, len);
                 else {
                     if (len < 0)
                         printf
                             ( "消息接收失败!错误代码是%d,错误信息是'%s'\n" ,
                              errno , strerror ( errno ));
                     else
                         printf ( "对方退出了,聊天终止!\n" );
                     break ;
                 }
             }
             if (FD_ISSET(0, &rfds)) {
                 /* 用户按键了,则读取用户输入的内容发送出去 */
                 bzero(buffer, MAXBUF + 1);
                 fgets (buffer, MAXBUF, stdin);
                 if (!strncasecmp(buffer, "quit" , 4)) {
                     printf ( "自己请求终止聊天!\n" );
                     break ;
                 }
                 /* 发消息给服务器 */
                 len = send(sockfd, buffer, strlen (buffer) - 1, 0);
                 if (len < 0) {
                     printf
                         ( "消息'%s'发送失败!错误代码是%d,错误信息是'%s'\n" ,
                          buffer, errno , strerror ( errno ));
                     break ;
                 } else
                     printf
                         ( "消息:%s\t发送成功,共发送了%d个字节!\n" ,
                          buffer, len);
             }
         }
     }
     /* 关闭连接 */
     close(sockfd);
     return 0;
}

编译用如下命令:
gcc -Wall async-server.c -o server
gcc -Wall async-client.c -o client
运行用如下命令:
./server 7838 1
./client 127.0.0.1 7838

分享到:
评论

相关推荐

    Linux网络编程-异步通讯聊天程序.pdf )

    文档《Linux网络编程-异步通讯聊天程序.pdf》为我们提供了一个使用C语言编写的异步通讯聊天程序示例,这个示例使用了select模型来处理多路复用的socket通信,下面将详细介绍相关知识点。 ### Linux网络编程基础 ...

    异步通讯聊天程序

    【异步通讯聊天程序】是一种通信模式,其中通信的任何一方都可以随时发送消息,并且当有新消息到达时,系统会通知接收方进行接收。在Linux环境下,这种异步通信通常通过`select`函数实现。`select`函数允许程序监控...

    Liniux 下面聊天程序

    在给定的压缩包“异步通讯聊天程序”中,可能包含了实现这些步骤的源代码和相关文档。通过阅读和分析这些文件,你可以更深入地了解异步聊天程序的内部工作原理,包括错误处理、数据编码解码、线程同步等细节。 总之...

    tcp_sigio异步通讯代码

    TCP_SigIO是一种在Unix/Linux系统中实现异步I/O通信的方法,它结合了套接字(socket)和信号(signal)机制,使得程序可以在不阻塞的情况下处理网络通信。这个压缩包文件“sigio”可能包含了一段示例代码,用于演示...

    NetMsgClient.rar_聊天_聊天程序

    【标题】"NetMsgClient.rar_聊天_聊天程序"指的是一个网络消息客户端的压缩文件,这个客户端设计用于与服务器端的聊天程序进行交互,实现用户间的实时通讯功能。"聊天"和"聊天程序"标签进一步确认了这个软件的主要...

    两个qq聊天实例

    本主题将深入探讨“两个qq聊天实例”,主要关注企业QQ系统和网络通讯版QQ,以及它们如何利用socket通讯技术实现高效的信息传输。 首先,我们来看企业QQ系统。这是一个专为企业设计的即时通讯工具,它提供了与普通QQ...

    linux-chatroom.rar_Chatroom_chatroom c Linux_linux 聊天室_linux 鑱婂ぉ

    在本项目中,我们主要探讨的是如何在Linux操作系统环境下,利用网络编程技术构建一个聊天室。这个聊天室不仅提供基本的即时通讯功能,还具备了对聊天内容进行管理的能力,尤其是针对不健康信息的过滤。这是一项对于...

    仿QQ2008聊天程序(c#源码) - .Net源码 - C#

    标题中的“仿QQ2008聊天程序(c#源码)”指的是一个基于C#编程语言开发的聊天应用程序,它的设计灵感来源于2008年版本的腾讯QQ,一个在中国广泛流行的即时通讯软件。这个程序旨在提供类似QQ的功能,如文本聊天、文件...

    计算机网络socket编程

    我们将主要讨论如何在Linux环境下使用C语言编写客户端和服务器端的Socket程序。 首先,让我们来看看`im_serv.c`和`im_cli.c`这两个源文件。它们分别代表服务器端和客户端的主程序代码。在服务器端,`im_serv.c`通常...

    聊天室程序设计报告聊天室程序设计报告.doc

    实验的目的在于熟悉Socket通讯机制,理解网络程序设计方法,以及掌握TCP协议的网络通讯。 1. **C/S模式** C/S模式(Client/Server模式)是一种常见的网络架构,其中服务器为多个客户端提供服务。并发性是C/S模式的...

    即时通讯APP源码 IM聊天社交APP+ios可上架+安卓苹果双端+pc端+H5端+微信端

    APP 端历史聊天记录、图片以及前台程序缓存在本地,页面秒开,支持云端同步聊天记录,断网状态页面之间也可以切换,流畅性媲美原生。 技术路线: 后台开发语言:PHP (原生架构) 前台开发语言:uniapp socket 推送...

    TCPSocket.zip

    在实际编程中,为了处理并发连接,通常会使用多线程或者异步I/O模型,如IOCP(I/O完成端口)或者epoll在Linux下。同时,为了防止资源泄露,需要妥善处理异常情况,确保在任何情况下都能正确关闭Socket。 总的来说,...

    linux网络基础编程示例

    实现一个简单的即时通讯程序需要理解多线程或异步I/O模型,如epoll或select/poll,以处理多个并发用户。开发者需要设计一套消息协议,用于客户端和服务器之间的数据交换。这可能涉及文本聊天、文件传输等功能,同时...

    Socket开发资料

    Socket开发是计算机网络编程中的重要组成部分,主要用于实现进程间的通信,尤其在网络应用中,如Web服务器、邮件系统、在线聊天软件等。这份“Socket开发资料”涵盖了Socket编程的基础概念、API使用方法以及常见问题...

    使用UDP通讯的语音聊天代码

    本文将深入探讨一个基于UDP(User Datagram Protocol)实现的语音聊天程序。这个程序能够捕捉麦克风输入的声音数据,并通过UDP协议进行双向全双工(Full Duplex)传输,确保双方可以同时进行语音交流,提供类似电话...

    C#聊天软件

    【C#聊天软件】是一种基于C#编程语言开发的即时通讯工具,它的设计灵感来源于流行的QQ聊天软件,旨在实现类似的功能,如用户注册、登录、发送消息、接收消息以及在线状态显示等。这款软件的核心技术涉及到C#语言、...

    NetCoreServer:超快速和低延迟异步套接字服务器和客户端C#.NET Core库,支持TCP,SSL,UDP,HTTP,HTTPS,WebSocket协议和10K连接问题解决方案

    内容产品特点跨平台(Linux,OSX,Windows) 异步通讯支持的传输协议: , , , 支持的Web协议: , , , 支持的迭代文档要求Linux OSX Windows 10可选的:如何建造?设置库git clone ...

    java 聊天软件

    - **Socket编程**:Java聊天软件的核心是网络通信,这通常涉及使用Java的Socket类,它允许程序通过TCP/IP协议发送和接收数据。 - **多线程**:为了实现即时通讯,软件需要处理多个并发连接,这就需要用到Java的多...

    基于C++的聊天系统客户端

    4. **异步I/O**:考虑到性能和用户体验,客户端可能采用异步I/O模型,如IOCP(I/O完成端口)或epoll在Linux系统中,来避免阻塞等待网络I/O操作。这允许客户端在等待数据时执行其他任务,提高效率。 5. **数据序列化...

    C++构建的聊天软件客户端源代码

    【描述】"本程序是用C++构建的聊天软件的客户端的源代码"表明这是一个实际的、可运行的程序,提供了完整的源代码供学习和研究。客户端通常是用户与服务器进行交互的部分,负责显示消息、发送输入、处理用户界面事件...

Global site tag (gtag.js) - Google Analytics