Linux网络编程用select实现异步通讯聊天程序

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

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

服务器端源代码如下:
#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
            (
"  ----等待新的连接到来开始新一轮聊天……  " );
        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  " ,
                   inet_ntoa(their_addr.sin_addr),
                   ntohs(their_addr.sin_port), new_fd);

        
/*  开始处理每个新连接上的数据收发  */
        printf
            (
"  准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方  " );
        
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
                   ("没有任何消息到来,用户也没有按键,继续等待…… "); 
*/
                
continue ;
            } 
else  {
                
if  (FD_ISSET( 0 & rfds)) {
                    
/*  用户按键了,则读取用户输入的内容发送出去  */
                    bzero(buf, MAXBUF 
+   1 );
                    fgets(buf, MAXBUF, stdin);
                    
if  ( ! strncasecmp(buf,  " quit " 4 )) {
                        printf(
" 自己请求终止聊天!  " );
                        
break ;
                    }
                    len 
=  send(new_fd, buf, strlen(buf)  -   1 0 );
                    
if  (len  >   0 )
                        printf
                            (
" 消息:%s 发送成功,共发送了%d个字节!  " ,
                             buf, len);
                    
else  {
                        printf
                            (
" 消息'%s'发送失败!错误代码是%d,错误信息是'%s'  " ,
                             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个字节的数据  " ,
                             buf, len);
                    
else  {
                        
if  (len  <   0 )
                            printf
                                (
" 消息接收失败!错误代码是%d,错误信息是'%s'  " ,
                                 errno, strerror(errno));
                        
else
                            printf(
" 对方退出了,聊天终止  " );
                        
break ;
                    }
                }
            }
        }
        close(new_fd);
        
/*  处理每个新连接上的数据收发结束  */
        printf(
" 还要和其它连接聊天吗?(no->退出) " );
        fflush(stdout);
        bzero(buf, MAXBUF 
+   1 );
        fgets(buf, MAXBUF, stdin);
        
if  ( ! strncasecmp(buf,  " no " 2 )) {
            printf(
" 终止聊天!  " );
            
break ;
        }
    }

    close(sockfd);
    
return   0 ;
}
客户端源代码如下:
#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
            (
" 参数格式错误!正确用法如下: %s IP地址 端口 比如: %s 127.0.0.1 80 此程序用来从某个 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
        (
"  准备就绪,可以开始聊天了……直接输入消息回车即可发信息给对方  " );
    
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
               ("没有任何消息到来,用户也没有按键,继续等待…… "); 
*/
            
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个字节的数据  " ,
                         buffer, len);
                
else  {
                    
if  (len  <   0 )
                        printf
                            (
" 消息接收失败!错误代码是%d,错误信息是'%s'  " ,
                             errno, strerror(errno));
                    
else
                        printf(
" 对方退出了,聊天终止!  " );
                    
break ;
                }
            }
            
if  (FD_ISSET( 0 & rfds)) {
                
/*  用户按键了,则读取用户输入的内容发送出去  */
                bzero(buffer, MAXBUF 
+   1 );
                fgets(buffer, MAXBUF, stdin);
                
if  ( ! strncasecmp(buffer,  " quit " 4 )) {
                    printf(
" 自己请求终止聊天!  " );
                    
break ;
                }
                
/*  发消息给服务器  */
                len 
=  send(sockfd, buffer, strlen(buffer)  -   1 0 );
                
if  (len  <   0 ) {
                    printf
                        (
" 消息'%s'发送失败!错误代码是%d,错误信息是'%s'  " ,
                         buffer, errno, strerror(errno));
                    
break ;
                } 
else
                    printf
                        (
" 消息:%s 发送成功,共发送了%d个字节!  " ,
                         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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值