select练习小结
来源:互联网 发布:c 串口编程 编辑:程序博客网 时间:2024/06/11 21:00
<pre name="code" class="cpp">//readwrite.c#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#define MAXLEN 1024struct packet{int len;char content[MAXLEN];};size_t readn(int fd, void *buf, size_t len){ size_t left = len; int ret; char *pbuf = (char *)buf; while(left > 0) { ret = read(fd, pbuf, left); if(ret < 0) { if(errno == EINTR) //遇到中断则继续 continue; return -1; } else if(ret == 0) { return len - left;//对等方结束发送 } left -= ret; pbuf += ret;}return len;}size_t writen(int fd, void *buf, size_t len){ size_t left = len; int ret; char *pbuf = (char *)buf; while(left > 0) { ret = write(fd, pbuf, left); if(ret < 0) { if (errno == EINTR) continue; return 1; } else if(ret == 0) { continue; // 没有写入,则继续 } left -= ret; pbuf += ret; } return len;}// client.c#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include "readwrite.h"size_t doit(int sock){ fd_set rset; FD_ZERO(&rset); int fdmax; int nready; int fd_stdin = fileno(stdin); fdmax = sock > fd_stdin ? sock : fd_stdin; int n; struct packet recvBuf; struct packet sendBuf; while(1) { FD_SET(sock, &rset); FD_SET(fd_stdin, &rset); nready = select(fdmax + 1, &rset, NULL, NULL, NULL); if(nready == -1) { perror("select return -1."); exit(1); } else if(nready == 0) continue;// actually, nready == 0 would NEVER happen, because timeval is NULL else { if(FD_ISSET(sock, &rset)) { memset(&recvBuf, 0, sizeof(recvBuf)); int ret = readn(sock, &recvBuf.len, 4); if(ret == -1) { perror("sock ret -1"); exit(-1); } else if(ret < 4) { perror("client close."); break; } n = ntohl(recvBuf.len); ret = readn(sock, recvBuf.content, n); if(ret == -1) { perror("sock ret -1"); exit(-1); } else if(ret < n) { perror("client close."); break; } fputs(recvBuf.content, stdout); } if(FD_ISSET(fd_stdin, &rset)) { if(fgets(sendBuf.content, sizeof(sendBuf.content), stdin) == NULL) break; n = strlen(sendBuf.content); sendBuf.len = htonl(n); writen(sock, &sendBuf, n + 4); memset(&sendBuf, 0, sizeof(sendBuf)); } }} close(sock);}int main(){ int sock; if((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) perror("socket error!"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6000); servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) { perror("sockect error."); exit(1); } doit(sock); return 0;}//server.c#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <stdlib.h>#include <stdio.h>#include <errno.h>#include <string.h>#include "readwrite.h"void do_srvce(int conn){ int nready; fd_set rset; FD_ZERO(&rset); int fdstdin = fileno(stdin); int maxfd = conn > fdstdin ? conn:fdstdin; struct packet sendBuf; struct packet recvBuf; while(1) { FD_SET(conn, &rset); FD_SET(fdstdin, &rset); nready = select(maxfd + 1, &rset, NULL, NULL, NULL); if(nready == -1) { perror("select ret -1"); exit(-1); } else if(nready == 0) continue; if(FD_ISSET(conn, &rset)) { memset(&recvBuf, 0, sizeof(recvBuf)); int ret = readn(conn, &recvBuf.len, 4); if(ret == -1) { perror("conn ret -1"); exit(-1); } else if(ret < 4) { perror("client close."); break; } int n = ntohl(recvBuf.len); ret = readn(conn, recvBuf.content, n); if(ret == -1) { perror("conn ret -1"); exit(-1); } else if(ret < n) {perror("client close.");break; } fputs(recvBuf.content, stdout); } if(FD_ISSET(fdstdin, &rset)) { if(fgets(sendBuf.content, sizeof(sendBuf.content), stdin) == NULL)break; sendBuf.len = htonl(strlen(sendBuf.content)); writen(conn, &sendBuf, strlen(sendBuf.content) + 4); memset(&sendBuf, 0, sizeof(sendBuf)); }} close(conn);}int main(){ int listenfd; if((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) perror("socket error!"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(6000); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0) perror("bind error!"); if(listen(listenfd, SOMAXCONN) < 0) perror("listen"); struct sockaddr_in peeraddr; socklen_t peerlen = sizeof(peeraddr); int conn; if((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0) { perror("accept error!"); exit(1); } do_srvce(conn); close(listenfd); return 0;}
select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述符就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回则设置timeout结构中的成员值为0),函数返回。当select函数返回后,可以通过遍历fdset,来找到就绪的描述符。
select的几大缺点:
(1)每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时会很大
(2)同时每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大
(3)select支持的文件描述符数量太小了,默认是1024
pollfd结构包含了要监视的event和发生的revent,不再使用select“参数-值”传递的方式。同时,pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。
select和poll都需要在返回后,通过遍历文件描述符来获取已经就绪的socket。事实上,同时连接的大量客户端在一时刻可能只有很少的处于就绪状态,因此随着监视的描述符数量的增长,其效率也会线性下降。
epoll解决了poll的三个缺点:
对于第一个缺点,epoll的解决方案在epoll_ctl函数中。每次注册新的事件到epoll句柄中时(在epoll_ctl中指定EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait的时候重复拷贝。epoll保证了每个fd在整个过程中只会拷贝一次。
对于第二个缺点,epoll的解决方案不像select或poll一样每次都把current轮流加入fd对应的设备等待队列中,而只在epoll_ctl时把current挂一遍(这一遍必不可少)并为每个fd指定一个回调函数,当设备就绪,唤醒等待队列上的等待者时,就会调用这个回调函数,而这个回调函数会把就绪的fd加入一个就绪链表)。epoll_wait的工作实际上就是在这个就绪链表中查看有没有就绪的fd(利用schedule_timeout()实现睡一会,判断一会的效果,和select实现中的第7步是类似的)。
对于第三个缺点,epoll没有这个限制,它所支持的FD上限是最大可以打开文件的数目,这个数字一般远大于2048,举个例子,在1GB内存的机器上大约是10万左右,具体数目可以cat /proc/sys/fs/file-max察看,一般来说这个数目和系统内存关系很大。
- select练习小结
- oracle select 练习
- SELECT超时小结
- jquery操作select小结
- jquery操作select小结
- SELECT超时小结
- Radio、Checkbox、Select小结
- bootstrape select使用小结
- javascript练习,易错点小结
- 3.8 小结与练习
- 生成函数练习小结
- java小结之练习
- 小结:前几个练习
- sqlzoo练习答案--SELECT within SELECT Tutorial
- sqlzoo练习答案--SELECT within SELECT Tutorial
- SQL 练习疑问-SELECT within SELECT Tutorial
- [test]select之having练习
- emp单表select练习
- LeetCode 之 Palindrome Linked List — C++ 实现
- 这些注释太可爱啦!我也要加到我的项目中去!
- 最小生成树之Prim算法
- 超级权限容器
- 设计模式读书笔记:Template Method(模板方法)
- select练习小结
- 队列和栈
- 碰撞检测
- Treap
- Best Time to Buy and Sell Stock II
- 回调函数
- ASP.net Xml
- HDU(1312)
- Python 模拟登陆教务选课系统