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
原创粉丝点击