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模型学习的更多相关文章

  1. UNIX网络编程-Poll模型学习

    1.相关接口介绍 1.1 poll ---------------------------------------------------------------------- #include &l ...

  2. UNIX网络编程——select函数的并发限制和 poll 函数应用举例

    一.用select实现的并发服务器,能达到的并发数,受两方面限制 1.一个进程能打开的最大文件描述符限制.这可以通过调整内核参数.可以通过ulimit -n来调整或者使用setrlimit函数设置,  ...

  3. UNIX网络编程——网络I/O模型

    在学习UNIX网络编程的时候.一開始分不清 同步 和 异步,所以还是总结一下,理清下他们的差别比較好. IO分类 IO依据对IO的调度方式可分为堵塞IO.非堵塞IO.IO复用.信号驱动IO.异步IO. ...

  4. 【unix网络编程第三版】阅读笔记(五):I/O复用:select和poll函数

    本博文主要针对UNP一书中的第六章内容来聊聊I/O复用技术以及其在网络编程中的实现 1. I/O复用技术 I/O多路复用是指内核一旦发现进程指定的一个或者多个I/O条件准备就绪,它就通知该进程.I/O ...

  5. UNIX网络编程——使用select函数编写客户端和服务器

    首先看原先<UNIX网络编程--并发服务器(TCP)>的代码,服务器代码serv.c: #include<stdio.h> #include<sys/types.h> ...

  6. Unix网络编程中的五种I/O模型_转

    转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描 ...

  7. 《UNIX网络编程 卷1》之"学习环境搭建"(CentOS 7)

    <UNIX网络编程 卷1>的源码可以从www.unpbook.com下载得到.解压之后的目录为unpv13e. 详细步骤 编译 进入unpv13e目录,按如下步骤编译: ./configu ...

  8. UNIX网络编程 第6章 I/O复用:select和poll函数

    UNIX网络编程 第6章 I/O复用:select和poll函数

  9. 记录一次配置unix网络编程环境的过程和遇到的问题

    记录一次搭建unix网络编程环境过程中遇到的问题和总结 计算机环境虚拟机 linuxmint-18-xfce-64bit 1.打开unix网络编程.iso 把目录下的文件复制到某一目录,修改权限,可命 ...

随机推荐

  1. HttpClient方式模拟http请求设置头

    关于HttpClient方式模拟http请求,请求头以及其他参数的设置. 本文就暂时不给栗子了,当作简版参考手册吧. 发送请求是设置请求头:header HttpClient httpClient = ...

  2. javax.el.PropertyNotFoundException:

    javax.el.PropertyNotFoundException: Property 'ContextPath' not found on type org.apache.catalina.cor ...

  3. React(JSX语法)----JSX拼写

    注意:For DOM differences,such as the inline style attribute,check here. // bad: it displays "FIrs ...

  4. 自学 PHP,如何不走弯路?

    1.一本好书至关重要.如果这本书的知识非常深入,那么还是不要看了.对初学者来说只能是打击.因为很多东西都看不懂.一本知识较为浅显,并且说明非常详细,但是能让你上手的基础知识又非常完善的书籍就非常好.( ...

  5. pvoid64 pvoid

    如果需要某一个结构体,既在kernel space用,又在user space用,如 typedef struct { PVOID data; int size; }binary,pbinary; 上 ...

  6. java疑问-继承问题

    存在两个类,B 继承 A,C 继承 B,我们能将 B 转换为 C 么?如 C = (C) B:

  7. 想让你的java代码更漂亮,用枚举吧

    枚举是java 5之后添加的一个重要特性,这个特性不能提高性能,但是能让java程序员写出更优雅的代码. 我之前看到过挺多介绍java枚举的不错的帖子,我也来参与以下这个话题. 1. 枚举基本用法 / ...

  8. 关于回溯与n个数的全排列

    今天要讲的题目是全排列的问题:有1.2.3.....n这样一个数列,要求输出其全排列. 那么,显然,这道题目非常之简单,用一个标志数组变量,标记数字的使用情况,然后根据它挑选数字即可.由于题目很简单, ...

  9. oracle case when

    http://www.cnblogs.com/kevin2013/archive/2010/07/02/1769682.html

  10. Linux监控实战-2

    vmstat命令 用法:vmstat 1 --->每个1s打印信息; vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存 ...