五种I/O模型

1、阻塞I/O     2、非阻塞I/O     3 、I/O复用(select和poll)   4、信号驱动I/O    5、异步I/O

select函数I/O复用:

select Function

The select function determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.

int select(
  __in          int nfds,
  __in_out      fd_set* readfds,
  __in_out      fd_set* writefds,
  __in_out      fd_set* exceptfds,
  __in          const struct timeval* timeout
);

Parameters

nfds

Ignored. The nfds parameter is included only for compatibility with Berkeley sockets.

readfds

Optional pointer to a set of sockets to be checked for readability.

writefds

Optional pointer to a set of sockets to be checked for writability.

exceptfds

Optional pointer to a set of sockets to be checked for errors.

timeout

Maximum time for select to wait, provided in the form of a TIMEVAL structure. Set the timeout parameter to null for blocking operations.

Return Value

The select function returns the total number of socket handles that are ready and contained in thefd_set structures, zero if the time limit expired, or SOCKET_ERROR
if an error occurred. If the return value is SOCKET_ERROR,WSAGetLastError can be used to retrieve a specific error code.

Error code Meaning

WSANOTINITIALISED


A successful WSAStartup call must occur before using this function.


WSAEFAULT


The Windows Sockets implementation was unable to allocate needed resources for its internal operations, or thereadfds,
writefds, exceptfds, or timeval parameters are not part of the user address space.


WSAENETDOWN


The network subsystem has failed.


WSAEINVAL


The time-out value is not valid, or all three descriptor parameters were null.


WSAEINTR


A blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall.


WSAEINPROGRESS


A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function.


WSAENOTSOCK


One of the descriptor sets contains an entry that is not a socket.

Remarks

The select function is used to determine the status of one or more sockets. For each socket, the caller can request information on read, write, or error status. The set of sockets for which a given status is requested is indicated by anfd_set
structure. The sockets contained within thefd_set structures must be associated with a single service provider. For the purpose of this restriction, sockets are considered to be from the same service provider if theWSAPROTOCOL_INFO
structures describing their protocols have the sameproviderId value. Upon return, the structures are updated to reflect the subset of these sockets that meet the specified condition. Theselect function returns the number of sockets
meeting the conditions. A set of macros is provided for manipulating anfd_set structure. These macros are compatible with those used in the Berkeley software, but the underlying representation is completely different.

The parameter readfds identifies the sockets that are to be checked for readability. If the socket is currently in thelisten state, it will be marked as readable if an incoming
connection request has been received such that anaccept is guaranteed to complete without blocking. For other sockets, readability means that queued data is available for reading such
that a call torecv,
WSARecv,
WSARecvFrom, orrecvfrom is guaranteed not to block.

For connection-oriented sockets, readability can also indicate that a request to close the socket has been received from the peer. If the virtual circuit was closed gracefully, and all data was received, then arecv will return immediately
with zero bytes read. If the virtual circuit was reset, then arecv will complete immediately with an error code such asWSAECONNRESET.
The presence of OOB data will be checked if the socket option SO_OOBINLINE has been enabled (seesetsockopt).

The parameter writefds identifies the sockets that are to be checked for writability. If a socket is processing aconnect call (nonblocking), a socket is writeable if the
connection establishment successfully completes. If the socket is not processing aconnect call, writability means a
send, sendto, orWSASendto are guaranteed to succeed. However, they can block on a blocking socket if thelen parameter exceeds the amount of outgoing system
buffer space available. It is not specified how long these guarantees can be assumed to be valid, particularly in a multithreaded environment.

The parameter exceptfds identifies the sockets that are to be checked for the presence of OOB data or any exceptional error conditions.

Note  Out-of-band data will only be reported in this way if the option SO_OOBINLINE is FALSE. If a socket is processing aconnect call (nonblocking), failure of the connect attempt is indicated inexceptfds
(application must then call getsockopt SO_ERROR to determine the error value to describe why the failure occurred). This document does not define which other errors will be included.

Any two of the parameters, readfds, writefds, or exceptfds, can be given as null. At least one must be non-null, and any non-null descriptor set must contain at least one handle to a socket.

In summary, a socket will be identified in a particular set when select returns if:

readfds:

  • If listen has been called and a connection is pending,accept will succeed.
  • Data is available for reading (includes OOB data if SO_OOBINLINE is enabled).
  • Connection has been closed/reset/terminated.

writefds:

  • If processing a connect call (nonblocking), connection has succeeded.
  • Data can be sent.

exceptfds:

  • If processing a connect call (nonblocking), connection attempt failed.
  • OOB data is available for reading (only if SO_OOBINLINE is disabled).

Four macros are defined in the header file Winsock2.h for manipulating and checking the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which can be modified by defining
FD_SETSIZE to another value before including Winsock2.h.) Internally, socket handles in anfd_set structure are not represented as bit flags as in Berkeley Unix. Their data representation is opaque. Use of these macros will maintain software
portability between different socket environments. The macros to manipulate and checkfd_set contents are:

FD_CLR(s, *set)

Removes the descriptor s from set.

FD_ISSET(s, *set)

Nonzero if s is a member of the set. Otherwise, zero.

FD_SET(s, *set)

Adds descriptor s to set.

FD_ZERO(*set)

Initializes the set to the null set.

The parameter time-out controls how long the select can take to complete. Iftime-out is a null pointer,
select will block indefinitely until at least one descriptor meets the specified criteria. Otherwise,time-out points to a
TIMEVAL structure that specifies the maximum time thatselect should wait before returning. When
select returns, the contents of theTIMEVAL structure are not altered. If
TIMEVAL is initialized to {0, 0},select will return immediately; this is used to poll the state of the selected sockets. Ifselect returns immediately, then the
select call is considered nonblocking and the standard assumptions for nonblocking calls apply. For example, the blocking hook will not be called, and Windows Sockets will not yield.

Note  The select function has no effect on the persistence of socket events registered withWSAAsyncSelect orWSAEventSelect.

Requirements


Client


Requires Windows Vista, Windows XP, Windows 2000 Professional, Windows NT Workstation, Windows Me, Windows 98, or Windows 95.


Server


Requires Windows Server 2008, Windows Server 2003, Windows 2000 Server, or Windows NT Server.


Header


Declared in Winsock2.h.


Library


Use Ws2_32.lib.


DLL


Requires Ws2_32.dll.

echocli.c

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <signal.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#define ERR_EXIT(m) \

do \

{ \

perror(m); \

exit(EXIT_FAILURE); \

} while(0)

ssize_t readn(int fd, void *buf, size_t count)

{

size_t nleft = count;

ssize_t nread;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nread = read(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}

return count;

}

ssize_t writen(int fd, const void *buf, size_t count)

{

size_t nleft = count;

ssize_t nwritten;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nwritten = write(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}

return count;

}

ssize_t recv_peek(int sockfd, void *buf, size_t len)

{

while (1)

{

int ret = recv(sockfd, buf, len, MSG_PEEK);

if (ret == -1 && errno == EINTR)

continue;

return ret;

}

}

ssize_t readline(int sockfd, void *buf, size_t maxline)

{

int ret;

int nread;

char *bufp = buf;

int nleft = maxline;

while (1)

{

ret = recv_peek(sockfd, bufp, nleft);

if (ret < 0)

return ret;

else if (ret == 0)

return ret;

nread = ret;

int i;

for (i=0; i<nread; i++)

{

if (bufp[i] == ‘\n‘)

{

ret = readn(sockfd, bufp, i+1);

if (ret != i+1)

exit(EXIT_FAILURE);

return ret;

}

}

if (nread > nleft)

exit(EXIT_FAILURE);

nleft -= nread;

ret = readn(sockfd, bufp, nread);

if (ret != nread)

exit(EXIT_FAILURE);

bufp += nread;

}

return -1;

}

void echo_cli(int sock)

{

/*

char sendbuf[1024] = {0};

char recvbuf[1024] = {0};

while (fgets(sendbuf, sizeof(sendbuf), stdin) != NULL)

{

writen(sock, sendbuf, strlen(sendbuf));

int ret = readline(sock, recvbuf, sizeof(recvbuf));

if (ret == -1)

ERR_EXIT("readline");

else if (ret == 0)

{

printf("client close\n");

break;

}

fputs(recvbuf, stdout);

memset(sendbuf, 0, sizeof(sendbuf));

memset(recvbuf, 0, sizeof(recvbuf));

}

close(sock);

*/

fd_set rset;

FD_ZERO(&rset);

int nready;

int maxfd;

int fd_stdin = fileno(stdin);

if (fd_stdin > sock)

maxfd = fd_stdin;

else

maxfd = sock;

char sendbuf[1024] = {0};

char recvbuf[1024] = {0};

while (1)

{

FD_SET(fd_stdin, &rset);

FD_SET(sock, &rset);

nready = select(maxfd+1, &rset, NULL, NULL, NULL);

if (nready == -1)

ERR_EXIT("select");

if (nready == 0)

continue;

if (FD_ISSET(sock, &rset))

{

int ret = readline(sock, recvbuf, sizeof(recvbuf));

if (ret == -1)

ERR_EXIT("readline");

else if (ret == 0)

{

printf("server close\n");

break;

}

fputs(recvbuf, stdout);

memset(recvbuf, 0, sizeof(recvbuf));

}

if (FD_ISSET(fd_stdin, &rset))

{

if (fgets(sendbuf, sizeof(sendbuf), stdin) == NULL)

break;

writen(sock, sendbuf, strlen(sendbuf));

memset(sendbuf, 0, sizeof(sendbuf));

}

}

close(sock);

}

void handle_sigpipe(int sig)

{

printf("recv a sig=%d\n", sig);

}

int main(void)

{

/*

signal(SIGPIPE, handle_sigpipe);

*/

signal(SIGPIPE, SIG_IGN);

int sock;

if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

ERR_EXIT("socket");

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(5188);

servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");

if (connect(sock, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

ERR_EXIT("connect");

struct sockaddr_in localaddr;

socklen_t addrlen = sizeof(localaddr);

if (getsockname(sock, (struct sockaddr*)&localaddr, &addrlen) < 0)

ERR_EXIT("getsockname");

printf("ip=%s port=%d\n", inet_ntoa(localaddr.sin_addr), ntohs(localaddr.sin_port));

echo_cli(sock);

return 0;

}

echosrv.c

#include <unistd.h>

#include <sys/types.h>

#include <sys/socket.h>

#include <netinet/in.h>

#include <arpa/inet.h>

#include <signal.h>

#include <sys/wait.h>

#include <stdlib.h>

#include <stdio.h>

#include <errno.h>

#include <string.h>

#define ERR_EXIT(m) \

do \

{ \

perror(m); \

exit(EXIT_FAILURE); \

} while(0)

ssize_t readn(int fd, void *buf, size_t count)

{

size_t nleft = count;

ssize_t nread;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nread = read(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nread == 0)

return count - nleft;

bufp += nread;

nleft -= nread;

}

return count;

}

ssize_t writen(int fd, const void *buf, size_t count)

{

size_t nleft = count;

ssize_t nwritten;

char *bufp = (char*)buf;

while (nleft > 0)

{

if ((nwritten = write(fd, bufp, nleft)) < 0)

{

if (errno == EINTR)

continue;

return -1;

}

else if (nwritten == 0)

continue;

bufp += nwritten;

nleft -= nwritten;

}

return count;

}

ssize_t recv_peek(int sockfd, void *buf, size_t len)

{

while (1)

{

int ret = recv(sockfd, buf, len, MSG_PEEK);

if (ret == -1 && errno == EINTR)

continue;

return ret;

}

}

ssize_t readline(int sockfd, void *buf, size_t maxline)

{

int ret;

int nread;

char *bufp = buf;

int nleft = maxline;

while (1)

{

ret = recv_peek(sockfd, bufp, nleft);

if (ret < 0)

return ret;

else if (ret == 0)

return ret;

nread = ret;

int i;

for (i=0; i<nread; i++)

{

if (bufp[i] == ‘\n‘)

{

ret = readn(sockfd, bufp, i+1);

if (ret != i+1)

exit(EXIT_FAILURE);

return ret;

}

}

if (nread > nleft)

exit(EXIT_FAILURE);

nleft -= nread;

ret = readn(sockfd, bufp, nread);

if (ret != nread)

exit(EXIT_FAILURE);

bufp += nread;

}

return -1;

}

void echo_srv(int conn)

{

char recvbuf[1024];

while (1)

{

memset(recvbuf, 0, sizeof(recvbuf));

int ret = readline(conn, recvbuf, 1024);

if (ret == -1)

ERR_EXIT("readline");

if (ret == 0)

{

printf("client close\n");

break;

}

fputs(recvbuf, stdout);

writen(conn, recvbuf, strlen(recvbuf));

}

}

void handle_sigchld(int sig)

{

/*    wait(NULL);*/

while (waitpid(-1, NULL, WNOHANG) > 0)

;

}

int main(void)

{

/*    signal(SIGCHLD, SIG_IGN);*/

signal(SIGCHLD, handle_sigchld);

int listenfd;

if ((listenfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)

/*    if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0)*/

ERR_EXIT("socket");

struct sockaddr_in servaddr;

memset(&servaddr, 0, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(5188);

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

/*servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");*/

/*inet_aton("127.0.0.1", &servaddr.sin_addr);*/

int on = 1;

if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)

ERR_EXIT("setsockopt");

if (bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)

ERR_EXIT("bind");

if (listen(listenfd, SOMAXCONN) < 0)

ERR_EXIT("listen");

struct sockaddr_in peeraddr;

socklen_t peerlen;

int conn;

/*

pid_t pid;

while (1)

{

if ((conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen)) < 0)

ERR_EXIT("accept");

printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

pid = fork();

if (pid == -1)

ERR_EXIT("fork");

if (pid == 0)

{

close(listenfd);

echo_srv(conn);

exit(EXIT_SUCCESS);

}

else

close(conn);

}

*/

int i;

int client[FD_SETSIZE];

int maxi = 0;

for (i=0; i<FD_SETSIZE; i++)

client[i] = -1;

int nready;

int maxfd = listenfd;

fd_set rset;

fd_set allset;

FD_ZERO(&rset);

FD_ZERO(&allset);

FD_SET(listenfd, &allset);

while (1)

{

rset = allset;

nready = select(maxfd+1, &rset, NULL, NULL, NULL);

if (nready == -1)

{

if (errno == EINTR)

continue;

ERR_EXIT("select");

}

if (nready == 0)

continue;

if (FD_ISSET(listenfd, &rset))

{

peerlen = sizeof(peeraddr);

conn = accept(listenfd, (struct sockaddr*)&peeraddr, &peerlen);

if (conn == -1)

ERR_EXIT("accept");

for (i=0; i<FD_SETSIZE; i++)

{

if (client[i] < 0)

{

client[i] = conn;

if (i > maxi)

maxi = i;

break;

}

}

if (i == FD_SETSIZE)

{

fprintf(stderr, "too many clients\n");

exit(EXIT_FAILURE);

}

printf("ip=%s port=%d\n", inet_ntoa(peeraddr.sin_addr), ntohs(peeraddr.sin_port));

FD_SET(conn, &allset);

if (conn > maxfd)

maxfd = conn;

if (--nready <= 0)

continue;

}

for (i=0; i<=maxi; i++)

{

conn = client[i];

if (conn == -1)

continue;

if (FD_ISSET(conn, &rset))

{

char recvbuf[1024] = {0};

int ret = readline(conn, recvbuf, 1024);

if (ret == -1)

ERR_EXIT("readline");

if (ret == 0)

{

printf("client close\n");

FD_CLR(conn, &allset);

client[i] = -1;

}

fputs(recvbuf, stdout);

writen(conn, recvbuf, strlen(recvbuf));

if (--nready <= 0)

break;

}

}

}

return 0;

}

makefile:

.PHONY:clean all

CC=gcc

CFLAGS=-Wall -g

BIN=echosrv echocli

all:$(BIN)

%.o:%.c

$(CC) $(CFLAGS) -c $< -o [email protected]

clean:

rm -f *.o $(BIN)

五种I/O模型

时间: 2024-10-10 15:29:14

五种I/O模型的相关文章

Unix网络编程中的五种I/O模型_转

转自:Unix网络编程中的的五种I/O模型 下面主要是把unp第六章介绍的五种I/O模型. 1. 阻塞I/O模型 例如UDP函数recvfrom的内核到应用层.应用层到内核的调用过程是这样的:首先把描述符.接受数据缓冲地址.大小传递给内核,但是如果此时 该与该套接口相应的缓冲区没有数据,这个时候就recvfrom就会卡(阻塞)在这里,知道数据到来的时候,再把数据拷贝到应用层,也就是传进来的地址空 间,如果没有数据到来,就会使该函数阻塞在那里,这就叫做阻塞I/O模型,如下图: 2. 非阻塞I/O模

Windows Socket五种I/O模型——代码全攻略(转)

Winsock 的I/O操作: 1. 两种I/O模式 阻塞模式:执行I/O操作完成前会一直进行等待,不会将控制权交给程序.套接字 默认为阻塞模式.可以通过多线程技术进行处理. 非阻塞模式:执行I/O操作时,Winsock函数会返回并交出控制权.这种模式使用 起来比较复杂,因为函数在没有运行完成就进行返回,会不断地返回 WSAEWOULDBLOCK错误.但功能强大.为了解决这个问题,提出了进行I/O操作的一些I/O模型,下面介绍最常见的三种: Windows Socket五种I/O模型——代码全攻

五种I/O模型简述

在说I/O模型之前,我们先来说说同步,异步,阻塞,非阻塞这四种调用方式的概念: 同步:在发出一个功能调用时,在没有得到结果之前,该调用就不返回,通俗点就是必须一件一件的做事,等这件事做完了才能做下一件事: 异步:异步和同步正好相对,当一个异步过程调用发出后,调用者不能立即得到结果,当该异步调用完成后,通过状态,通知和回调来通知调用者. 阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起(线程进入非可执行状态,在这个状态之下,cpu不会给线程分配时间片,即线程暂停运行),函数只有在得到结果之后才

Unix系统的五种I/O模型

Unix下共有五种I/O模型: 1. 阻塞式I/O  2. 非阻塞式I/O  3. I/O复用(select和poll)  4. 信号驱动式I/O(SIGIO)  5. 异步I/O(POSIX的aio_系列函数)  io请求分两步: 1. 先将数据从存储介质(磁盘,网络等)拷贝到内核缓冲区,此时称为数据准备好,可以被用户应用程序读取. 2. 由用户应用程序拷贝内核缓冲区中的数据到用户缓冲区. ① 阻塞I/O模型            进程一直阻塞,直到数据拷贝完成 我们将函数recvfrom视为

(转载)Windows Socket五种I/O模型——代码全攻略

如果你想在Windows平台上构建服务器应用,那么I/O模型是你必须考虑的.Windows操作系统提供了选择(Select).异步选择(WSAAsyncSelect).事件选择(WSAEventSelect).重叠I/O(Overlapped I/O)和完成端口(Completion Port)共五种I/O模型.每一种模型均适用于一种特定的应用场景.程序员应该对自己的应用需求非常明确,而且综合考虑到程序的扩展性和可移植性等因素,作出自己的选择. 我会以一个回应反射式服务器(与<Windows网络

[]转帖] 浅谈Linux下的五种I/O模型

浅谈Linux下的五种I/O模型 https://www.cnblogs.com/chy2055/p/5220793.html  一.关于I/O模型的引出 我们都知道,为了OS的安全性等的考虑,进程是无法直接操作I/O设备的,其必须通过系统调用请求内核来协助完成I/O动作,而内核会为每个I/O设备维护一个buffer.如下图所示: 整个请求过程为: 用户进程发起请求,内核接受到请求后,从I/O设备中获取数据到buffer中,再将buffer中的数据copy到用户进程的地址空间,该用户进程获取到数

五种I/O模型的学习

来自   http://www.52im.net/thread-1935-1-1.html 4.互联网服务端处理网络请求的原理 首先看看一个典型互联网服务端处理网络请求的典型过程:<ignore_js_op> 由上图可以看到,主要处理步骤包括: 1)获取请求数据,客户端与服务器建立连接发出请求,服务器接受请求(1-3): 2)构建响应,当服务器接收完请求,并在用户空间处理客户端的请求,直到构建响应完成(4): 3)返回数据,服务器将已构建好的响应再通过内核空间的网络 I/O 发还给客户端(5-

Unix下可用的五种 I/O 模型

介绍 当TCP客户端同时处理两个输入时:标准输入和TCP套接字,当客户端fgets(在标准输入上)被阻塞并且服务器进程被终止时,我们遇到了问题.服务器TCP正确地将FIN发送到客户端TCP,但由于客户端进程被禁止从标准输入读取,所以它从没有看到EOF,直到它从套接字读取(可能更晚). 如果一个或多个I / O条件准备好(即,输入准备好被读取,或者描述符能够获得更多输出),我们希望得到通知.此功能称为 I/O 多路复用,由select和poll函数以及前者的较新POSIX变体提供,称为pselec

【Java】设计模型-五种单例模型

一. 什么是单例模式 只需要某个类同时保留一个对象,不希望有更多对象,此时,我们则应考虑单例模式的设计. 单例模式的主要作用是保证在Java程序中,某个类只有一个实例存在. 单例模式有很多好处,它能够避免实例对象的重复创建,不仅可以减少每次创建对象的时间开销,还可以节约内存空间: 能够避免由于操作多个实例导致的逻辑错误.如果一个对象有可能贯穿整个应用程序,而且起到了全局统一管理控制的作用,那么单例模式也许是一个值得考虑的选择. 二. 单例模式的特点 1. 单例模式只能有一个实例. 2. 单例类必