linux select 函数使用Demo
来源:互联网 发布:盘古网络永清县种养殖 编辑:程序博客网 时间:2024/05/29 15:31
参考资料来源
linux tcp并发式服务器应用SELECT函数编写实例源代码
单线程多客户端的
tcp_select.cpp
#include <iostream>#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/socket.h>#include <unistd.h>#include <string.h>#include <errno.h>#include <netinet/in.h>#include <arpa/inet.h>const int MYPORT = 1240;const int BACKLOG = 5;const int BUF_SIZE = 1024;using namespace std;int main(){int sock_fd,new_fd;struct sockaddr_in server_addr,client_addr;char buf[BUF_SIZE];if((sock_fd = socket(AF_INET,SOCK_STREAM,0)) == -1){perror("socket");exit(1);}int yes = 1;//yes = 1;(即TRUE)if(setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(yes)) == -1){perror("setsockopt");exit(1);}server_addr.sin_family = AF_INET;server_addr.sin_port = htons(MYPORT);server_addr.sin_addr.s_addr = INADDR_ANY;memset(server_addr.sin_zero,'0',sizeof(server_addr.sin_zero));if(bind(sock_fd,(struct sockaddr * )&server_addr,sizeof(server_addr)) == -1){perror("bind");exit(1);}if(listen(sock_fd,BACKLOG) == -1){perror("listen");exit(1);}fd_set fdsr;int maxsock;int i;struct timeval tv;int fd_A[BACKLOG];//fdint con_amount = 0;//int ret;maxsock = sock_fd;//int sin_size = sizeof(client_addr);//int len ; wrongsocklen_t sin_size = sizeof(client_addr);while(1){//select函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中FD_ZERO(&fdsr);FD_SET(sock_fd,&fdsr);tv.tv_sec = 30;//每一次查询 套接字是否就绪的时间tv.tv_usec = 0;//for(i = 0;i<BACKLOG;i++) //BACKLOG --段错误 吐核for(i = 0;i<con_amount;i++){if(fd_A[i] != 0)FD_SET(fd_A[i],&fdsr);}ret = select(maxsock + 1,&fdsr,NULL,NULL,&tv);//if(ret < 0){perror("select");break;}else if(ret == 0)// 没有准备就绪的文件描述符 就进入下一次循环{cout << "timeout" << endl;continue;}//有准备就绪的套接字,则分别检查哪些 连接套接字 和 监听套接字 已经就绪 分别进行数据读取和建立连接for(i = 0;i<con_amount;i++){if(FD_ISSET(fd_A[i],&fdsr)){ret = recv(fd_A[i],buf,BUF_SIZE -1,0);if(ret > 0){buf[ret] = '\0';cout << "msg from " << fd_A[i] << "is: " << buf << endl;}else//------------------client close {cout << "client " << fd_A[i] << " is closed!" << endl;close(fd_A[i]);//FD_CLR(fd_A[i],&fdsr);fd_A[i] = 0;/*perro("recv");exit(1);*/}}}//end of "for" if(FD_ISSET(sock_fd,&fdsr)){//if((new_fd = accept(sock_fd,(struct sockaddr *)&client_addr,sizeof(client_addr)) == -1)//errorif((new_fd = accept(sock_fd,(struct sockaddr *)&client_addr,&sin_size)) == -1){perror("accept");exit(1);}//if(con_amount < BACKLOG){fd_A[con_amount++] = new_fd;//FD_SET(new_fd,&fdsr); // no need , fd_A[i] != 0 will be added to fdsr in the begin of each loopcout << "new client:" <<inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << endl;//update maxsock ------if(new_fd > maxsock)maxsock = new_fd;}else{//send msg cout << "Max connections arrived!" << endl;send(new_fd,"Bye",4,0);close(new_fd);//break;//}}}//end of "while(1)"/*close(sock_fd);for(i = 0;i<con_amount;i++){if(fd_A[i] != 0)close(fd_A[i]);}*/return 0;}
test_client.c
</pre><pre name="code" class="cpp">#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netdb.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>/* 服务器程序监听的端口号 *///#define PORT 1240/* 我们一次所能够接收的最大字节数 */#define MAXDATASIZE 100int main(int argc, char *argv[]){/* 套接字描述符 */int sockfd, numbytes;char buf[MAXDATASIZE];int port;struct hostent *he;/* 连接者的主机信息 */struct sockaddr_in their_addr;/* 检查参数信息 */if(argc!= 3){/* 如果没有参数,则给出使用方法后退出 */fprintf(stderr,"usage: server_host server_port\n");exit(1);}/* 取得主机信息 */if ((he=gethostbyname(argv[1])) == NULL){/* 如果 gethostbyname()发生错误,则显示错误信息并退出 */herror("gethostbyname");exit(1);}if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {/* 如果 socket()调用出现错误则显示错误信息并退出 */perror("socket");exit(1);}port = atoi(argv[2]);///* 主机字节顺序 */their_addr.sin_family = AF_INET;/* 网络字节顺序,短整型 */their_addr.sin_port = htons(port);their_addr.sin_addr = *((struct in_addr *)he->h_addr);/* 将结构剩下的部分清零*/bzero(&(their_addr.sin_zero), 8);if(connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == -1){/* 如果 connect()建立连接错误,则显示出错误信息,退出 */perror("connect");exit(1);}/*if((numbytes=recv(sockfd, buf, MAXDATASIZE, 0)) == -1){// 如果接收数据错误,则显示错误信息并退出 perror("recv");exit(1);}buf[numbytes] = '\0';printf("Received: %s",buf);bzero(buf,100);*/strcpy(buf,"Received your message!\n");send(sockfd,buf,strlen(buf),0);/*sleep(100);strcpy(buf,"Received your message2!\n");send(sockfd,buf,strlen(buf),0);*///close(sockfd);return 0;}
测试结果:
笔记:
select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中
连接数达到最大的假象
分析:客户端连接断开仅仅fd_A[i] = 0; 并没有压缩和清空数组。
所以用数组存放套接字描述符并不是最佳选择。(需要删除数组中的元素和调整长度)
而conn_amount没有减小,会造成位置浪费,
即设BACKLOG = 5,如果有5个连接,断开了3个,第6个连接到来的时候仍然被判断为超过最大连接数。
没有初始化的数组元素越界异常:
0 0
- linux select 函数使用Demo
- Linux中select函数的使用 select() Linux linux函数 select
- Linux下select函数的使用
- Linux下select函数的使用
- Linux下select函数的使用
- linux下select函数的使用
- Linux下select函数的使用
- Linux Select()函数使用简解
- Linux下select函数的使用
- linux中select函数的使用
- Linux下select函数的使用
- Linux下select函数的使用
- Linux 中select函数的使用
- Linux下select函数的使用
- Linux下select函数的使用
- Linux下select函数的使用
- linux c select函数使用求解释
- Linux下select函数的使用
- 安卓代码混淆
- 【BZOJ】【P3671】【NOI2014】【随机数生成器】【题解】【贪心】
- Java JNI使用情况
- 10-4. 字符串循环左移(20)
- iOS 在Xcode中使用C++ Library
- linux select 函数使用Demo
- 在IIS中使用Windows域服务器域摘要式身份验证对Web应用程序进行访问控
- 为什么bios将mbr装载到0x7c00地址,0x7c00怎么来的?
- ORACLE 权限和角色
- C++学习建议
- sn9c291 驱动加载成功,mpayer无法播放
- 《活着》读后感
- 线段树 模板 及 解释
- Spring Data JPA入门