通过三种方法实现IO多路复用,核心框架

一.通过三种方法实现IO多路复用,核心框架
1.select(监测个数,读事件地址,写事件地址,异常事件地址,超时检测地址)
//1.创建表
fd_set readfds,tempfds;
//2.清空表
FD_ZERO readfds;
//3.将关心的描述符写入表(根据描述符的数字写入对应下标)
FD_SET(0,&readfds);
FD_SET(sockfd,&readfds);
//4.定义变量存最大下标
int maxfd=sockfd;
//5.判断是哪个描述符产生了事件
while(1)
 {  
   tempfds=readfds;//表还原
    //调用select函数
   int set=select(maxfd+1,&tempfds,NULL,NULL,NULL);//第二个参数是结构体首地址
        //判断是哪个描述符产生了事件
   if(FD_ISSET(0,&tempfds))
    {
      fgets(buf,sizeof(buf),stdin);
      printf("key:%s\n",buf);
    }
   if(FD_ISSET(sockfd,&tempfds))
    {
       int acceptfd=accept(sockfd,(struct sockaddr *)&caddr,&len);
       //将通过链接产生的通信描述符写入表中
       FD_SET(acceptfd,&readfds);
       if(maxfd < acceptfd)
           maxfd=acceptfd;
    }
   for(int i=4;i<=maxfd;i++)
     {
         //判断通信描述符此时是否产生事件
         if(FD_ISSET(i,&tempfds));
         int ret=recv(i,buf,sizeof(buf),0);
         if(ret < 0)
           {
             perror("recv err.\n");
             return -1; 
           }
         else if(ret == 0)
           {
             printf("%d:client exit\n",i);//谁退了
             close(i);
             FD_CLR(i,&readfds);
             if(maxfd == i)
                  maxfd--;
           }
         else
           {
             printf("%d:%s\n",i,buf);//接受的谁的信号
           }
      }
 }
close(sockfd);
return 0;

2.poll(数组,个数,超时检测)
//表(顺序表)
struct pollfd fds[100]={};
//写入表
fds[0].fd=0;
fds[0].events=POLLIN;//读事件系列
fds[1].fd=sockfd;
fds[1].events=POLLIN;
//定义变量存放最后一个描述符所在位置下标
int last=1;
//循环遍历是否发生事件
while(1)
{
    //调用poll函数
        poll(fds,last+1,-1);
    for(int i=0;i<=last;i++)
       //先判断所有描述符是否有发生事件的
         {
              if(fds[i].revents==POLLIN)
               {
              //再判断是谁发生了事件,再做出对应的逻辑处理
                   if(fds[i].fd==0)
                     {
                     fgets(buf,sizeof(buf),stdin);
                     printf("key:%s\n",buf);
                     }
                    else if(fds[i].fd==sockfd)
                     {
                      int acceptfd=accept(sockfd,(struct sockaddr *)&caddr,&len);
                      last++;
                      fds[last].fd=acceptfd;
                      fds[last].events=POLLIN;
                     }
                    else
                     {
                      int ret=recv(fds[i].fd,buf,sizeof(buf),0);
                      if(ret < 0)
                        {
                           perror("recv err.");
                           return -1;
                        }
                      else if(ret == 0)
                        {
                           printf("%d:client exit\n",fds[i].fd);
                           close(fds[i].fd);
                           fds[i]=fds[last];
                           last--;
                           i--;//得在for循环里重新判断一下i所在位置
                         }
                      else
                         {
                            printf("%d:%s\n",fds[i].fd,buf);
                         }
                 
                   }
           }
  }
close(sockfd);
return 0;

3. epoll_ctl(树根,操作,描述符,事件地址)
//1.建树
int epfd=epoll_create(1);
//2.构建结构体暂时存放写入关心的文件描述符
struct epoll_event event;
//3.填充结构体
event.data.fd=0;
event.events=EPOLLIN|EPOLLET;

event.data.fd=sockfd;
event.events=EPOLLIN|EPOLLET;
//4.上树
epoll_ctl(epfd,EPOLL_CTL_ADD,0,&event);//第四个参数是结构体指针,传结构体首地址
epoll_ctl(epfd,EPOLL_CTL_ADD,sockffd,&event);

//5.构建结构体暂时保存发生事件的event集合
struct epoll_event events[20];
//6.判断是哪些描述符发生了事件
while(1)
{
   //调用函数,列出发生事件的描述符,对描述符做对应的逻辑处理
    int wt=epoll_wait(epfd,events,20,-1);//第二个参数也是地址,数组的首地址是数组名
    for(int i=0;i<wt;i++)
      {
         if(events[i].data.fd==0)
        {
             fgets(buf,sizeof(buf),stdin);
             printf("key:%s\n",buf);
           }
         else if(events[i].data.fd==sockfd)
           {
             int acceptfd=accept(sockfd,(struct sockaddr *)&caddr,&len);
             //上树
             event.data.fd=acceptfd;
             event.events=EPOLLIN|EPOLLET;
             epoll_ctl(efds,EPOLL_CTL_ADD,acceptfd,&event);
           }
         else
           {
              int recvtype=recv(events[i].data.fd,buf,sizeof(buf),0);//0:阻塞
              if(recvtype < 0)
                {
                   perror("recv err.");
                   return -1;
                }
              else if(recvtype == 0)
                {
                    printf("%d   client exit\n",events[i].data.fd);//谁退了
                    close(events[i].data.fd);
                    epoll_ctl(epfd,EPOLL_CTL_DEL,events[i].data.fd,NULL);//下树不用传事件
                }
               else
                {
                     printf("%d:%s\n",events[i].data.fd,buf);//打印谁
                }
             }
      }
}
close(sockfd);
return 0;       

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Java中,使用`select`多路复用技术的代码通常是基于Java NIO(New I/O)库来实现的。这个库提供了`Selector`类,用于实现多路复用。 然而,需要注意的是,在Windows操作系统上,`select`函数只能用于套接字,而不能用于文件句柄。因此,在Windows中使用`select`多路复用技术时,需要借助一些额外的库或框架实现。 一个常见的选择是使用Java NIO的替代库,比如Netty。Netty是一个异步事件驱动的网络应用程序框架,提供了高性能的网络编程和多路复用功能。它可以在Windows上使用`select`多路复用技术,并且对开发者来说更加友好和方便。 以下是一个简单的使用Netty实现多路复用示例代码: ```java import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; public class MultiplexingServer { public static void main(String[] args) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // 添加处理器 ch.pipeline().addLast(new MyHandler()); } }); ChannelFuture channelFuture = serverBootstrap.bind(8080).sync(); channelFuture.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } } ``` 在这个示例中,我们使用了Netty框架来创建一个基于NIO的服务器。通过`NioEventLoopGroup`和`NioServerSocketChannel`来实现多路复用。然后,我们通过`ChannelInitializer`来添加自定义的处理器(`MyHandler`)来处理请求。 这只是一个简单的示例,实际使用中可能需要根据具体需求和业务逻辑进行调整和优化。同时,也可以尝试其他类似的库或框架实现多路复用功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bug解决中

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值