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:

  1. 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.
  2. 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.
  3. After the socket descriptor is created, the bind() gets a unique name for the socket.
  4. The listen() allows the server to accept incoming client connections.
  5. 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.
  6. 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.
  7. The accept() and recv() APIs are completed when the EWOULDBLOCK is returned.
  8. The send() API echoes the data back to the client.
  9. The close() API closes any open socket descriptors.
Note: By using the examples, you agree to the terms of the Code license and disclaimer information.
 #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()的更多相关文章

  1. 【Pyhton Network】使用poll()或select()实现非阻塞传输

    通常情况下,socket上的I/O会阻塞.即除非操作结束,否则程序不会照常进行.而以下集中情况需要在非阻塞模式下进行:1. 网络接口在等待数据时是活动的,可以做出相应:2. 在不使用线程或进程的情况下 ...

  2. linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例

    除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnblogs.com/Anker/p/3265058.html 最简单的select示例: #incl ...

  3. linux select 与 阻塞( blocking ) 及非阻塞 (non blocking)实现io多路复用的示例【转】

    转自:https://www.cnblogs.com/welhzh/p/4950341.html 除了自己实现之外,还有个c语言写的基于事件的开源网络库:libevent http://www.cnb ...

  4. [转]何为C10K问题

    我在学习网络编程的时候经常看到C10K问题,那么究竟什么是C10K问题呢?我看到了一篇好文章就转了过来,原文地址为:c10k问题 所谓c10k问题,指的是服务器同时支持成千上万个客户端的问题,也就是c ...

  5. net programming guid

    Beej's Guide to Network Programming Using Internet Sockets Brian "Beej Jorgensen" Hallbeej ...

  6. Linux中epoll+线程池实现高并发

    服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下,每个线程 ...

  7. 高并发的epoll+线程池,线程池专注实现业务

    我们知道,服务器并发模型通常可分为单线程和多线程模型,这里的线程通常是指“I/O线程”,即负责I/O操作,协调分配任务的“管理线程”,而实际的请求和任务通常交由所谓“工作者线程”处理.通常多线程模型下 ...

  8. IO多路复用技术详解

      IO多路复用:I/O是指网络I/O,多路指多个TCP连接(即socket或者channel),复用指复用一个或几个线程.意思说一个或一组线程处理多个TCP连接.最大优势是减少系统开销小,不必创建过 ...

  9. I/O 复用 multiplexing data race 同步 coroutine 协程

    小结: 1.A file descriptor is considered ready if it is possible to perform the corresponding I/O opera ...

随机推荐

  1. JS函数运行在它们被定义的作用域内,而不是它们被执行的作用域内

    一个函数的作用域并不会因为被另一个函数调用而拓展,取得另一个函数的作用域: function show(name){ alert(name) } function show2(){ var name= ...

  2. 阿里云部署nodejs服务器(windows)

    花了大半个月做的网站终于要上线了,周围的同学们很多都在使用阿里云的服务器,我也入手了一台.考虑到自己不是很适应ubuntu的命令行界面,于是买了个windows的,上网搜了一下,似乎都是用linux来 ...

  3. 移动端H5页面高清多屏适配方案

    背景 开发移动端H5页面 面对不同分辨率的手机 面对不同屏幕尺寸的手机 视觉稿 在前端开发之前,视觉MM会给我们一个psd文件,称之为视觉稿. 对于移动端开发而言,为了做到页面高清的效果,视觉稿的规范 ...

  4. java类加载器加载文件

    例子:采用配置文件加反射的方式创建ArrayList和HashSet的实例对象. //第一种方式:类加载器加载文件 InputStream ips = ReflectTest2.class.getCl ...

  5. Ubuntu 12.04 安装 Apache2+PHP5+MySQL

    LAMP是Linux web服务器组合套装的缩写,分别是Apache+MySQL+PHP.此教程教大家如何在Ubuntu 12.04 LTS server 上安装Apache2服务器,包括PHP5(m ...

  6. CMS系统存储路径

    CMS系统特点:前后端分离 index.html 首页文件index.php 管理后台的页面 api文件夹: 提供的接口 caches文件夹: 缓存文件 html文件夹:  生成的静态页面 phpcm ...

  7. 377. Combination Sum IV

    问题 Given an integer array with all positive numbers and no duplicates, find the number of possible c ...

  8. Date、Calender类及日期和字符串转换

    Calendar是一个抽象类,抽象类java.util.Calendar 不可以通过new来获取一个实例,可以通过类方法getinstance()获取此类型的一个通用的对象 ①用法: Calendar ...

  9. MYsql 数据库密码忘记(Window)

    之前想在自己的机器上搭建一个数据库,但是又怕占用内存太大,因此特地从网上下载了一个绿色版,免安装版本的,开始用着 还可以,后来重启机器发现悲催了,数据库用不了了, 决心好好整整Mysql 我的是 版本 ...

  10. WPF 通过Border来画边框

    WPF有自己的表格控件DataGrid.ListBox等,如果只是简单的需求,可以通过Border控件来画边框. 比如我们需要给上面的控件加上边框. <Window x:Class=" ...