linux select io,柳大的Linux游记·基础篇(5)select IO复用机制

柳大的Linux游记·基础篇(5)select IO复用机制

Author: 柳大·Poechant(钟超)

Email: zhongchao.ustc#gmail.com (#->@)

Date: March 13th, 2012

Copyright © 柳大·Poechant

1 基本原理

0818b9ca8b590ca3270a3433284dd417.png

1 数据结构与函数原型

1.1 select

函数原型

int select(

int nfds,

fd_set *readset,

fd_set *writeset,

fd_set* exceptset,

struct timeval *timeout

);

头文件

select位于:

#include

struct timeval位于:

#include

返回值

返回对应位仍然为1的fd的总数。

参数

nfds:第一个参数是:最大的文件描述符值+1;

readset:可读描述符集合;

writeset:可写描述符集合;

exceptset:异常描述符;

timeout:select 的监听时长,如果这短时间内所监听的 socket 没有事件发生。

1.2 fd_set

1.2.1 清空描述符集合

FD_ZERO(fd_set *)

1.2.2 向描述符集合添加指定描述符

FD_SET(int, fd_set *)

1.2.3 从描述符集合删除指定描述符

FD_CLR(int, fd_set *)

1.2.4 检测指定描述符是否在描述符集合中

FD_ISSET(int, fd_set *)

1.2.5 描述符最大数量

#define FD_SETSIZE 1024

1.3 描述符集合

可读描述符集合中可读的描述符,为1,其他为0;可写也类似。异常描述符集合中有异常等待处理的描述符的值为1,其他为0。

1.4 ioctl

函数原型:int ioctl(int handle, int cmd,[int *argdx, int argcx]);

头文件:#include

返回值:

0 - 成功

1 - 失败

2 示例

程序各部分的解释在注释中。

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define TRUE 1

#define FALSE 0

int main(int argc, char *argv[])

{

int i, len, rc, on = TRUE;

int listen_sd, new_sd = 0, max_sd;

int desc_ready;

char buffer[80];

int close_conn, end_server = FALSE;

struct sockaddr_in server_addr;

struct timeval timeout;

struct fd_set master_set, working_set;

// Listen

listen_sd = socket(AF_INET, SOCK_STREAM, 0);

if (listen_sd < 0)

{

perror("socket() failed");

exit(-1);

}

// Set socket options

rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));

if (rc < 0)

{

perror("setsockopt() failed");

close(listen_sd);

exit(-1);

}

// Set IO control

rc = ioctl(listen_sd, FIONBIO, (char *) &on);

if (rc < 0)

{

perror("ioctl() failed");

close(listen_sd);

exit(-1);

}

// Bind

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(atoi(argv[1]));

rc = bind(listen_sd, (struct sockaddr *) &server_addr, sizeof(server_addr));

if (rc < 0)

{

perror("bind() failed\n");

close(listen_sd);

exit(-1);

}

// Listen

rc = listen(listen_sd, 32);

if (rc < 0)

{

perror("listen() failed\n");

close(listen_sd);

exit(-1);

}

// Intialize sd set

FD_ZERO(&master_set);

max_sd = listen_sd;

FD_SET(listen_sd, &master_set);

timeout.tv_sec = 3 * 60;

timeout.tv_usec = 0;

// Start

do

{

// Copy master_set into working_set

memcpy(&working_set, &master_set, sizeof(master_set));

printf("Waiting on select()...\n");

rc = select(max_sd + 1, &working_set, NULL, NULL, &timeout);

if (rc < 0)

{

perror(" select() failed\n");

break;

}

if (rc == 0)

{

printf(" select() timed out. End program.\n");

break;

}

desc_ready = rc; // number of sds ready in working_set

// Check each sd in working_set

for (i = 0; i <= max_sd && desc_ready > 0; ++i)

{

// Check to see if this sd is ready

if (FD_ISSET(i, &working_set))

{

--desc_ready;

// Check to see if this is the listening sd

if (i == listen_sd)

{

printf(" Listeing socket is readable\n");

do

{

// Accept

new_sd = accept(listen_sd, NULL, NULL);

// Nothing to be accepted

if (new_sd < 0)

{

// All have been accepted

if (errno != EWOULDBLOCK)

{

perror(" accept() failed\n");

end_server = TRUE;

}

break;

}

// Insert new_sd into master_set

printf(" New incoming connection - %d\n", new_sd);

FD_SET(new_sd, &master_set);

if (new_sd > max_sd)

{

max_sd = new_sd;

}

}

while (new_sd != -1);

}

// This is not the listening sd

else

{

close_conn = FALSE;

printf(" Descriptor %d is avaliable\n", i);

do

{

rc = recv(i, buffer, sizeof(buffer), 0);

// Receive data on sd "i", until failure occurs

if (rc < 0)

{

// Normal failure

if (errno != EWOULDBLOCK)

{

perror(" recv() failed\n");

close_conn = TRUE;

}

break;

}

// The connection has been closed by the client

if (rc == 0)

{

printf(" Connection closed\n");

close_conn = TRUE;

break;

}

/* Receiving data succeeded and echo it back

the to client */

len = rc;

printf(" %d bytes received\n", len);

rc = send(i, buffer, len, 0);

if (rc < 0)

{

perror(" send() failed");

close_conn = TRUE;

break;

}

}

while (TRUE);

// If unknown failure occured

if (close_conn)

{

// Close the sd and remove it from master_set

close(i);

FD_CLR(i, &master_set);

// If this is the max sd

if (i == max_sd)

{

// Find the max sd in master_set now

while (FD_ISSET(max_sd, &master_set) == FALSE)

{

--max_sd;

}

} // End of if (i == max_sd)

} // End of if (close_conn)

}

}

}

}

while (end_server == FALSE);

/* Close each sd in master_set */

for (i = 0; i < max_sd; ++i)

{

if (FD_ISSET(i, &master_set))

{

close(i);

}

}

return 0;

}

参考

http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzab6%2Frzab6xnonblock.htm

-

-

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值