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 ...
随机推荐
- Javascript模块化编程(二):AMD规范
Javascript模块化编程(二):AMD规范 作者: 阮一峰 原文地址:http://www.ruanyifeng.com/blog/2012/10/asynchronous_module_d ...
- HTML5 图片本地压缩上传插件「localResizeIMG」
移动应用中用户往往需要上传照片,但是用户上传的照片尺寸通常很大,而手机的流量却很有限,所以在上传前对图像进行压缩是很有必要的. 原生应用可以直接对文件进行处理,网页应用就没有这个优势了.不过 canv ...
- android gpio口控制
android gpio口控制 GPIO口控制方式是在jni层控制的方式实现高低电平输出,类似linux的控制句柄方式,在linux系统下将每个设备看作一个文件,android系统是基于linux内 ...
- Python flask @app.route
转载自 http://python.jobbole.com/80956/ 下面是Flask主页给我们的第一个例子,我们现在就由它入手,深入理解“@app.route()”是如何工作的. ...
- 【TIP】已经上架的app在AppStore上搜不到的解决办法
相信很多人都遇到过这个问题,天天刷iTunes connect,终于发现app已经上架了,兴奋的跑过去告诉老板,老板说好,大家都装一个吧!然后大家过来问你怎么搜不到,老板看你都是一副这个表情: 这 ...
- WPF制作的VS黑色风格的Listbox
最近写的一个玩具,WPF写出来的东西还是挺好看的 style.xaml <ResourceDictionary xmlns="http://schemas.microsoft.com/ ...
- 有人要分享pjax吗?
安装 1.在 composer.json 的 require里 加入 "yuanchao/pjax-for-laravel-5": "dev-master" 2 ...
- 【python】发送post请求
1. json格式的post请求 关键部分加粗显示了,主要是post数据的编码方式以及请求头的Content-type #coding=utf8 import json import gzip imp ...
- 学号20145332 《信息安全系统设计基础》实验五 简单嵌入式WEB服务器实验
实验目的 掌握在 ARM 开发板实现一个简单 WEB 服务器的过程. 学习在 ARM 开发板上的 SOCKET 网络编程. 学习 Linux 下的 signal()函数的使用. 实验内容 学习使用 s ...
- 解决Eclipse Failed to write core dump. Minidumps are not enabled by default on client versions
-XX:+CreateMinidumpOnCrash 如果还有问题,就只能看日志了 T_T