I/O复用初级示例代码

服务端:

#include"common.h"


//存放客户端信息的结构体
typedef struct cli_t
{
    int cfd;
    struct sockaddr_in caddr;
    struct cli_t *next;
}cli_t;


int main()
{
    struct sockaddr_in caddr,saddr;
    int caddr_len;
    int fd,ret;
    int nfd;
    char buf[1024];
    int max_fd;


    cli_t * head =NULL;
    cli_t * pcli;

    fd = socket(AF_INET,SOCK_STREAM,0);
    printf("socket fd = %d\n",fd);
    if(fd < 0)
    {
        perror("socket");
        goto END;
    }


    saddr.sin_family =  AF_INET;
    saddr.sin_port = htons(9000);
    inet_pton(AF_INET,"192.168.6.125",&saddr.sin_addr.s_addr);




    ret = bind(fd,(struct sockaddr *)&saddr,sizeof(saddr));
    printf("bind ret = %d\n",fd);
    if(ret < 0)
    {
        perror("bind");
        goto END;
    }


    ret = listen(fd,100);
    printf("listen ret = %d\n",fd);
    if(ret < 0)
    {
        perror("listen");
        goto END;
    }


    //清空集合
    FD_ZERO(&set);
    //放入集合
    FD_SET(fd,&set);
    max_fd = fd;


    while(1)
    {
        //每次进来用set给rset初始化 保证rset集合里的文件描述符是没受影响的   
        rset = set;
        printf("select...\n");


        //select 可能会对集合里的数据产生影响 所以每次selete里我们用rset集合;

          ret = select(max_fd+1,&rset,NULL,NULL,NULL); 

        //我们要保证程序运行要毫无阻塞的回到select 即监听状态  所以下面的read()前面就加了判定 保证每新连接一个客户端 不用阻塞在read()中,然后回到监听状态 这个时候 由于set已经赋给了rset,所以这个时候客户端如果对服务端执行write()操作,select就会监听到这个动作,并解除阻塞状态  程序往下执行 由于这个动作与fd(即连接客户端)无关,所以会跳过accept这一步,并继续往下走,然后循环遍历链表,发现该nfd在rest这个集合中,不会continue,并执行read操作。read()一次后,会再回到select,客户端写一条,服务端读一条并再回到监听状态。这是和服务端中与read相关的动作,而它一共可以监听两个动作,另外一个就是客户端连接动作,所以该程序一共有两条if(FD_ISSET())判断语句,即如果fd在rset中处于可使用状>态,就会accept,如果nfd在rset中处于可使用状态,即客户端正在给服务端write()时,就会read()。实现在不用多线程或多进程的情况下,一个进程中一个线程的服务端同时为多个客户端服务。

        printf("select over...\n");


        //判断是否有客服端连接的动作  fd是sokect返回值
        if(FD_ISSET(fd,&rset))
        {
           //接收链接
            caddr_len = sizeof(caddr);
            printf("accept...\n");
            nfd = accept(fd,(struct sockaddr *)&saddr,&caddr_len);
            printf("accept over...\n");
            printf("accept nfd = %d\n",nfd);

            //声明集合
            fd_set set,rset;
            //   加入集合
            FD_SET(nfd,&set);


            max_fd = max_fd > nfd ? max_fd : nfd;
            //加入链表
            pcli = malloc(sizeof(struct cli_t));
            pcli->cfd = nfd;
            pcli->caddr = caddr;


            pcli->next = head;

            head = pcli;


        }


        printf("11111\n");
        for(pcli = head;pcli!=NULL;pcli=pcli->next)
        {
            int tfd = pcli->cfd;


            //判断 保证每连接一个客户端 代码走到这里的时候不会被read阻塞
            if(!FD_ISSET(tfd,&rset))
                continue;


            ret = read(tfd,buf,1024);


             if(ret <= 0)
            {
                printf("read ret = 0 tcp broken\n");
                //从集合中移除tfd 防止它一直处于运行状态
                FD_CLR(tfd,&set);


            }
            else
            {
                printf("buf:%s\n",buf);
            }
        }


    }


END:close(fd);
    return 0;








}


客户端:

#include"common.h"




void handler()
{
 printf("recv sigpipe...\n");
 return;
}






int main()
{
 struct sockaddr_in saddr;
 int fd,ret;
 char buf[1024];


 signal(SIGPIPE,handler);


 fd = socket(AF_INET,SOCK_STREAM,0);
 if(fd < 0)
 {
  perror("socket");
  goto END;
 }


 saddr.sin_family = AF_INET;
 saddr.sin_port = htons(9000);
 inet_pton(AF_INET,"192.168.6.125",&saddr.sin_addr.s_addr);


 printf("connet three handshakes now...\n");
 ret = connect(fd,(struct sockaddr *)&saddr,sizeof(saddr));
 if(ret < 0)
 {
  perror("connect");
  goto END;
 }
 printf("connet three handshakes success...\n");


 while(1)
 {
  fgets(buf,1024,stdin);
  ret = write(fd,buf,strlen(buf)+1);
  if(ret < 0)
  {
   perror("write");
   goto END;
  }


 }


END:close(fd);
    exit(-1);


}
~                                                                                                                                                                                                                                                
~                  

                                      


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值