select server
2015-07-21 16:31
288 查看
server with select
ref1 ref2
#include<stdio.h> #include<sys/types.h> #include<sys/socket.h> #include<unistd.h> #include<stdlib.h> #include<errno.h> #include<arpa/inet.h> #include<netinet/in.h> #include<string.h> #include<signal.h> #include<sys/wait.h> #define ERR_EXIT(m) \ do { \ perror(m); \ exit(EXIT_FAILURE); \ } while (0) int main(void) { signal(SIGPIPE, SIG_IGN); int listenfd; //被动套接字(文件描述符),即只可以accept, 监听套接字 if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) // listenfd = socket(AF_INET, SOCK_STREAM, 0) ERR_EXIT("socket error"); struct sockaddr_in servaddr; memset(&servaddr, 0, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(5188); servaddr.sin_addr.s_addr = htonl(INADDR_ANY); /* servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); */ /* inet_aton("127.0.0.1", &servaddr.sin_addr); */ int on = 1; if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) ERR_EXIT("setsockopt error"); if (bind(listenfd, (struct sockaddr*)&servaddr,sizeof(servaddr)) < 0) ERR_EXIT("bind error"); if (listen(listenfd, SOMAXCONN) < 0) //listen应在socket和bind之后,而在accept之前 ERR_EXIT("listen error"); struct sockaddr_in peeraddr; //传出参数 socklen_t peerlen = sizeof(peeraddr); //传入传出参数,必须有初始值 int conn; // 已连接套接字(变为主动套接字,即可以主动connect) int i; int client[FD_SETSIZE]; int maxi = 0; // client数组中最大不空闲位置的下标 for (i = 0; i < FD_SETSIZE; i++) client[i] = -1; int nready; int maxfd = listenfd; fd_set rset; fd_set allset; FD_ZERO(&rset); FD_ZERO(&allset); FD_SET(listenfd, &allset); while (1) { rset = allset; nready = select(maxfd + 1, &rset, NULL, NULL, NULL); if (nready == -1) { if (errno == EINTR) continue; ERR_EXIT("select error"); } if (nready == 0) continue; if (FD_ISSET(listenfd, &rset)) { conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen); //accept不再阻塞 if (conn == -1) ERR_EXIT("accept error"); for (i = 0; i < FD_SETSIZE; i++) { if (client[i] < 0) { client[i] = conn; if (i > maxi) maxi = i; break; } } if (i == FD_SETSIZE) { fprintf(stderr, "too many clients\n"); exit(EXIT_FAILURE); } printf("recv connect ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port)); FD_SET(conn, &allset); if (conn > maxfd) maxfd = conn; if (--nready <= 0) continue; } for (i = 0; i <= maxi; i++) { conn = client[i]; if (conn == -1) continue; if (FD_ISSET(conn, &rset)) { char recvbuf[1024] = {0}; int ret = read(conn, recvbuf, 1024); if (ret == -1) ERR_EXIT("readline error"); else if (ret == 0) { //客户端关闭 printf("client close \n"); FD_CLR(conn, &allset); client[i] = -1; close(conn); } fputs(recvbuf, stdout); write(conn, recvbuf, strlen(recvbuf)); if (--nready <= 0) break; } } } return 0; }
ref1 ref2
相关文章推荐
- HTML学习笔记——标签设置格式
- vim帮助手册汉化
- jQuery 获取 table 行数
- 【Java】归并排序
- Mongodb详解与安装
- 微信接入,获取用户信息并入库
- 5.编写一个程序,有两个类,其中类MAX中具有两个方法,方法名都是max,一个方法能够比较两个数的大小,另外一个方法能够比较三个数的大小。在另外一个类中创建对象,调用这两个方法,分别输出两组数:2、6
- table数据表格添加checkbox进行数据进行两个表格左右移动。
- eclipse 环境配置
- SlidingMenu (二)SlidingMenu简介
- Android从服务端获取json解析显示在客户端上面
- ACM动态规划总结
- hcharts学习笔记-显示点值的折线图
- Intel平台下Linux中ELF文件动态链接的加载、解析及实例分析
- table数据表格添加checkbox进行数据进行两个表格左右移动。
- JS移动客户端--触屏滑动事件
- HDU 1276 士兵队列训练问题(队列)
- struts2、spring整合
- flash 调用启动一个.exe文件并向其传递参数的方法
- python中字符串的使用