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. Linux下的压缩和解压缩命令——tar

    tar命令 选项: -c: 建立压缩档案 -x:解压 -t:查看内容 -r:向压缩归档文件末尾追加文件 -u:更新原压缩包中的文件 这五个是独立的命令,压缩解压都要用到其中一个,可以和别的命令连用但只 ...

  2. PHP 查看安装信息

    1.运行PHP脚本,查看phpinfo函数的输出. 2.在系统环境变量Path中配好php.exe可执行文件的路径,命令管理器CMD中,执行`php.exe -i`查看. 3.在phpinfo()的输 ...

  3. Unity3D 计算FPS

    using UnityEngine; using System.Collections; public class FPS : MonoBehaviour { private const string ...

  4. dom操作导致超级卡顿。。。

    var i=0;j=30;setinterval(function(){ document.getElementId(idname).style.top=j+'px'; i<3?i++:i=0; ...

  5. tomcat虚拟路径

    目的:减小项目大小,方便部署和资源共享 tomcat/conf/server.xml host 标签中添加 p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: ...

  6. gulp学习-gulpfile

    安装gulp 假设已经安装了node 和npm (淘宝的cnpm很适合国内使用). 1.首页全局安装gulp. 1 npm install --global gulp 2.其次局部安装gulp.(注: ...

  7. 深入理解Objective-C:Category

    摘要 无论一个类设计的多么完美,在未来的需求演进中,都有可能会碰到一些无法预测的情况.那怎么扩展已有的类呢?一般而言,继承和组合是不错的选择.但是在Objective-C 2.0中,又提供了categ ...

  8. php 批量删除

    <body><form action="shanchu.php" method="post"><table width=" ...

  9. 素数的平方阶群必为Abel群

    定理  设$p$为素数,则$p^2$阶群$G$必为Abel群.

  10. JS基础学习(二)

    昨天把网站上的基础知识看完了,下面是剩下的部分 第六节 JS Window浏览器对象模型 JavaScript全局对象,函数,变量均自动成为window对象的成员. 1.Window对象 1.获取浏览 ...