linux select 函数使用Demo
2014-07-30 22:32
381 查看
参考资料来源
linux tcp并发式服务器应用SELECT函数编写实例源代码
单线程多客户端的
tcp_select.cpp
test_client.c
测试结果:
笔记:
select()函数会清空它所检测的socket描述符集合,导致每次调用select()之前都必须把socket描述符重新加入到待检测的集合中
连接数达到最大的假象
分析:客户端连接断开仅仅fd_A[i] = 0; 并没有压缩和清空数组。
所以用数组存放套接字描述符并不是最佳选择。(需要删除数组中的元素和调整长度)
而conn_amount没有减小,会造成位置浪费,
即设BACKLOG = 5,如果有5个连接,断开了3个,第6个连接到来的时候仍然被判断为超过最大连接数。
没有初始化的数组元素越界异常:
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];//fd int con_amount = 0;// int ret; maxsock = sock_fd; //int sin_size = sizeof(client_addr);//int len ; wrong socklen_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)//error if((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 loop cout << "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 100 int 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个连接到来的时候仍然被判断为超过最大连接数。
没有初始化的数组元素越界异常:
相关文章推荐
- 线程超时等待方法---linux中select()函数使用
- 使用 select 设计超时 connect 函数的问题(linux 上连接 127.0.0.1 任何端口总是成功)
- linux中select()函数分析
- 如何使用select()函数
- snprintf函数使用(Windows与Linux版本)
- Linux I/O 模型---I/O复用:Select和Poll函数
- linux下的时间函数使用
- 如何有效地使用函数select()
- DataTable.Select()中的表达式可使用的函数
- linux中select()函数相关:
- DataTable.Select()中的表达式可使用的函数
- linux 系统下使用C程序实现时钟的函数
- linux中select()函数分析
- linux中select()函数分析
- linux中select()函数分析
- DataTable.Select()中的表达式可使用的函数
- linux下使用数学函数
- select 函数 使用
- Linux 中的 curses 函数库--- 使用 getch 必需
- linux中select()函数分析