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. caffe 安装资料整理

    最近在安装caffe,因为过程繁琐,而且不同的作者给出了不同的安装教程,鱼龙混杂,所以做了个简单的整理. 基本安装方法在下面博客上面都有详细介绍,不过不同版本的硬件适配不同版本的软件,所以安装的时候一 ...

  2. Hibernate save, saveOrUpdate, persist, merge, update 区别

    Hibernate Save hibernate save()方法能够保存实体到数据库,正如方法名称save这个单词所表明的意思.我们能够在事务之外调用这个方法,这也是我不喜欢使用这个方法保存数据的原 ...

  3. Eclipse 打不开

    查看环境变量中是否存在重复的javahome变量路径 如上图存在-vm C:\ProgramData\Oracle\Java\javapath\javaw.exe,就和自己配置的javahome变量存 ...

  4. Xcode8 上传完.ipa包 官网超过2天还没反应

    出现这个问题一般邮件有提示,我这里说一下,我之前都上传没有问题,就更新完Xcode8,就不行. 这个问题其实是因为权限没有写完  这样就可以了.

  5. HTML5画布实现方法:

    我们可以在HTML中使用属性width和height来定义Canvas.但是实现Canvas的相关功能主要还依赖于Javascript实现,即HTML5 Canvas API.我们使用javascri ...

  6. sql server 条件 not in (null)总是false

    SELECT  1 WHERE   2 NOT  IN ( 1 ); 结果: (无列名) 1   SELECT  1 WHERE   2 NOT  IN ( 1, NULL ); 结果:(无列名)   ...

  7. linux 持续构建(自动部署) 重启动tomcat或进程的脚本

    #!/bin/sh TOMCAT_PATH=`dirname "$0"` echo "TOMCAT_PATH is /usr/local/tomcat" PID ...

  8. C++ 资源大全

    http://www.uml.org.cn/c++/201411145.asp http://ezlippi.com/blog/2014/12/c-open-project.html <C++ ...

  9. c#读取INI文件

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.I ...

  10. MySql 存储过程及调用方法

    存储过程实例: DELIMITER $$drop procedure if exists ff $$CREATE /*[DEFINER = { user | CURRENT_USER }]*/ PRO ...