当前位置: 首页 > news >正文

定制网站建设公司排行大兴今日头条新闻

定制网站建设公司排行,大兴今日头条新闻,产业园网站建设方案,医院做网站的好处三种多路IO转接方法&#xff1a;select &#xff0c; poll &#xff0c; epoll 改进select多路IO转接&#xff0c;使用数组来保存含有需要连接的套接字cfd&#xff0c;不用循环至1024&#xff0c;节约时间提高效率。 #include<stdio.h> #include<stdlib.h> #in…

三种多路IO转接方法:select , poll  , epoll

改进select多路IO转接,使用数组来保存含有需要连接的套接字cfd,不用循环至1024,节约时间提高效率。 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#define SER_PORT 9003
void sys_err(char* s)
{perror(s);exit(1);
}int main(int argc , char *argv[])
{int cfd , lfd , maxi;int client[FD_SETSIZE] ;char buf[BUFSIZ] , str[INET_ADDRSTRLEN];struct sockaddr_in serv_addr , clit_addr;socklen_t clit_addr_len;bzero(&serv_addr , sizeof(serv_addr));serv_addr.sin_family = AF_INET;serv_addr.sin_port = htons(SER_PORT);serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);lfd = socket(AF_INET , SOCK_STREAM , 0);if(lfd == -1)sys_err("socket error");int opt = 1;setsockopt(lfd , SOL_SOCKET , SO_REUSEADDR , (void*)&opt , sizeof(opt));int ret = bind(lfd , (struct sockaddr*)&serv_addr , sizeof(serv_addr));if(ret == -1)sys_err("bind error");listen(lfd , 128);fd_set rset , allset;int maxfd , i , k , n ,j , m , sockfd;maxfd = lfd;maxi = -1;for(j = 0 ; j < 1024 ; j++)client[j] = -1;FD_ZERO(&allset);FD_SET(lfd , &allset);while(1){rset = allset;clit_addr_len = sizeof(clit_addr);ret = select(maxfd + 1 , &rset , NULL , NULL , NULL);if(ret < 0){sys_err("select error");}else if(ret > 0){if(FD_ISSET(lfd , &rset)){cfd = accept(lfd , (struct sockaddr*)&clit_addr , &clit_addr_len);if(cfd == -1)sys_err("accept error");printf("--received from %s at port %d\n" , inet_ntop(AF_INET , &clit_addr.sin_addr.s_addr , str , sizeof(str)) , ntohs(clit_addr.sin_port));for( m = 0 ; m < 1024 ;m++){if(client[m] < 0){client[m] = cfd;break;}}if( m == 1023){printf("too many clients\n");exit(1);}if(m > maxi)maxi = m;FD_SET(cfd , &allset);if(maxfd < cfd)maxfd = cfd ;if(ret == 1)continue;}for(i = lfd + 1 ; i <= maxi ; i++){if((sockfd = client[i]) < 0 )continue;if(FD_ISSET(sockfd , &rset)){n = read(sockfd , buf , sizeof(buf));if(n == 0){close(i);FD_CLR(sockfd , &allset);client[i] = -1;}else if( n > 0){for( k = 0 ; k < n; k++){buf[k] = toupper(buf[k]);}write(STDOUT_FILENO , buf , n);write(sockfd , buf , n);}else{sys_err("read error");}if(ret == 1)break;}}}}close(cfd);return 0 ;
}

poll

int poll(struct pollfd *fds, nfds_t nfds, int timeout);fds:监听的文件描述符数组struct pollfd {int   fd;         //监听的文件描述符short events;     //待监听的文件描述符对应的监听事件取值events : 读POLLIN , 写POLLOUT , 错误POLLERRshort revents;    //传入时,给0,满足对应事件会返回非0-->上述取值};nfds:监听数组的实际有效监听个数
timeout:超时时长,毫秒级等待
-1:阻塞等
0:立即返回,不阻塞进程
>0:等待指定毫秒数返回值:成功返回满足对应监听事件的文件描述符总个数初始化
struct pollfd pfds[1024];
pfds[0].fd = lfd;
pfds[0].events = POLLIN;
pfds[0].revents = 0;

read函数返回值

>0:实际读到字节数

=0:socket中,表示对端关闭。close()

<0:如果errno == EINTR  被异常中断,需要重启 。

     如果errno == EAGIN/EWOULDBLOCK 以非阻塞方式读数据,但是没有数据。需要再次读

     如果errno == ECONNRSET  说明连接被重置 需要close , 移除监听队列。

poll优缺点

优点:

1、自带数组结构,可以将 监听事件 和 返回事件 分离。

2、拓展监听上限。select无法修改,除非重新编译内核。

缺点:

1、不能跨平台。只有Linux和类Unix

2、无法直接定位满足监听事件的文件描述符,编码难度较大

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<ctype.h>
#include<poll.h>
#define SER_PORT 9003void sys_err(char* s)
{perror(s);exit(1);
}int main(int argc , char* argv[])
{int cfd , lfd , sockfd;char buf[BUFSIZ] , str[INET_ADDRSTRLEN];struct sockaddr_in serv_addr , clit_addr ;bzero(&serv_addr , sizeof(serv_addr));socklen_t clit_addr_len;lfd = socket(AF_INET , SOCK_STREAM , 0);if(lfd == -1)sys_err("socket error");int opt = 1 ;setsockopt(lfd , SOL_SOCKET , SO_REUSEADDR , (void*)&opt , sizeof(opt));int ret = bind(lfd , (struct sockaddr*)&serv_addr , sizeof(serv_addr));if(ret == -1)sys_err("bind error");listen(lfd , 128);struct pollfd pfds[1024];int maxi = lfd;pfds[0].fd = lfd;pfds[0].events = POLLIN;int i , n ,k;while(1){ret = poll(pfds , maxi + 1 , -1);if(ret < 0){sys_err("poll error");}else if(ret > 0){if(pfds[0].revents & POLLIN){clit_addr_len = sizeof(clit_addr);cfd = accept(lfd , (struct sockaddr*)&clit_addr , &clit_addr_len);if(cfd == -1)sys_err("accept error");printf("received from %s at PORT %d\n" ,inet_ntop(AF_INET , &clit_addr.sin_addr.s_addr , str ,                     sizeof(str)),ntohs(clit_addr.sin_port));for(i = 0 ; i < 1024 ; i++){if(pfds[i].fd<0){pfds[i].fd = cfd;break;}}if(i == 1024){printf("too many clients\n");exit(1);}if(maxi < i)maxi = i;if(ret == 1)continue;}for(i = 1 ; i <= maxi ; i++){sockfd = pfds[i].fd;if(sockfd < 0)continue;if(pfds[i].revents & POLLIN){n = read(sockfd , buf ,sizeof(buf));if(n == 0){close(sockfd);pfds[i].fd = -1;}else if(n > 0){for(k = 0 ; k < n ; k++){buf[k] = toupper(buf[k]);}write(sockfd , buf , n);write(STDOUT_FILENO , buf , n);}if(ret == 1)break;}}}}return 0 ;
}

突破1024文件描述符限制

cat /proc/sys/fs/file-max  -->当前计算机所能打开的最大文件个数,受硬件影响。

ulimit -a -->当前用户下的进程,默认打开文件描述符个数。1024

修改: sudo vi /etc/security/limits.conf  修改soft 基本不用

* soft nofile 65536 ---> 修改默认值,可直接借助命令修改:ulimit -n 数字(注销用户生效)

* hard nofile 100000 ---> 命令修改上限

epoll实现多路IO转接(重点)

本质是一个平衡二叉树,又是其特例红黑树。

epoll_create

创建一颗监听红黑树

int epoll_create(int size);
size:创建的红黑树的监听节点数量(仅供内核参考)。 返回值:成功返回指向新创建的红黑树的根节点的文件描述符fd
失败-1 ,errno

epoll_ctl(重点) 

操作监听红黑树

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
epfd:epoll_create函数的返回值
op:对该监听红黑树所做的操作EPOLL_CTL_ADD:添加fd到监听红黑树EPOLL_CTL_MOD:修改fd在监听红黑树的监听事件EPOLL_CTL_DEL:将一个fd从监听红黑树上摘下(取消监听)
fd:待监听的fd
event:本质是struct epoll_event类型的结构体 地址events:EPOLLIN EPOLLOUT EPOLLERRdata:联合体共用体int fd; 对应监听事件的fdvoid *ptr;uint32_t u32;uint32_t u64;  返回值 成功0 , 失败-1 errno

epoll_wait

阻塞监听

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);
epfd:epoll_create函数的返回值
events:传出参数【数组】,传出满足监听条件文件描述符结构体
maxevents:数组元素总个数 1024struct epoll_event events[1024];
timeout:超时时长,毫秒级等待
-1:阻塞等
0:立即返回,不阻塞进程
>0:等待指定毫秒数返回值:>0 满足监听的总个数,可以用作循环上限。
=0 , 没有fd满足监听事件
-1 , 失败 errno

流程

lfd = socket();
bind()
listen()int epfd = epoll_create(1024);                //epfd,监听红黑树的树根struct epoll_event tep , ep[1024];            //tep用来设置单个fd的属性,ep是epoll_wait函数传出的满足监听事件的数组
tep.events = EPOLLIN;
tep.data.fd = lfd;epoll_ctl(epfd , EPOLL_CTL_ADD , lfd , &tep); //将lfd添加到监听红黑树上while(1){int ret = epoll_wait(epfd , ep , 1024 , -1);  //实施监听for(i = 0 ; i < ret ; i++){             if(ep[i].data.fd == lfd){cfd = accept();tep.events = EPOLLIN;tep.data.fd = cfd;epoll_ctl(epfd , EPOLL_CTL_ADD , cfd , &tep);}else{                n = read(); if(n == 0){close();epoll_ctl(epfd , EPOLL_CTL_ADD , cfd , NULL); //摘除最后一个不需要初始化了,直接传NULL。}else if(n>0){小-->大write();}}}

使用epoll进行多路IO转接代码

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<sys/epoll.h>
#include<ctype.h>
#define SER_PORT 9004
void sys_err(char* s)
{perror(s);exit(1);
}int main(int argc , char *argv[])
{int lfd , cfd ,epfd , sockfd , i , n , kfd , k;char buf[BUFSIZ],str[INET_ADDRSTRLEN];struct sockaddr_in serv_addr , clit_addr;socklen_t clit_addr_len;bzero(&serv_addr , sizeof(serv_addr));serv_addr.sin_family = AF_INET ;serv_addr.sin_port = htons(SER_PORT);serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);lfd = socket(AF_INET , SOCK_STREAM , 0);if(lfd == -1)sys_err("socket error");int opt = 1;setsockopt(lfd , SOL_SOCKET , SO_REUSEADDR , (void*)&opt , sizeof(opt));int ret = bind(lfd , (struct sockaddr*)&serv_addr , sizeof(serv_addr));if(ret == -1)sys_err("bind error");listen(lfd , 128);epfd = epoll_create(1024);if(epfd == -1)sys_err("epoll_create error");struct epoll_event tep , ep[1024];tep.events = EPOLLIN;tep.data.fd = lfd;ret = epoll_ctl(epfd , EPOLL_CTL_ADD , lfd , &tep);if(ret == -1)sys_err("epoll_ctl error");while(1){kfd = epoll_wait(epfd , ep , 1024 , -1);if(kfd == -1 ){sys_err("epoll_wait error");}else if(kfd > 0){for(i = 0 ; i < kfd ; i++){sockfd = ep[i].data.fd;if(sockfd == lfd){clit_addr_len = sizeof(clit_addr);cfd = accept(lfd,(struct sockaddr*)&clit_addr, &clit_addr_len);if(cfd == -1)sys_err("accept error");printf("------received from %s at port %d------\n" ,inet_ntop(AF_INET, &clit_addr.sin_addr, str ,                 sizeof(str)),ntohs(clit_addr.sin_port));tep.events = EPOLLIN;tep.data.fd = cfd;ret = epoll_ctl(epfd , EPOLL_CTL_ADD , cfd , &tep);if(ret == -1)sys_err("epoll_ctl error");}else{n = read(sockfd , buf , sizeof(buf));if(n == 0){close(sockfd);epoll_ctl(epfd , EPOLL_CTL_DEL , sockfd , NULL);}else if(n > 0){for(k = 0 ; k < n ; k++){buf[k] = toupper(buf[k]);}write(sockfd , buf , n);write(STDOUT_FILENO , buf , n);}else{sys_err("read error");}}}}}return 0 ;
}

感觉epoll有些东西容易和poll弄混,黑马老师说可以只记epoll,在之后基本都是使用到epoll进行多路IO转接。

epoll实现多路IO转接主要是使用3个函数,第一个函数是epoll_create(1024),参数创建的红黑树的监听节点数量(仅供内核参考)。 第二个函数是epoll_ctl(epfd , EPOLL_CTL_ADD/MOD/DEL , lfd/cfd , &tep) , tep初始化是 struct epoll_event tep ; tep.events = EPOLLIN/OUT/ERR; tep.data.fd = lfd/cfd; 将lfd挂到红黑树上之后进行while循环,进行监听,kfd = epoll_wait(epfd , ep , 1024 , -1); ep是结构体数组,初始化为struct epoll_event ep[1024];

随后只需要根据下标取出epoll_wait函数的传出参数ep数组中的元素进行判断。是否是lfd或者是cfd,如果是lfd说明有要连接的客户端,进行accept连接,若是cfd,则说明有客户端进行写操作,服务器则进行相应的读操作以及小写转大写的操作即可。

http://www.cadmedia.cn/news/13267.html

相关文章:

  • 个人网站设计毕业论文10000字营销推广方案怎么写
  • ps做网站导航东莞做网络推广的公司
  • 百度系优化保定百度推广优化排名
  • 网站制作价格甄选乐云践新数字营销软件
  • 网站排名推广软件培训机构招生方案模板
  • 网站建设费摊销年限百度指数手机版
  • 网站生成二维码seo知名公司
  • 邯郸网站设计价位博客网站
  • 郑州免费网站建设哪家好微信公众号怎么做文章推广
  • 绿色科技网站建设写软文推广
  • 网站建设合同用贴印花税吗个人网页怎么制作
  • 网站推广策划方案书站长工具的网址
  • 地方网站收录爱站网关键词挖掘
  • 平台网站建设有哪些方面大连seo
  • 专业网站设计制作过程盐城seo培训
  • 100个无水印短视频素材免费黑帽seo技术论坛
  • 东莞企业网站seo网络公司关键词排名
  • 北京网站开发联系电话2020年百度搜索排名
  • 用ppt做网站方法武汉大学人民医院地址
  • 常宁市住房和城乡建设局网站网站宣传费用
  • 商丘做网站优化全网营销推广 好做吗
  • 辽宁建设厅网站监管处cfa三级和一二级关系大吗
  • 成都网站建设前50强浙江关键词优化
  • 门户网站建设检察搜索引擎竞价广告
  • 企业建站划算吗网络营销的概念及特点
  • 交通部基本建设质量监督网站买域名
  • 北京网站制作公司招聘百度网盘下载速度
  • 需要登陆的网站如何做爬虫天津百度分公司
  • 门户网站编辑流程合肥网络推广网络运营
  • 网站备案信息真实性核验网络营销的特征和功能