UNIX网络编程-Select模型学习
1、相关接口介绍
1.1 select
----------------------------------------------------------------------
#include <sys/select.h>
#include <sys/time.h>
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timeval *timeout);
返回:准备好描述字的正数目,0—超时,-1—出错。
----------------------------------------------------------------------
参数说明:
maxfdp1: 制定要检查的描述符的个数,实际应用中传入最大描述符加1,表明要检查0到最大描述符中间的所有描述符。
readset、writeset、exceptset: 这三个参数都是值-结果参数,传入的是应用程序想让内核检查的套接字集合,传出的是内核检查过的可进行操作的套接字集合。
timeout: 超时设置,NULL表示一直等,直到有一个套接字准备好I/O时才返回,将秒和微秒两个字段都设置为0表示不等待,立即返回。
1.2 fd_set
fd_set: 存放套接字的集合。
有四个操作fd_set的宏,分别是:
void FD_ZERO(fd_set *fdset);
void FD_SET(int fd, fd_set *fdset);
void FD_CLR(int fd, fd_set *fdset);
void FD_ISSET(int fd, fd_set *fdset);
FD_SET设置文件描述符集fdset中对应于文件描述符fd的位(设置为1)
FD_CLR清除文件描述符集fdset中对应于文件描述符fd的位(设置为0)
FD_ZERO清除文件描述符集fdset中的所有位(既把所有位都设置为0)。
使用这3个宏在调用select前设置描述符屏蔽位,在调用select后使用FD_ISSET来检测文件描述符集fdset中对应于文件描述符fd的位是否被设置。
1.3 timeval
是一个表示时间的结构体:
struct timeval
{
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
2、select I/O复用模型的工作流程
2.1 初始化的时候将要检查的socket放入事先定义好的fd_set集合中;
2.2通过调用select函数来获取可读、可写的socket集合;
2.3 获取集合后先检查监听socket,看是否有新的socket连接,若有,则将新的socket添加到集合中准备下一次的扫描;
2.4扫描检查过的集合,对相应的socket进行读写操作;
以下是一个使用select的简单demo,可以处理多个客户端同时跟服务端通信。
3、一个简单的Echo Server
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <strings.h> #define PORT 8080
#define LISTENQ 5
#define MAXLINE 1024
#define IS_ERROR(condition) \
if(condition) \
{ \
printf("Error in func[%s] and line[%d]!\n", \
__PRETTY_FUNCTION__, __LINE__); \
return ; \
} int main(int argc, char *argv[])
{
struct sockaddr_in addrSer;
struct sockaddr_in addrCli;
int listenSock;
int connSock;
int clientSock[FD_SETSIZE]; int maxSock; //the max fd
int sumSock; //sum of client sockets - 1
int nCliLen; //len of addrCli
int nReady; //the num of ready sockets fd_set allset;
fd_set rset; char buf[MAXLINE];
int nRet;
int i; /*create listen socket*/
listenSock = socket(AF_INET, SOCK_STREAM, );
IS_ERROR(listenSock == -); /*bind listen port*/
bzero(&addrSer, sizeof(addrSer));
addrSer.sin_family = AF_INET;
addrSer.sin_addr.s_addr = htonl(INADDR_ANY);
addrSer.sin_port = htons(PORT);
nRet = bind(
listenSock,
(struct sockaddr *)&addrSer,
sizeof(struct sockaddr_in)
);
IS_ERROR(nRet == -); /*listen port*/
nRet = listen(listenSock, LISTENQ);
IS_ERROR(nRet == -); /*init*/
maxSock = listenSock;
sumSock = -; /*Init socket array*/
for (i=; i<FD_SETSIZE; ++i)
{
clientSock[i] = -;
} /*Init fd_set*/
FD_ZERO(&allset);
FD_SET(listenSock, &allset); /*request*/
while ()
{
rset = allset;
nReady = select(maxSock+, &rset, NULL, NULL, NULL); /*accept*/
if (FD_ISSET(listenSock, &rset))
{
nCliLen = sizeof(addrCli);
connSock = accept(listenSock, (struct sockaddr *)&addrCli, &nCliLen);
for (i=; i<FD_SETSIZE; ++i)
{
if (clientSock[i] < )
{
clientSock[i] = connSock;
break;
}
} if (i == FD_SETSIZE)
{
printf("too many clients!\n");
return ;
} FD_SET(connSock, &allset); maxSock = (maxSock < connSock) ? connSock : maxSock;
sumSock = (sumSock < i) ? i : sumSock; if (--nReady <= )
{
continue;
}
} /*send and recv*/
for (i=; i<=sumSock; ++i)
{
if (clientSock[i] < )
{
continue;
} if (FD_ISSET(clientSock[i], &rset))
{
nRet = recv(clientSock[i], buf, MAXLINE, ); if (nRet == || nRet == -)
{
printf("read sock %d err, nRet = %d!\n", clientSock[i], nRet);
close(clientSock[i]);
FD_CLR(clientSock[i], &allset);
clientSock[i] = -;
}
else if (- == send(clientSock[i], buf, nRet, ))
{
printf("write sock %d err!\n", clientSock[i]);
close(clientSock[i]);
FD_CLR(clientSock[i], &allset);
clientSock[i] = -;
} if (--nReady <= )
{
break;
}
} //if (FD_ISSET(clientSock[i], &rset))
} //for (i=0; i<=sumSock; ++i)
} //while(1) return ;
}
UNIX网络编程-Select模型学习的更多相关文章
- UNIX网络编程-Poll模型学习
1.相关接口介绍 1.1 poll ---------------------------------------------------------------------- #include &l ...
- UNIX网络编程——select函数的并发限制和 poll 函数应用举例
一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置, ...
- UNIX网络编程——网络I/O模型
在学习UNIX网络编程的时候.一開始分不清 同步 和 异步,所以还是总结一下,理清下他们的差别比較好. IO分类 IO依据对IO的调度方式可分为堵塞IO.非堵塞IO.IO复用.信号驱动IO.异步IO. ...
- 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数
本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...
- UNIX网络编程——使用select函数编写客户端和服务器
首先看原先<UNIX网络编程--并发服务器(TCP)>的代码,服务器代码serv.c: #include<stdio.h> #include<sys/types.h> ...
- Unix网络编程中的五种I/O模型_转
转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...
- 《UNIX网络编程 卷1》之"学习环境搭建"(CentOS 7)
<UNIX网络编程 卷1>的源码可以从www.unpbook.com下载得到.解压之后的目录为unpv13e. 详细步骤 编译 进入unpv13e目录,按如下步骤编译: ./configu ...
- UNIX网络编程 第6章 I/O复用:select和poll函数
UNIX网络编程 第6章 I/O复用:select和poll函数
- 记录一次配置unix网络编程环境的过程和遇到的问题
记录一次搭建unix网络编程环境过程中遇到的问题和总结 计算机环境虚拟机 linuxmint-18-xfce-64bit 1.打开unix网络编程.iso 把目录下的文件复制到某一目录,修改权限,可命 ...
随机推荐
- (实用篇)php支付宝接口用法分析
本文实例讲述了php支付宝接口用法.分享给大家供大家参考.具体分析如下: 现在流行的网站支持平台,支付宝当仁不让的老大了,现在我们就来告诉你如何使用支付宝api来做第三方支付,把支付宝放到自己网站来, ...
- CLR via C# 3rd - 06 - Type and Member Basics
1. Different Kinds of Type Members A type can define zero or more of the following kinds of ...
- web开发实战--图片裁剪和上传
前言: 最近的开发中, 有一个上传头像的任务. 由于头像本身的特殊性, 其一般流程为选择图片, 编辑裁剪区域, 再继而上传图片操作. 看似简单的东西, 实则是挺麻烦的一件事. 借助这次开发机会, 来具 ...
- JavaScript DOM 编程艺术·setInterval与setTimeout的动画实现解析
先贴上moveElement()函数的大纲,为了方便观看,删了部分代码,完整版粘到文章后面. function moveElement(elementID,final_x,final_y,interv ...
- 新冲刺Sprint3(第六天)
一.Sprint介绍 商家功能模块继续完善着,加快了工作的步伐. 二.Sprint周期 看板: 燃尽图:
- 工程环境搭建和网站部署(java)
我们一般访问网站的时候,都是用127.0.0.1:8080...去访问,如果想用www.shopping.com访问java网站时 需要配置C:\Windows\System32\drivers\et ...
- jsp基础知识
- *** missing separator. Stop.
在make命令后出现这种错误提示,是提示第2行没有分隔符. 例如: 1 target:prerequisites 2 command -- 改为: 1 target:prerequisites 2 ...
- shh简化
对于SSH框架中部分的操作简化我分为两大类: 一:操作 1. 在SSH的struts.xml里 name="Action类_*" class="注入的实例"(同 ...
- #mysql:command not found
一.问题描述 1.在linux中已经安装好mysql,通过#ps -ef |grep mysql 能显示mysql已经启动,但去进入mysql命令页面出现如下问题: [root@root ~]# my ...