Nonblocking I/O and select()
This sample program illustrates a server application that uses nonblocking and the select() API.

Socket flow of events: Server that uses nonblocking I/O and select()
The following calls are used in the example:
- The socket() API returns a socket descriptor, which represents an endpoint. The statement also identifies that the INET (Internet Protocol) address family with the TCP transport (SOCK_STREAM) is used for this socket.
- The ioctl() API allows the local address to be reused when the server is restarted before the required wait time expires. In this example, it sets the socket to be nonblocking. All of the sockets for the incoming connections are also nonblocking because they inherit that state from the listening socket.
- After the socket descriptor is created, the bind() gets a unique name for the socket.
- The listen() allows the server to accept incoming client connections.
- The server uses the accept() API to accept an incoming connection request. The accept() API call blocks indefinitely, waiting for the incoming connection to arrive.
- The select() API allows the process to wait for an event to occur and to wake up the process when the event occurs. In this example, the select() API returns a number that represents the socket descriptors that are ready to be processed.
- 0
- Indicates that the process times out. In this example, the timeout is set for 3 minutes.
- -1
- Indicates that the process has failed.
- 1
- Indicates only one descriptor is ready to be processed. In this example, when a 1 is returned, the FD_ISSET and the subsequent socket calls complete only once.
- n
- Indicates that multiple descriptors are waiting to be processed. In this example, when an n is returned, the FD_ISSET and subsequent code loops and completes the requests in the order they are received by the server.
- The accept() and recv() APIs are completed when the EWOULDBLOCK is returned.
- The send() API echoes the data back to the client.
- The close() API closes any open socket descriptors.
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <errno.h> #define SERVER_PORT 12345 #define TRUE 1
#define FALSE 0 main (int argc, char *argv[])
{
int i, len, rc, on = ;
int listen_sd, max_sd, new_sd;
int desc_ready, end_server = FALSE;
int close_conn;
char buffer[];
struct sockaddr_in6 addr;
struct timeval timeout;
struct fd_set master_set, working_set; /*************************************************************/
/* Create an AF_INET6 stream socket to receive incoming */
/* connections on */
/*************************************************************/
listen_sd = socket(AF_INET6, SOCK_STREAM, );
if (listen_sd < )
{
perror("socket() failed");
exit(-);
} /*************************************************************/
/* Allow socket descriptor to be reuseable */
/*************************************************************/
rc = setsockopt(listen_sd, SOL_SOCKET, SO_REUSEADDR,
(char *)&on, sizeof(on));
if (rc < )
{
perror("setsockopt() failed");
close(listen_sd);
exit(-);
} /*************************************************************/
/* Set socket to be nonblocking. All of the sockets for */
/* the incoming connections will also be nonblocking since */
/* they will inherit that state from the listening socket. */
/*************************************************************/
rc = ioctl(listen_sd, FIONBIO, (char *)&on);
if (rc < )
{
perror("ioctl() failed");
close(listen_sd);
exit(-);
} /*************************************************************/
/* Bind the socket */
/*************************************************************/
memset(&addr, , sizeof(addr));
addr.sin6_family = AF_INET6;
memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
addr.sin6_port = htons(SERVER_PORT);
rc = bind(listen_sd,
(struct sockaddr *)&addr, sizeof(addr));
if (rc < )
{
perror("bind() failed");
close(listen_sd);
exit(-);
} /*************************************************************/
/* Set the listen back log */
/*************************************************************/
rc = listen(listen_sd, );
if (rc < )
{
perror("listen() failed");
close(listen_sd);
exit(-);
} /*************************************************************/
/* Initialize the master fd_set */
/*************************************************************/
FD_ZERO(&master_set);
max_sd = listen_sd;
FD_SET(listen_sd, &master_set); /*************************************************************/
/* Initialize the timeval struct to 3 minutes. If no */
/* activity after 3 minutes this program will end. */
/*************************************************************/
timeout.tv_sec = * ;
timeout.tv_usec = ; /*************************************************************/
/* Loop waiting for incoming connects or for incoming data */
/* on any of the connected sockets. */
/*************************************************************/
do
{
/**********************************************************/
/* Copy the master fd_set over to the working fd_set. */
/**********************************************************/
memcpy(&working_set, &master_set, sizeof(master_set)); /**********************************************************/
/* Call select() and wait 3 minutes for it to complete. */
/**********************************************************/
printf("Waiting on select()...\n");
rc = select(max_sd + , &working_set, NULL, NULL, &timeout); /**********************************************************/
/* Check to see if the select call failed. */
/**********************************************************/
if (rc < )
{
perror(" select() failed");
break;
} /**********************************************************/
/* Check to see if the 3 minute time out expired. */
/**********************************************************/
if (rc == )
{
printf(" select() timed out. End program.\n");
break;
} /**********************************************************/
/* One or more descriptors are readable. Need to */
/* determine which ones they are. */
/**********************************************************/
desc_ready = rc;
for (i=; i <= max_sd && desc_ready > ; ++i)
{
/*******************************************************/
/* Check to see if this descriptor is ready */
/*******************************************************/
if (FD_ISSET(i, &working_set))
{
/****************************************************/
/* A descriptor was found that was readable - one */
/* less has to be looked for. This is being done */
/* so that we can stop looking at the working set */
/* once we have found all of the descriptors that */
/* were ready. */
/****************************************************/
desc_ready -= ; /****************************************************/
/* Check to see if this is the listening socket */
/****************************************************/
if (i == listen_sd)
{
printf(" Listening socket is readable\n");
/*************************************************/
/* Accept all incoming connections that are */
/* queued up on the listening socket before we */
/* loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Accept each incoming connection. If */
/* accept fails with EWOULDBLOCK, then we */
/* have accepted all of them. Any other */
/* failure on accept will cause us to end the */
/* server. */
/**********************************************/
new_sd = accept(listen_sd, NULL, NULL);
if (new_sd < )
{
if (errno != EWOULDBLOCK)
{
perror(" accept() failed");
end_server = TRUE;
}
break;
} /**********************************************/
/* Add the new incoming connection to the */
/* master read set */
/**********************************************/
printf(" New incoming connection - %d\n", new_sd);
FD_SET(new_sd, &master_set);
if (new_sd > max_sd)
max_sd = new_sd; /**********************************************/
/* Loop back up and accept another incoming */
/* connection */
/**********************************************/
} while (new_sd != -);
} /****************************************************/
/* This is not the listening socket, therefore an */
/* existing connection must be readable */
/****************************************************/
else
{
printf(" Descriptor %d is readable\n", i);
close_conn = FALSE;
/*************************************************/
/* Receive all incoming data on this socket */
/* before we loop back and call select again. */
/*************************************************/
do
{
/**********************************************/
/* Receive data on this connection until the */
/* recv fails with EWOULDBLOCK. If any other */
/* failure occurs, we will close the */
/* connection. */
/**********************************************/
rc = recv(i, buffer, sizeof(buffer), );
if (rc < )
{
if (errno != EWOULDBLOCK)
{
perror(" recv() failed");
close_conn = TRUE;
}
break;
} /**********************************************/
/* Check to see if the connection has been */
/* closed by the client */
/**********************************************/
if (rc == )
{
printf(" Connection closed\n");
close_conn = TRUE;
break;
} /**********************************************/
/* Data was received */
/**********************************************/
len = rc;
printf(" %d bytes received\n", len); /**********************************************/
/* Echo the data back to the client */
/**********************************************/
rc = send(i, buffer, len, );
if (rc < )
{
perror(" send() failed");
close_conn = TRUE;
break;
} } while (TRUE); /*************************************************/
/* If the close_conn flag was turned on, we need */
/* to clean up this active connection. This */
/* clean up process includes removing the */
/* descriptor from the master set and */
/* determining the new maximum descriptor value */
/* based on the bits that are still turned on in */
/* the master set. */
/*************************************************/
if (close_conn)
{
close(i);
FD_CLR(i, &master_set);
if (i == max_sd)
{
while (FD_ISSET(max_sd, &master_set) == FALSE)
max_sd -= ;
}
}
} /* End of existing connection is readable */
} /* End of if (FD_ISSET(i, &working_set)) */
} /* End of loop through selectable descriptors */ } while (end_server == FALSE); /*************************************************************/
/* Clean up all of the sockets that are open */
/*************************************************************/
for (i=; i <= max_sd; ++i)
{
if (FD_ISSET(i, &master_set))
close(i);
}
}
Nonblocking I/O and select()的更多相关文章
- 【Pyhton Network】使用poll()或select()实现非阻塞传输
通常情况下,socket上的I/O会阻塞.即除非操作结束,否则程序不会照常进行.而以下集中情况需要在非阻塞模式下进行:1. 网络接口在等待数据时是活动的,可以做出相应:2. 在不使用线程或进程的情况下 ...
- linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例
除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnblogs.com/Anker/p/3265058.html 最简单的select示例: #incl ...
- linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例【转】
转自:https://www.cnblogs.com/welhzh/p/4950341.html 除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnb ...
- [转]何为C10K问题
我在学习网络编程的时候经常看到C10K问题,那么究竟什么是C10K问题呢?我看到了一篇好文章就转了过来,原文地址为:c10k问题 所谓c10k问题,指的是服务器同时支持成千上万个客户端的问题,也就是c ...
- net programming guid
Beej's Guide to Network Programming Using Internet Sockets Brian "Beej Jorgensen" Hallbeej ...
- Linux中epoll+线程池实现高并发
服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下,每个线程 ...
- 高并发的epoll+线程池,线程池专注实现业务
我们知道,服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下 ...
- IO多路复用技术详解
IO多路复用:I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程.意思说一个或一组线程处理多个TCP连接.最大优势是减少系统开销小,不必创建过 ...
- I/O 复用 multiplexing data race 同步 coroutine 协程
小结: 1.A file descriptor is considered ready if it is possible to perform the corresponding I/O opera ...
随机推荐
- canvas简介
一.canvas简介 1.1 什么是canvas?(了解) 是HTML5提供的一种新标签 <canvas></canvas> 英 ['kænvəs] 美 ['kænvəs] 帆 ...
- js数组中sort排序注意的地方
var a=[1,2,3,4,5] function sum(a,b) { return a-b } //从小到大 function obj(a,b) { return b-a } //从大到小 a. ...
- 使用zxing生成二维码
public static Bitmap Create2DCode(String str) throws WriterException { // 生成二维矩阵,编码时 ...
- 开发维护大型 Java 项目的建议
假设你是正在开发和维护一个包含2000个类并使用了很多框架的Java开发者.你要如何理解这些代码?在一个典型的Java企业项目小组中,大部 分能够帮你的高级工程师看起来都很忙.文档也很少.你需要尽快交 ...
- XP机器上WCF采用X509证书加密时IIS读取证书的授权
XP机器上WCF采用X509证书加密时IIS读取证书的授权 XP下的授权命令为:winhttpcertcfg -g -c LOCAL_MACHINE\My -s 证书名称 -a "ASPNE ...
- lvs+keepalived
一.简介 VS/NAT原理图: 二.系统环境 实验拓扑: 系统平台:CentOS 6.3 Kernel:2.6.32-279.el6.i686 LVS版本:ipvsadm-1.26 keepalive ...
- java方法强制传递引用参数(做为返回值),改变被传递参数值。
Java传递参数分为2种: 值类型,Java里面也叫简单类型,这种参数类型的传递的是它的副本拷贝: 引用类型,传递的是对象引用地址,如果在方法内改变该参数对象属性即是对原引用对象的改变:如果不想这样传 ...
- 51nod1183(Edit Distance)
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1183 题意:中文题啦- 思路:dp 用dp[i][j]表示从 ...
- SQLite文件查看工具DB Browser for SQLite
有时候,我们用Python创建了一个test.sqlite文件,想查看里面的数据,除了用Python连上数据库,SELECT出来,还有什么好办法呢?这里推荐使用一个小工具DB Browser for ...
- 截取QueryString 通过截取?和& 小写
$(function () { var url = location.href.replace("#", ""); var paraString = url.s ...