热度 22
2013-5-18 08:47
1216 次阅读|
1 个评论
自学嵌入式linux时间也不短了,但是作为一个三天打鱼两天晒网的人来说,我学习随意性很强,一般在工作之余看一点儿书、敲几行代码,进度也很慢。现在把总结的一些内容整理成博客,一方面跟大家共同分享一下学习过程,另一方面呢也督促一下自己努力学习!哈哈。下面进入正题,这篇博客的主题是select()函数实现并发服务器。下面直接上代码(带有注释的哦,全是我自己的理解,有误之处恳请各位大牛多多扶持),在代码的最后我用visio做了个简单的流程图,做的很粗糙,希望不会有碍观瞻! 以下代码是select()函数实现并发服务器的程序代码,现对其作出解释: #include #include #include #include #include #include #include #include #define BACK_LOG 10 #define BUF_SIZE 1024 #define PORT 8000 int main(int argc, char *argv ; char buffer ; fd_set allset,rdset; struct timeval tv = {0, 0}; if(argc != 2) { printf("Usage: echoserv "); exit(1); } bzero(servaddr,sizeof(struct sockaddr_in)); servaddr.sin_family = AF_INET; servaddr.sin_addr.s_addr = INADDR_ANY; // servaddr.sin_port = htons(PORT); servaddr.sin_port = htons(atoi(argv )); // 端口号由程序运行时作为参数传入 sockfd = socket(AF_INET, SOCK_STREAM, 0); // 打开通讯端口 if (sockfd == -1) { perror("socket"); exit(1); } ret_val = bind(sockfd, (struct sockaddr *)servaddr, sizeof(struct sockaddr)); //绑定服务器IP和端口 if (ret_val == -1) { perror("bind"); exit(1); } ret_val = listen(sockfd, BACK_LOG); // 将主动连接套接字变为被动连接套接字 if (ret_val == -1) { perror("listen"); exit(1); } max_fd = sockfd; FD_ZERO(allset); // 清空描述符集 FD_ZERO(rdset); FD_SET(sockfd,allset); // 将通讯端口描述符加入描述符集中 for(i=0; i FD_SETSIZE; i++) client = -1; max_index = -1; for(;;) { rdset = allset; //nready = select(max_fd+1,rdset,NULL,NULL,NULL); // 以阻塞方式监听rdset描述符集中是否有可读的描述符 nready = select(max_fd+1,rdset,NULL,NULL,tv); // 以完全非阻塞方式监听rdset描述符集中是否有可读的描述符 if(FD_ISSET(sockfd, rdset)) // FD_ISSET用来检测描述符集中指定描述符状态是否发生了变化,在此用来检测通讯端口是否有新的请求连接 { clilen = sizeof(cliaddr); connfd = accept(sockfd, (struct sockaddr *)cliaddr, clilen); // 为新建立的连接分配通讯描述符 if(connfd ==-1) { perror("accept"); continue; } for(i=0; i; { if(client == -1) { client = connfd; // 填充客户端通讯描述符表 break; } } if(i == FD_SETSIZE) // FD_SETSIZE宏是在哪里定义的? { printf("Too many client here!"); exit(1); } if(i max_index) max_index = i; if(connfd max_fd) max_fd = connfd; FD_SET(connfd,allset); if(--nready =0) // 完成对新建的客户端分配描述符之后重新跳select()监控新建立的客户端或者接收已建立客户端的数据发送请求 continue; } for (i=0; i= max_index; i++) // 程序运行到此处说明有客户端发送数据请求(select()函数以阻塞方式工作时)以轮询方式服务已建立的客户端 { if((clifd=client ) 0) continue; if(FD_ISSET(clifd,rdset)) // 检查是哪个客户端发起的数据请求,并为服务 { len = BUF_SIZE; len = recv(clifd, buffer, len, 0); if (len = 0) { close(clifd); FD_CLR(clifd,allset); client = -1; } else send(clifd,buffer,len,0); // 应用层协议在此实现 ,该范例仅原样返回接收到的字符串 if(--nready =0) break; }//if }//for }//for } 以下是我编写的程序流程图: 附件中是程序源码和visio格式的程序流程图。