socket通信之最简单的I/O 多路复用

在Linux/UNIX 下,有下面这五种I/O 操作方式:
1.阻塞 I/O
2. 非阻塞 I/O
3.I/O 多路复用
4.信号驱动 I/O(SIGIO)
5.异步 I/O

至于每种模式的含义自己去查吧,百度百科、wiki百科介绍的都很详细,要是介绍的话,我也就是抄袭过来,要学会使用搜索引擎~~

还记得上一篇文章的例子吧,那就是基于阻塞I/O模式的,简单的不能再简单的socket通信,写那篇主要是为了对socket通信有个简单的认识及明白各个函数的使用方法,以下是为更深一步做基础。

这篇要介绍下I/O多路复用,重要的函数:

1.select()

#include <sys/time.h>

#include <unistd.h>

int select(int maxfd,fd_set *rdset,fd_set *wrset,fd_set *exset,struct timeval *timeout);

参数maxfd是需要监视的最大的文件描述符值+1;

rdset,wrset,exset分别对应于需要检测的可读文件描述符的集合,可写文件描述符的集 合及异常文件描述符的集合。

struct timeval结构用于描述一段时间长度,如果在这个时间内,需要监视的描述符没有事件发生则函数返回,返回值为0。

注意:关于返回值问题,若有就绪描述符则为其数目,若超时则为0,若出错则为1

2.几个重要的宏

FD_CLR(inr fd,fd_set* set);用来清除描述词组 set中相关 fd的位 
FD_ISSET(int fd,fd_set *set);用来测试描述词组 set中相关 fd的位是否为真 
FD_SET(int fd,fd_set*set);用来设置描述词组 set中相关 fd的位 
FD_ZERO(fd_set *set);用来清除描述词组 set的全部位参数

3.一个重要的结构体
timeout为结构 timeval,用来设置 select()的等待时间,其结构定义如下:
struct timeval

 time_t tv_sec; 
 time_t tv_usec;
};
下面是常见的程序片段
  fs_set readset;
  FD_ZERO(&readset);
  FD_SET(fd,&readset);
  select(fd+1,&readset,NULL,NULL,NULL);
  if(FD_ISSET(fd,readset){……}

完成的代码例子:

[cpp]  view plain copy
  1. #include <stdio.h>  
  2. #include <sys/time.h>     
  3. #include <sys/types.h>    
  4. #include <unistd.h>       
  5. #define TIMEOUT 5 /* select timeout in seconds *  
  6. #define BUF_LEN 1024 /* read buffer in bytes */   
  7. int main (void)     
  8. {   
  9.     struct timeval tv;  
  10.     fd_set readfds;     
  11.     int ret;    
  12.     /* Wait on stdin for input. */    
  13.     FD_ZERO(&readfds);  
  14.     FD_SET(STDIN_FILENO, &readfds);   
  15.     /* Wait up to five seconds. */    
  16.     tv.tv_sec = TIMEOUT;      
  17.     tv.tv_usec = 0;     
  18.     /* All right, now block! */       
  19.     ret = select (STDIN_FILENO + 1,&readfds,NULL,NULL,&tv);  
  20.     if (ret == -1)   
  21.     {    
  22.         perror("select");   
  23.         return 1;   
  24.     }   
  25.     else if (!ret)   
  26.     {    
  27.         printf ("%d seconds elapsed.\n", TIMEOUT);        
  28.         return 0;   
  29.     }   
  30.     /* 
  31.     * Is our file descriptor ready to read?  
  32.     * (It must be, as it was the only fd that        
  33.     * we provided and the call returned      
  34.     * nonzero, but we will humor ourselves.) 
  35.     */  
  36.     if (FD_ISSET(STDIN_FILENO, &readfds))   
  37.     {   
  38.         char buf[BUF_LEN+1];  
  39.         int len;  
  40.         /* guaranteed to not block */     
  41.         len = read (STDIN_FILENO, buf, BUF_LEN);  
  42.         if (len == -1)   
  43.         {    
  44.             perror ("read");    
  45.             return 1;   
  46.         }   
  47.         if (len)   
  48.         {  
  49.             buf[len]='\0';      
  50.             printf ("read: %s\n", buf);       
  51.         }   
  52.         return 0;   
  53.     }   
  54.     fprintf (stderr, "This should not happen!\n");    
  55.     return 1;   
  56. }   

代码不是很长,是一个最简单的例子,很好理解。



FROM; http://blog.csdn.net/xluren/article/details/8045028


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用C语言编写Web服务器可以使用I/O多路复用技术提高服务器的性能和并发能力。以下是基于Linux下的I/O多路复用的Web服务器实现步骤: 1. 创建socket并绑定IP地址和端口号 2. 将socket设置为非阻塞模式 3. 创建epoll句柄,并将socket加入epoll监听列表中 4. 进入事件循环,等待客户端连接请求 5. 当有客户端连接请求到来时,使用accept函数接受连接,并将新连接加入epoll监听列表中 6. 当有读写事件到来时,使用recv和send函数进行读写操作 7. 关闭连接,从epoll监听列表中删除连接 下面是一个简单的示例代码: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <arpa/inet.h> #include <sys/socket.h> #include <sys/epoll.h> #define MAX_EVENTS 1024 #define BUFFER_SIZE 1024 int main(int argc, char *argv[]) { struct sockaddr_in address; int listenfd, connfd, epollfd, nfds, n, i; char buffer[BUFFER_SIZE]; struct epoll_event ev, events[MAX_EVENTS]; if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("socket"); exit(1); } memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(INADDR_ANY); address.sin_port = htons(8080); if (bind(listenfd, (struct sockaddr *)&address, sizeof(address)) == -1) { perror("bind"); exit(1); } if (listen(listenfd, 5) == -1) { perror("listen"); exit(1); } if ((epollfd = epoll_create(1)) == -1) { perror("epoll_create"); exit(1); } ev.events = EPOLLIN; ev.data.fd = listenfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listenfd, &ev) == -1) { perror("epoll_ctl"); exit(1); } while (1) { nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1); if (nfds == -1) { perror("epoll_wait"); exit(1); } for (i = 0; i < nfds; i++) { if (events[i].data.fd == listenfd) { if ((connfd = accept(listenfd, (struct sockaddr *)NULL, NULL)) == -1) { perror("accept"); exit(1); } ev.events = EPOLLIN | EPOLLET; ev.data.fd = connfd; if (epoll_ctl(epollfd, EPOLL_CTL_ADD, connfd, &ev) == -1) { perror("epoll_ctl"); exit(1); } } else { if ((n = recv(events[i].data.fd, buffer, BUFFER_SIZE, 0)) <= 0) { close(events[i].data.fd); continue; } buffer[n] = '\0'; printf("Received message: %s\n", buffer); if (send(events[i].data.fd, buffer, n, 0) == -1) { perror("send"); exit(1); } } } } close(listenfd); close(epollfd); return 0; } ``` 此示例代码只是一个简单的Web服务器,可以作为你自己的Web服务器的基础框架。如果需要更完善的功能,你需要进一步完善代码。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值