io多路复用

本文详细介绍了如何使用C语言通过select和poll方法实现服务器端的IO多路复用,包括创建套接字、设置端口重用、绑定地址、监听客户端连接请求以及处理客户端交互和服务器通信。
摘要由CSDN通过智能技术生成

select实现io多路复用服务器

#include <myhead.h>
#define  SER_IP  "192.168.125.171" //服务器IP地址
#define  SER_PORT  8888            //服务器端口号


int main(int argc, const char *argv[])
{

    //1.创建套接字:用于接收客户端链接请求
    int sfd =socket(AF_INET,SOCK_STREAM,0);
    if(sfd == -1){
        perror("socket error");
        return -1;
    }
    printf("%d\n",sfd);

    //设置端口号快速重用
    int reuse =1;

    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");

   //2.绑定IP地址和端口号
   //2.1填充地址信息结构体
   struct sockaddr_in  buf;
   buf.sin_family =AF_INET;  //地址族
   buf.sin_port=htons(SER_PORT);//端口号
   buf.sin_addr.s_addr = inet_addr(SER_IP); //IP地址

   //2.2绑定工作
   int n=bind(sfd,(struct sockaddr*)&buf,sizeof(buf));
   if(n==-1){
       perror("bind");
       return 1;
   }
   printf("%#x\n",buf.sin_family);
   
  // 3.将套接字设置成被动监听状态
   if(listen(sfd,128)==-1){
      perror("listen ");
   }
   printf("listen success\n");

   //4. 阻塞等待客户端连接请求
   //定义地址信息结构体变量用于接收客户端的地址信息
   struct sockaddr_in cin_arr[1024];
   struct sockaddr_in cin;
   socklen_t socklen =sizeof(cin);

   fd_set readfds,tempfds;

   FD_ZERO(&readfds);

   FD_SET(0,&readfds);
   FD_SET(sfd,&readfds);

   int maxfd =sfd;
   while(1){


       tempfds=readfds;
       int res =select(maxfd+1,&tempfds,NULL,NULL,NULL);
       if(res==0)
       {
         printf("time out\n");
         return-1;
       }else if(res ==-1)
        {
            perror("select error");
            return -1;

       }
      for(int i=0;i<=maxfd;i++)
      {
          if(!FD_ISSET(i,&tempfds))
          {
           continue;

          }
     
      if(i==sfd)
      {
          int newfd =accept(sfd,(struct sockaddr*)&cin,&socklen);
        if(newfd ==-1){
          perror("accept error");
         return 1;
         }
        printf("[%s:%d]:已连接,newfd=%d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),newfd);
    
        FD_SET(newfd,&readfds);
        cin_arr[newfd]=cin;
        if(maxfd<newfd)
        { 
          maxfd =newfd;

        }
      }
      else if(i ==0)
      {
         char buf[128]="";
         fgets(buf,sizeof(buf),stdin);
         buf[strlen(buf)-1]=0;
         printf("触发键盘输入事件:%s\n",buf);

         for(int i=4;i<=maxfd;i++)
         {
         send(i,buf,sizeof(buf),0);
         }

      }
      
     else 
      {
        char rbuf[128]="";//用于接收消息
        bzero(rbuf,sizeof(rbuf));
        int ret =recv(i,rbuf,sizeof(rbuf),0);
        if(ret == 0)
        {
            printf("客户端已下线\n");
            close(i);
            FD_CLR(i,&readfds);
            for(int j=maxfd;j<sfd;j--)
            {
              if(FD_ISSET(j,&readfds))
              {
                 maxfd=j;
                 break;
              }

            }
            continue;
        }
        printf("[%s:%d]:rbuf=%s\n",inet_ntoa(cin_arr[i].sin_addr),ntohs(cin_arr[i].sin_port),rbuf);
     
        for(int i=4;i<=maxfd;i++)
        {
           send(i,rbuf,strlen(rbuf),0);
        }
      }
     }
   }
   close(sfd);
   return 0;
}
 

poll实现多路复用客服端

#include <myhead.h>
#define  SER_IP  "192.168.125.171" //服务器IP地址
#define  SER_PORT  8888            //服务器端口号
#define  CLI_IP   "192.168.125171" //客户端IP地址
#define  CLI_PORT   9999            //客户端端口号

int main(int argc, const char *argv[])
{

    //1.创建套接字:用于接收客户端链接请求
    int sfd =socket(AF_INET,SOCK_STREAM,0);
    if(sfd == -1){
        perror("socket error");
        return -1;
    }
    printf("%d\n",sfd);

    //设置端口号快速重用
    int reuse =1;

    if(setsockopt(sfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){
        perror("setsockopt error");
        return -1;
    }
    printf("端口号快速重用成功\n");

   //2.绑定IP地址和端口号
   //2.1填充地址信息结构体
   struct sockaddr_in  buf;
   buf.sin_family =AF_INET;  //地址族
   buf.sin_port=htons(CLI_PORT);//端口号
   buf.sin_addr.s_addr = inet_addr(CLI_IP); //IP地址

   //2.2绑定工作
   int n=bind(sfd,(struct sockaddr*)&buf,sizeof(buf));
   if(n==-1){
       perror("bind");
       return 1;
   }
   printf("bind success\n");

  
   //3连接服务器
  
   struct sockaddr_in cin;
   cin.sin_family=AF_INET;
   cin.sin_port= htons(SER_PORT);//服务器端口号
   cin.sin_addr.s_addr = inet_addr(SER_IP);//服务器IP地址


   //4.连接服务器
   if(connect(sfd,(struct sockaddr*)&cin,sizeof(cin))==-1)
   {
      perror("connect error");
      return -1;
   }
   printf("connect success\n");
  
   //创建一个用于检测文件的描述符的容器
   struct pollfd pfds[2];

   pfds[0].fd =0;//表示第一个元素检测0号文件描述符
   pfds[0].events =POLLIN; //要检测0号文件描述符的读事件
   

   pfds[1].fd =sfd;//表示第二个元素检测cfd号文件描述符
   pfds[1].events =POLLIN; //要检测cfd号文件描述符的读事件

   //5.数据的收发
   char wbuf[128]="";
   while(1)
   {
       int res =poll(pfds,2,-1);//阻塞检测文件描述符集合中是否有事件产生
       if(res == -1)
       {
         perror("poll error");
         return -1;
       }
       else if(res == 0)
       {
           printf("time out\n");
           return -1;
       }
       //程序执行至此,说明集合中有事件产生,接下来根据不同的事件,执行不同的函数即可
       if(pfds[0].revents == POLLIN)//判断是否为终端输入
       {
           //从终端获取数据
           fgets(wbuf,sizeof(wbuf),stdin);
           wbuf[strlen(wbuf)-1]=0;
           if(strcmp(wbuf,"quit")==0)
           {
              break;

           }
           //将数据发送给服务器
           send(sfd,wbuf,sizeof(wbuf),0);
       }
      //判断是否为服务器发来消息
      if(pfds[1].revents==POLLIN)
      {
          //接收服务器发来的消息
          bzero(wbuf,sizeof(wbuf));
          recv(sfd,wbuf,sizeof(wbuf),0);
          printf("收到服务器的消息为:%s\n",wbuf);

      }

   }
   close(sfd);
   return 0;
}
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值