实现TCP并发服务器之三(select函数)
来源:互联网 发布:域名阻断是怎么回事 编辑:程序博客网 时间:2024/05/16 13:46
前面两篇介绍用进程方式和线程方式实现并发服务,其实里面调用send,read,accept函数都会导致阻塞,而linux的select函数可以使我们在程序中同时监听多个文件描述符的读写状态。程序会停在select这里等待,直到被监视的文件描述符有某一个或多个发生了状态改变。select()的机制中提供一fd_set的数据结构,实际上是一long类型的数组, 每一个数组元素都能与一打开的文件描述符(不管是Socket描述符,还是其他 文件或命名管道或设备描述符)建立联系,当调用select()时,由内核根据IO状态修改fd_set的内容,由此来通知执行了select()的进程哪一Socket或文件可读。
下面我们用select函数实现单进程单线程的并发服务,客户端代码同多进程版本,服务器端代码如下
#include<stdio.h>#include<stdlib.h>#include<string.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/in.h>#include<arpa/inet.h>#define MAX_LISTEN 5#define PORT 1987#define IP "127.0.0.1"int main(){int conn_fd;int sock_fd = socket(AF_INET,SOCK_STREAM,0);if (sock_fd < 0) {perror("create socket failed");exit(1);}struct sockaddr_in addr_client;int client_size = sizeof(struct sockaddr_in);struct sockaddr_in addr_serv;memset(&addr_serv, 0, sizeof(addr_serv));addr_serv.sin_family = AF_INET;addr_serv.sin_port = htons(PORT);addr_serv.sin_addr.s_addr = inet_addr(IP);if (bind(sock_fd,(struct sockaddr *)&addr_serv,sizeof(struct sockaddr_in)) < 0) {perror("bind error");exit(1);}if (listen(sock_fd,MAX_LISTEN) < 0) {perror("listen failed");exit(1);}int recv_num;int send_num;char recv_buf[100];char send_buf[100];//用一个数组记录描述符的状态int i, ready, max_fd;int client[FD_SETSIZE];for (i = 0;i < FD_SETSIZE;i ++) {client[i] = -1;}fd_set readset;max_fd = sock_fd;//最大可用描述符的个数,一般受操作系统内核的设置影响,我的环境下这个值是1024printf("max fd num %d\n",FD_SETSIZE);while (1) {//重置监听的描述符FD_ZERO(&readset);FD_SET(sock_fd,&readset);for (i = 0;i < FD_SETSIZE;i ++) {if (client[i] == 1) {FD_SET(i, &readset);}}//开始监听描述符,是异步的,不会阻塞ready = select(max_fd+1, &readset, NULL, NULL, NULL);//可用描述符如果是创建连接描述符,则创建一个新的连接if (FD_ISSET(sock_fd, &readset)) {conn_fd = accept(sock_fd, (struct sockaddr *)&addr_client, &client_size);if (conn_fd < 0) {perror("accept failed");exit(1);}FD_SET(conn_fd, &readset);FD_CLR(sock_fd, &readset);if (conn_fd > max_fd) {max_fd = conn_fd;}client[conn_fd] = 1;}//检查所有的描述符,查看可读的是哪个,针对它进行IO读写for (i = 0; i < FD_SETSIZE; i ++) {if (FD_ISSET(i, &readset)) {recv_num = recv(i, recv_buf, sizeof(recv_buf), 0);if (recv_num <= 0) {FD_CLR(i, &readset);client[i] = -1;}recv_buf[recv_num] = '\0';memset(send_buf,0,sizeof(send_buf));sprintf(send_buf, "server proc got %d bytes\n", recv_num);send_num = send(i, send_buf, strlen(send_buf), 0);if (send_num <= 0) {FD_CLR(i, &readset);client[i] = -1;}}}}close(sock_fd);return 0;}程序的效果和单进程,单线程都是一样的,不过我上面存在两个问题还没解决,我主要也是简单了解select的使用方法,没有做过多钻研。
1,每次select之前我都重新设置了一遍需要监听的描述符,要是能把这个提取到while循环外就好了(不过放出去程序就会错误,未查清原因)
2,我没有引入可写的fd_set,其实应该将文件描述符的可写状态也作为监听变量传给select函数,不过上面的示例代码可用即可。
- 实现TCP并发服务器之三(select函数)
- 实现TCP并发服务器之四(poll函数)
- 实现TCP并发服务器之五(epoll函数)
- select()函数(I/O多路复用)-并发服务器的实现
- 基于select函数的单进程并发服务器程序----TCP
- select实现tcp并发服务器的基本框架流程
- Select实现并发服务器
- select实现并发服务器
- 实现TCP并发服务器之二(多线程)
- TCP并发服务器模型(三)
- Linux网络编程——tcp并发服务器(I/O复用之select)
- Linux网络编程——tcp并发服务器(I/O复用之select)
- Linux网络编程:tcp并发服务器(I/O复用之select)
- select版tcp服务器(python实现)
- select 实现 tcp echo 服务器
- TCP并发服务器之进程
- tcp并发服务器之线程
- 使用Select I/O模型来实现一个并发处理多个客户端的TCP服务器
- java IO操作 (读写、追加、删除、移动、复制)
- 【Delphi】VirtualTreeView控件
- Struts2.0里的过滤器interceptor之用户只可以访问Login.action与Register.action,访问其它.action的链接时,自动切换到登录页面
- malloc和new的区别
- 输入个人月收入总额,计算出本月应缴税款
- 实现TCP并发服务器之三(select函数)
- 二叉树的创建及递归的先,中,后序遍历
- Hi,今天终于有空管理CSDN博客
- Ajax与中文乱码
- 快毕业了,怎么办,工作啊,工作,烦!
- 【Delphi】FireMonkey下的WndProc实现
- 实现TCP并发服务器之一(多进程)
- Linux网络概述
- JNI的学习