套接字联网API之二 select作用和案例
来源:互联网 发布:手机java编程软件 编辑:程序博客网 时间:2024/06/05 02:36
这个系列的上一篇文章讲了套接字联网API在服务端和客户端的几个主要函数。 这篇文章用来实现,顺便说一下select模型,也在下面的代码中用到。
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
select模型出现的真正原因在网上一直找不到,经过仔细思考其实只有一个,就是解决异步的问题;而且这个select是要结合多线程的。下面对这些进行说明。
1) 当使用阻塞 I/0时, 当阻塞在输入的时候无法进行读取的监听;
2) 当使用非阻塞I/O时,会在读取的监听上消耗CPU的资源。 其实这种情况即使忽略消耗的CPU资源,也是不能实现异步的。
3) 这时可能会考虑到使用多线程,就是让读取的监听 和 输入放在不同的线程中。
比如采用select监听一个套接字, 如果返回一个结果,就开辟一个新线程用来进行交互,假设这个新的线程阻塞在输入上,监听线程还是能够监听的,如果收到了一个FIN,能够及时的终止这个新的线程。 这就是select的作用,但是是不是每个连接都要设置一个select? 不用的,之需要在全局的主线程设置一个select就可以了,每当一个连接建立,就信开辟一个线程,主线程仍然在监听;而它又收到监听描述符上的信息后(比如FIN报文),就会对该描述符对应的线程进行处理。
下面是select的一个模型,分为服务端和客户端,有详细的注释。
服务端流程如下: 只发了一个文件,目的是弄清流程
#include <stdio.h>#include <stdlib.h>#include "server.h"#include "database.h"#include "userdata.h"#include "struct.h"#include "thread.h"int main(){ int x = 0; //关于在线用户变量 userlist_init(&L); pthread_t hThread[FD_SETSIZE]; //套接字变量 struct message ma; int i,maxi; //maxi代表存储最大已连接描述符的序号 fd_set allset,curset; int readyfd,maxfd; //select返回的已准备好的描述符 int client[FD_SETSIZE];//连接描述符数组 int ser_sockfd,cli_sockfd,confd; int ser_length,cli_length; struct sockaddr_in server_address; struct sockaddr_in client_address; //先连上数据库 连接的mysql的数据库,用户名和密码均为majintao my_sql=mysql_init(NULL); if(NULL == my_sql) { printf("mysql init error\n"); return mysqlinit; } my_sql=mysql_real_connect(my_sql,"localhost","majintao","majintao","chatroom",0,NULL,0); if(NULL == my_sql) { printf("connect error\n"); return mysqlconnect; } //创建一个未命名的套接字 ser_sockfd=socket(AF_INET, SOCK_STREAM,0); if(ser_sockfd < 0) { printf("create socket error\n"); return 0; } bzero(&server_address,sizeof(server_address)); server_address.sin_family=AF_INET; server_address.sin_addr.s_addr=htonl(INADDR_ANY); //暂定 server_address.sin_port=htons(9734);//暂定 int bindfd=bind(ser_sockfd,(struct sockaddr*)&server_address,sizeof(server_address)); if(bindfd < 0) { printf("bind error\n"); return 0; } //客户端数据处理 bzero(&client_address,sizeof(client_address)); //cl_echo(ser_sockfd,(struct sockaddr*)&server_address,sizeof(server_address)); listen(ser_sockfd,LISTENQ); FD_ZERO(&allset); FD_SET(ser_sockfd,&allset); maxfd=ser_sockfd; //初始化描述符数组 for(i=0;i<FD_SETSIZE;i++) { client[i]=-1; } //开始select监听套接字 curset=allset; for(;;) { // <span style="color:#ff0000;">readyfd=select(maxfd+1,&curset,NULL,NULL,NULL);</span> if(FD_ISSET(ser_sockfd,&curset)) { cli_length=sizeof(client_address); if(-1 == (confd=accept(ser_sockfd,(struct sockaddr*)&client_address,&cli_length) ) ) { printf("accept error\n"); exit(1); } //把描述符放到合适的位置 for(i =0;i<FD_SETSIZE;i++) { if(client[i] <= 0) { client[i] = confd; break; } } //客户端连接太多 if(i == FD_SETSIZE) { printf("too many clients\n"); exit(1); } //重新设置 FD_SET(confd,&allset); //如果已连接描述符大于监听描述符,更改 //if(confd > maxfd) //{ // maxfd = confd; // } //更新描述符所在序号的最大值 if(i > maxi) { maxi = i; } //如果只有一个监听描述符,就不检查已连接描述符了 /*if(--readyfd <= 0) { continue; }*/ } //fd_set //对每一个已经连接描述符做处理 for(i = 0;i <=maxi; i++) { if( (testfd = client[i]) < 0) continue; if( FD_ISSET(testfd,&allset) ) { int tThread; //这个时候创建一个线程,意思为每个已经连接的描述符创建一个线程 <span style="color:#ff0000;">tThread = pthread_create(&hThread[x++], NULL, thread_ser,&testfd);</span> if(tThread != 0) { printf("Thread create failed\n"); return -1; } } client[i] = -1; //保证不会重复创建线程 if(--readyfd <= 0) break; }//第二个for }//最外层for循环}//main
客户端没有使用select,就不介绍了。
- 套接字联网API之二 select作用和案例
- UNIX 网络编程 卷一:套接字联网API(第3版) 读书笔记(6) 第六章 I/O复用:select和poll函数
- 套接字联网API之一 TCP套接字
- 学习《UNIX网络编程 卷1:套接字联网API》
- UNIX网络编程卷一:套接字联网API-整理
- UNIX网络编程 卷1:套接字联网API
- UNIX网络编程卷1:套接字联网API
- 非阻塞套接字及select模型案例
- 套接字结构和API
- UNIX 网络编程 卷一:套接字联网API 读书笔记(2) 第二章 传输层:TCP、UDP和SCTP
- UNIX网络编程卷1:套接字联网API-第2章:传输层 TCP/UDP和SCTP
- 异步套接字编程之select模型
- 套接字API(二)bind函数
- linux网络编程之套接字:套接字I/O超时设置方法和用select实现超时
- 套接字select模型
- 套接字select模型
- 套接字Select
- 套接字select模型
- 再谈const
- poj3071--Football(概率计算)
- C 语言中的好基友 数组和指针之一
- 即时通讯 - 保证push消息到达对方的流程
- JDBC与数据库的连接,及实现对数据库的增、删、查、修
- 套接字联网API之二 select作用和案例
- CANVAS TRANSFORM
- 适用于Shiny的ESS代码缩进设置
- xcode6.1.1升级到7.1.3后遇到的的2个问题:Could not find developer disk 和enable_bitcode错误相关
- Genymotion出现unknown generic error和This may occur if you are using a proxy错误的解决方案
- 【bzoj3916】 Baltic2014 friends hash
- web.xml管理的内容
- ireport5.6使用table组件,如何用table显示javaBean数据源
- 如何做到每天写代码?