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. 第三条:用私有构造器或者枚举类型强化Singleton属性

    1.使用单元素的枚举类型 public enum Singleton implements Serializable { INSTANCE; private String field; public ...

  2. 【JSTREE】 复选框默认选中【总结】

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"% ...

  3. CSS3实现鼠标移动到图片上图片变大

    CSS3实现鼠标移动到图片上图片变大(缓慢变大,有过渡效果,放大的过程是有动画过渡的,这个过渡的时间可以自定义 <!DOCTYPE html><html> <head&g ...

  4. HTML DOM Event 对象

    var event;if (document.createEvent){event = document.createEvent("HTMLEvents");event.initE ...

  5. CodeIgniter 3 源码学习笔记《一》

    CodeIgniter 是一套给 PHP 网站开发者使用的应用程序开发框架和工具包. 它的目标是让你能够更快速的开发,它提供了日常任务中所需的大量类库, 以及简单的接口和逻辑结构.通过减少代码量,Co ...

  6. js创建命名空间

    CreateNameSpace: function () { var nameSpaceObjec = arguments[0].split('.'); var currentNameSpaceNam ...

  7. 简单的ADO.NET连接数据小样例

    ADO.NET连接数据库的样例如下: using System; using System.Collections.Generic; using System.ComponentModel; usin ...

  8. webstorm基础使用总结

    webstorm基础使用总结(不仅仅是一堆快捷方式) 注:原文链接: 水车 :  本次写的内容是我想到那个就写那个,都是本人平时写代码的时候的一些习惯,未必是最好的,贵在交流! 1:  shift+e ...

  9. 漫谈iOS程序的证书和签名机制

    接触iOS开发半年,曾经也被这个主题坑的摸不着头脑,也在淘宝上买过企业证书签名这些服务,有大神都做了一个全自动的发布打包(不过此大神现在不卖企业证书了),甚是羡慕和崇拜.于是,花了一点时间去研究了一下 ...

  10. C++开始前篇,深入编译链接(3)

    一,COMMON块 什么是COMMON块,这是一种机制,早期的Fortran没有动态分配空间的机制,程序员必须事先声明它所需要的临时使用空间的大小.Fortran把这种空间叫做COMMON块,当不同的 ...