Linux下socket异步通讯聊天程序
Linux下socket异步通讯聊天程序(转)
original from: http://yangqi.org/linux-socket-asynchronous-im-system/
网络课的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; } |