半super16mm 全画幅换算要淘汰了我是卖了换全幅,还是继续用再上个

《Windows网络编程》_罗莉琴版_8.3节_基于Select模型的Socket编程_代码 | 独立观察员o博客
当前位置:& &
& 《Windows网络编程》_罗莉琴版_8.3节_基于Select模型的Socket编程_代码
《》_版_8.3节_基于的编程_代码
这是等人编著的《》(《Windows Network Programming》)一书2011.04版(我们网络编程的课本)中,第8.3小节——”基于Select模型的编程”中的代码。
配套的代码中没有这个,课件(PPT)中有前面一小部分代码,网上也没找到这个,为了做作业,只好手敲了。手打得挺辛苦,为了大家不再辛苦,所以发上来。另外,有些小地方做了改动,还有难免可能出错,所以建议对照书本学习。
以下就是代码:
基于Select模型的Socket编程之回显服务器
#include &stdio.h&
#include &winsock2.h&
#pragma comment(lib, "ws2_32.lib")
#include &tchar.h&
#define PORT 8888
#define DATA_BUFSIZE 1024
Select()函数原型:
int select(
//会被忽略;
fd_set * readfds,
//用于检测可读性的Socket集合;
fd_set * writefds,
//可写性的;
fd_set * exceptfds,
//错误的;
const struct timeval* timeout
//等待的时间,设为null则是阻塞模式;
typedef struct fd_set {
SOCKET fd_array[FD_SETSIZE];
FD_CLR(s, *set)
从集合中删除指定的套接字;
FD_ISSET(s, *set)
如果参数s是集合中的成员,则返回非0值,否则返回0;
FD_SET(s, *set)
向集合中添加套接字;
FD_ZERO(s, *set)
将集合初始化为空集合;
《Windows网络编程》 8.3 基于Select模型的Socket编程;
独立观察员倾情手打
typedef struct _SOCKET_INFORMATION{
Buffer[DATA_BUFSIZE];// 发送和接收数据的缓冲区
DataB // 定义发送和接收数据缓冲区的结构体,包括缓冲区的长度和内容
S // 与客户端进行通信的套接字
BytesSEND; // 保存套接字发送的字节数
BytesRECV; // 保存套接字接收的字节数
}SOCKET_INFORMATION, * LPSOCKET_INFORMATION;
/* winsock2.h中定义的结构体;
typedef struct _WSABUF {
// the length of the buffer
char FAR *
// the pointer to the buffer
} WSABUF, FAR * LPWSABUF;
//记录正在使用的套接字总数量;
DWORD TotalSockets = 0;
//保存Socket信息对象的数组(Socket集合),FD_SETSIZE表示SELECT模型中允许的最大Socket数量(64);
LPSOCKET_INFORMATION
SocketArray[FD_SETSIZE];
ListenS // 监听套接字
AcceptS // 与客户端进行通信的套接字
SOCKADDR_IN
InternetA // 服务器的地址
// 用于初始化套接字环境
// WinSock API的返回值
// 获取可写性的套接字集合
// 获取可读性的套接字集合
Total = 0;
// 处于就绪状态的套接字数量
// 发送的字节数
// 接收的字节数
BOOL CreateSocketInformation(SOCKET s)
LPSOCKET_INFORMATION
SI; // 用于保存套接字的信息
// 为SI分配内存空间
if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR, sizeof(SOCKET_INFORMATION))) == NULL)
printf("GlobalAlloc() failed with error %d\n", GetLastError());
// 初始化SI的值
SI-&Socket =
//与客户端进行通信的套接字;
SI-&BytesSEND = 0;
//发送的字节数初始为0;
SI-&BytesRECV = 0;
//接收的字节数也为0;
// 在SocketArray数组中增加一个新元素,用于保存SI对象
SocketArray[TotalSockets] = SI;
TotalSockets++;
// 增加套接字数量
return(TRUE);
void FreeSocketInformation(DWORD Index)
// 获取指定索引对应的LPSOCKET_INFORMATION对象
LPSOCKET_INFORMATION SI = SocketArray[Index];
closesocket(SI-&Socket);
// 关闭套接字
//printf("Closing socket number %d\n", SI-&Socket);
// 释放指定LPSOCKET_INFORMATION对象资源
GlobalFree(SI);
// 将数组中index索引后面的元素前移
for (DWORD i = I i & TotalS i++)
SocketArray[i] = SocketArray[i+1];
TotalSockets--;
// 套接字总数减
int _tmain(int argc, _TCHAR* argv[])
//初始化WinSock环境;
if((Ret = WSAStartup(0x0202,&wsaData)) != 0)
printf("WSAStartup() failed with error %d\n", Ret);
WSACleanup();
return -1;
//创建用于监听的Socket,WSASocket是Windows专用,支持异步操作;
if((ListenSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)
printf("WSAStartup() failed with error %d\n", WSAGetLastError());
return -1;
//设置监听地址和端口号;
InternetAddr.sin_family = AF_INET; //Address family
InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Wild card IP address
InternetAddr.sin_port = htons(PORT); //port to use
//绑定监听Socket到本地地址和端口;
if(bind( ListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr) ) == SOCKET_ERROR)
printf("bind() failed with error %d\n", WSAGetLastError());
return -1;
//开始监听;
if(listen(ListenSocket, 5))
//同时设置等待队列长度;
printf("listen() failed with error %d\n", WSAGetLastError());
return -1;
//设置为非阻塞模式;
ULONG NonBlock = 1;
if(ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return -1;
//为ListenSocket Socket创建对应的SOCKET_INFORMATION
//这样就可以把ListenSocket添加到SocketArray数组中;
CreateSocketInformation(ListenSocket);
while(TRUE)
//准备用于网络I/O通知的读/写Socket集合
FD_ZERO(&ReadSet);
//将集合初始化为空集合;
FD_ZERO(&WriteSet);
//向ReadSet集合添加监听Socket ListenSocket
FD_SET(ListenSocket, &ReadSet);
//将SocketArray数组中的所有Socket添加到WriteSet和ReadSet集合中
//SocketArray数组中保存着监听Socket和所有与客户端进行通信的Socket
//这样就可以使用Select()判断哪个Socket有接入数据或者读取/写入数据
for(DWORD i=0; i&TotalS i++)
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
FD_SET(SocketInfo-&Socket, &WriteSet);
FD_SET(SocketInfo-&Socket, &ReadSet);
//判断读/写Socket集合中就绪的Socket
if((Total = select(0,&ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR)
printf("select() returned with error %d\n", WSAGetLastError());
return -1;
//依次处理所有的Socket。本服务器是一个回应服务器,即将从客户端收到的字符串再发回到客户端
for(DWORD j=0; j&TotalS j++)
//SocketInfo为当前要处理的Socket信息
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
//判断当前Socket的可读性,即是否有接入的连接请求或者可以接收数据
if(FD_ISSET(SocketInfo-&Socket, &ReadSet))
//对于监听Socket来说,可读表示有新的连接请求
if(SocketInfo-&Socket == ListenSocket)
Total--; //就绪的Socket减1
//接受连接请求,得到与客户端进行通信的Socket AcceptSocket
if((AcceptSocket = accept(ListenSocket, NULL,NULL)) != INVALID_SOCKET)
//设置Socket AcceptSocket为非阻塞模式;
//这样服务器在调用WSASend()函数发送数据时就不会被阻塞
NonBlock = 1;
if(ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return -1;
//创建套接字信息,初始化LPSOCKET_INFORMATION结构体数据,
//将AcceptSocket(也就是新的Socket)添加到SocketArray数组中
if(CreateSocketInformation(AcceptSocket) == FALSE)
return -1;
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("accept() failed with error %d\n", WSAGetLastError());
return -1;
//对于其它Socket来说,表示可接收数据;
//如果当前Socket在ReadSet集合中,则表明该Socket上有可以读取的数据
if(FD_ISSET(SocketInfo-&Socket, &ReadSet))
//减少一个处于就绪状态的套接字
memset(SocketInfo-&Buffer, ' ', DATA_BUFSIZE);
//初始化缓冲区
SocketInfo-&DataBuf.buf = SocketInfo-&B //初始化缓冲区位置
SocketInfo-&DataBuf.len = DATA_BUFSIZE;
//初始化缓冲区长度
//接收数据
DWORD Flags = 0;
if(WSARecv(SocketInfo-&Socket, &(SocketInfo-&DataBuf), 1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)
//错误编码等于WSAEWOULDBLOCK表示暂时没有数据,否则表示出现异常
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i); //释放Socket信息;
//接收数据未出错
SocketInfo-&BytesRECV = RecvB
//记录接收数据的字节数
if(RecvBytes == 0)
//如果收到0个字节,则表示对方关闭连接
FreeSocketInformation(i); //释放Socket信息;
//如果成功接收数据则打印收到的数据;
printf(SocketInfo-&DataBuf.buf);
printf("\n");
//不是落在ReadSet集合内
//如果当前Socket在WriteSet集合中,则表明该Socket的内部数据缓冲区有数据可以发送
if(FD_ISSET(SocketInfo-&Socket, &WriteSet))
Total--; //就绪的Socket减1
//初始化缓冲区位置
SocketInfo-&DataBuf.buf = SocketInfo-&Buffer + SocketInfo-&BytesSEND;//因为是回显程序?
//初始化缓冲区长度
SocketInfo-&DataBuf.len = SocketInfo-&BytesRECV - SocketInfo-&BytesSEND;
if(SocketInfo-&DataBuf.len & 0)
if(WSASend(SocketInfo-&Socket, &(SocketInfo-&DataBuf), 1, &SendBytes, 0, NULL, NULL) == SOCKET_ERROR)
//错误编码等于WSAEWOULDBLOCK表示暂时没有数据,否则表示出现异常
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i); //释放Socket信息;
//发送数据未出错;
SocketInfo-&BytesSEND += SendB
//记录发送数据的字节数
//如果从客户端接收到的数据都已经发回到客户端
//则将发送和接收的字节数量设置为0
if(SocketInfo-&BytesSEND == SocketInfo-&BytesRECV)
SocketInfo-&BytesSEND = 0;
SocketInfo-&BytesRECV = 0;
}//for语句结束
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
#include &stdio.h&#include &winsock2.h&#pragma comment(lib, "ws2_32.lib")#include &tchar.h&&#define PORT 8888#define DATA_BUFSIZE 1024&/*Select()函数原型:int select( int nfds,&&//会被忽略; fd_set * readfds,&&//用于检测可读性的Socket集合; fd_set * writefds,&&//可写性的; fd_set * exceptfds,&&//错误的; const struct timeval* timeout&&//等待的时间,设为null则是阻塞模式;);typedef struct fd_set {&&u_int fd_ &&SOCKET fd_array[FD_SETSIZE]; } fd_&FD_CLR(s, *set)&&&&从集合中删除指定的套接字;FD_ISSET(s, *set)&&如果参数s是集合中的成员,则返回非0值,否则返回0;FD_SET(s, *set)&&&&向集合中添加套接字;FD_ZERO(s, *set)&& 将集合初始化为空集合;*/&/*《Windows网络编程》 8.3 基于Select模型的Socket编程;独立观察员倾情手打 */&typedef struct _SOCKET_INFORMATION{&& &&&&CHAR&&&& Buffer[DATA_BUFSIZE];// 发送和接收数据的缓冲区&&&&WSABUF&& DataBuf; // 定义发送和接收数据缓冲区的结构体,包括缓冲区的长度和内容&&&&SOCKET&& Socket; // 与客户端进行通信的套接字&&&&DWORD&&&&BytesSEND; // 保存套接字发送的字节数&&&&DWORD&&&&BytesRECV; // 保存套接字接收的字节数}SOCKET_INFORMATION, * LPSOCKET_INFORMATION;&& &/* winsock2.h中定义的结构体;typedef struct _WSABUF {&&&&u_long&&&&&&&&&& // the length of the buffer &&&&char FAR *&&&&&& // the pointer to the buffer } WSABUF, FAR * LPWSABUF;*/&//记录正在使用的套接字总数量;DWORD TotalSockets = 0;//保存Socket信息对象的数组(Socket集合),FD_SETSIZE表示SELECT模型中允许的最大Socket数量(64);LPSOCKET_INFORMATION&&SocketArray[FD_SETSIZE];&SOCKET&&&&&& ListenSocket; // 监听套接字SOCKET&&&&&& AcceptSocket; // 与客户端进行通信的套接字SOCKADDR_IN&&InternetAddr; // 服务器的地址WSADATA&&&&&&wsaData;
// 用于初始化套接字环境INT&&&&&&&&&&Ret;
// WinSock API的返回值FD_SET&&&&&& WriteSet;
// 获取可写性的套接字集合FD_SET&&&&&& ReadSet;
// 获取可读性的套接字集合DWORD&&&&&&&&Total = 0;
// 处于就绪状态的套接字数量DWORD&&&&&&&&SendBytes;
// 发送的字节数DWORD&&&&&&&&RecvBytes;
// 接收的字节数&BOOL CreateSocketInformation(SOCKET s)&& {&& &&&&LPSOCKET_INFORMATION&& SI; // 用于保存套接字的信息&&&&&& // 为SI分配内存空间&&&&if ((SI = (LPSOCKET_INFORMATION) GlobalAlloc(GPTR, sizeof(SOCKET_INFORMATION))) == NULL)&& &&&&{&& &&&&&&&&printf("GlobalAlloc() failed with error %d\n", GetLastError());&& &&&&&&&&return&& FALSE;&& &&&&}&& &&&&// 初始化SI的值&& &&&&SI-&Socket = s;&& //与客户端进行通信的套接字;&&&&SI-&BytesSEND = 0;&& //发送的字节数初始为0;&&&&SI-&BytesRECV = 0;&& //接收的字节数也为0;&&&&// 在SocketArray数组中增加一个新元素,用于保存SI对象&&&&SocketArray[TotalSockets] = SI;&&&&&& &&&&TotalSockets++;
// 增加套接字数量&&&&&&&&return(TRUE);&& }&void FreeSocketInformation(DWORD Index)&& {&& &&&&// 获取指定索引对应的LPSOCKET_INFORMATION对象&&&&&&&&LPSOCKET_INFORMATION SI = SocketArray[Index]; &&&&closesocket(SI-&Socket);&& // 关闭套接字&&&&//printf("Closing socket number %d\n", SI-&Socket);&& &&&&// 释放指定LPSOCKET_INFORMATION对象资源&&&&GlobalFree(SI);&& &&&&// 将数组中index索引后面的元素前移&&&&for (DWORD i = Index; i & TotalSockets; i++)&& &&&&{&& &&&&&&&&SocketArray[i] = SocketArray[i+1];&& &&&&}&& &&&&TotalSockets--;
// 套接字总数减}&int _tmain(int argc, _TCHAR* argv[]){&&
//初始化WinSock环境;&&&&if((Ret = WSAStartup(0x0202,&wsaData)) != 0)&&&&{&&&&&&&&printf("WSAStartup() failed with error %d\n", Ret);
WSACleanup();
return -1; }
//创建用于监听的Socket,WSASocket是Windows专用,支持异步操作; if((ListenSocket = WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED)) == INVALID_SOCKET)&&&&{
printf("WSAStartup() failed with error %d\n", WSAGetLastError());
return -1;&&&&}
//设置监听地址和端口号; InternetAddr.sin_family = AF_INET; //Address family&&&&InternetAddr.sin_addr.s_addr = htonl(INADDR_ANY); //Wild card IP address&&&&InternetAddr.sin_port = htons(PORT); //port to use
//绑定监听Socket到本地地址和端口; if(bind( ListenSocket, (PSOCKADDR)&InternetAddr, sizeof(InternetAddr) ) == SOCKET_ERROR)&&&&{
printf("bind() failed with error %d\n", WSAGetLastError());&&&&&&&&return -1;&&&&}
//开始监听; if(listen(ListenSocket, 5))&&//同时设置等待队列长度;&&&&{
printf("listen() failed with error %d\n", WSAGetLastError());&&&&&&&&return -1;&&&&}
//设置为非阻塞模式; ULONG NonBlock = 1;
if(ioctlsocket(ListenSocket, FIONBIO, &NonBlock) == SOCKET_ERROR) {
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());&&&&&&&&return -1; }
//为ListenSocket Socket创建对应的SOCKET_INFORMATION //这样就可以把ListenSocket添加到SocketArray数组中; CreateSocketInformation(ListenSocket);
while(TRUE) {
//准备用于网络I/O通知的读/写Socket集合
FD_ZERO(&ReadSet);&&//将集合初始化为空集合;
FD_ZERO(&WriteSet);
//向ReadSet集合添加监听Socket ListenSocket
FD_SET(ListenSocket, &ReadSet);
//将SocketArray数组中的所有Socket添加到WriteSet和ReadSet集合中
//SocketArray数组中保存着监听Socket和所有与客户端进行通信的Socket
//这样就可以使用Select()判断哪个Socket有接入数据或者读取/写入数据
for(DWORD i=0; i&TotalSockets; i++)
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
FD_SET(SocketInfo-&Socket, &WriteSet);
FD_SET(SocketInfo-&Socket, &ReadSet);
//判断读/写Socket集合中就绪的Socket
if((Total = select(0,&ReadSet, &WriteSet, NULL, NULL)) == SOCKET_ERROR)
printf("select() returned with error %d\n", WSAGetLastError());
return -1;
//依次处理所有的Socket。本服务器是一个回应服务器,即将从客户端收到的字符串再发回到客户端
for(DWORD j=0; j&TotalSockets; j++)
//SocketInfo为当前要处理的Socket信息
LPSOCKET_INFORMATION SocketInfo = SocketArray[i];
//判断当前Socket的可读性,即是否有接入的连接请求或者可以接收数据
if(FD_ISSET(SocketInfo-&Socket, &ReadSet))
//对于监听Socket来说,可读表示有新的连接请求
if(SocketInfo-&Socket == ListenSocket)
Total--; //就绪的Socket减1
//接受连接请求,得到与客户端进行通信的Socket AcceptSocket
if((AcceptSocket = accept(ListenSocket, NULL,NULL)) != INVALID_SOCKET)
//设置Socket AcceptSocket为非阻塞模式;
//这样服务器在调用WSASend()函数发送数据时就不会被阻塞
NonBlock = 1;
if(ioctlsocket(AcceptSocket, FIONBIO, &NonBlock) == SOCKET_ERROR)
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return -1;
//创建套接字信息,初始化LPSOCKET_INFORMATION结构体数据,
//将AcceptSocket(也就是新的Socket)添加到SocketArray数组中
if(CreateSocketInformation(AcceptSocket) == FALSE)
return -1;
else&&//出错;
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("accept() failed with error %d\n", WSAGetLastError());
return -1;
else&&//对于其它Socket来说,表示可接收数据;
//如果当前Socket在ReadSet集合中,则表明该Socket上有可以读取的数据
if(FD_ISSET(SocketInfo-&Socket, &ReadSet))
Total--;&&//减少一个处于就绪状态的套接字
memset(SocketInfo-&Buffer, ' ', DATA_BUFSIZE);&&//初始化缓冲区
SocketInfo-&DataBuf.buf = SocketInfo-&Buffer; //初始化缓冲区位置
SocketInfo-&DataBuf.len = DATA_BUFSIZE;&&//初始化缓冲区长度
//接收数据
DWORD Flags = 0;
if(WSARecv(SocketInfo-&Socket, &(SocketInfo-&DataBuf), 1, &RecvBytes, &Flags, NULL, NULL) == SOCKET_ERROR)
//错误编码等于WSAEWOULDBLOCK表示暂时没有数据,否则表示出现异常
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("WSARecv() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i); //释放Socket信息;
else&&//接收数据未出错
SocketInfo-&BytesRECV = RecvBytes;&&//记录接收数据的字节数
if(RecvBytes == 0)&& //如果收到0个字节,则表示对方关闭连接
FreeSocketInformation(i); //释放Socket信息;
else&& //如果成功接收数据则打印收到的数据;
printf(SocketInfo-&DataBuf.buf);
printf("\n");
else&&//不是落在ReadSet集合内
//如果当前Socket在WriteSet集合中,则表明该Socket的内部数据缓冲区有数据可以发送
if(FD_ISSET(SocketInfo-&Socket, &WriteSet))
Total--; //就绪的Socket减1
//初始化缓冲区位置
SocketInfo-&DataBuf.buf = SocketInfo-&Buffer + SocketInfo-&BytesSEND;//因为是回显程序?
//初始化缓冲区长度
SocketInfo-&DataBuf.len = SocketInfo-&BytesRECV - SocketInfo-&BytesSEND;
if(SocketInfo-&DataBuf.len & 0)
if(WSASend(SocketInfo-&Socket, &(SocketInfo-&DataBuf), 1, &SendBytes, 0, NULL, NULL) == SOCKET_ERROR)
//错误编码等于WSAEWOULDBLOCK表示暂时没有数据,否则表示出现异常
if(WSAGetLastError() != WSAEWOULDBLOCK)
printf("WSASend() failed with error %d\n", WSAGetLastError());
FreeSocketInformation(i); //释放Socket信息;
else&&//发送数据未出错;
SocketInfo-&BytesSEND += SendBytes;&&//记录发送数据的字节数
//如果从客户端接收到的数据都已经发回到客户端
//则将发送和接收的字节数量设置为0
if(SocketInfo-&BytesSEND == SocketInfo-&BytesRECV)
SocketInfo-&BytesSEND = 0;
SocketInfo-&BytesRECV = 0;
}//for语句结束 }//while}&
本文评分:
《Windows网络编程》_罗莉琴版_8.3节_基于Select模型的Socket编程_代码
0 votes, 0.00 avg. rating (0% score)
上一篇: &nbsp&nbsp&nbsp
开发的WP标签云插件要求
9 或者更高。
- 6,338 views - 3,960 views - 3,570 views - 3,410 views - 3,151 views - 3,114 views - 2,757 views - 2,346 views
2016年一月 &(1)
2015年十一月 &(2)
2015年十月 &(1)
2015年八月 &(1)
2015年六月 &(1)
2015年四月 &(2)
2015年三月 &(2)
2015年二月 &(1)
2015年一月 &(2)
2014年十二月 &(2)
2014年十一月 &(3)
2014年十月 &(3)
2014年九月 &(3)
2014年八月 &(3)
2014年七月 &(2)
2014年六月 &(4)
2014年五月 &(10)
2014年四月 &(12)
2014年三月 &(1)
Friend Link
微信订阅号Python基于Select模型实现Popen输出 - 推酷
Python基于Select模型实现Popen输出
参考了pssh的代码,实现了下面一个小的框架,用于实现并发处理涉及到的IO返回的标准输出和错误输出。IOMap里面保存了所有可读句柄对应的call函数。一旦select返回就read返回然后相应的处理,直接看代码吧。
#!/usr/bin/env python
#coding=utf-8
import signal
import select, sys, subprocess
BUFFER_SIZE = 1024
class IOMap(object):
&&&A manager for file descriptors and their associated handlers.
The poll method dispatches events to the appropriate handlers.
def __init__(self):
self.readmap = {}
self.writemap = {}
wakeup_readfd, wakeup_writefd = os.pipe()
self.register_read(wakeup_readfd, self.wakeup_handler)
# TODO: remove test when we stop supporting Python &2.5
if hasattr(signal, 'set_wakeup_fd'):
signal.set_wakeup_fd(wakeup_writefd)
self.wakeup_writefd = None
self.wakeup_writefd = wakeup_writefd
def register_read(self, fd, handler):
&&&Registers an IO handler for a file descriptor for reading.&&&
self.readmap[fd] = handler
def register_write(self, fd, handler):
&&&Registers an IO handler for a file descriptor for writing.&&&
self.writemap[fd] = handler
def unregister(self, fd):
&&&Unregisters the given file descriptor.&&&
if fd in self.readmap:
del self.readmap[fd]
if fd in self.writemap:
del self.writemap[fd]
def poll(self, timeout=None):
&&&Performs a poll and dispatches the resulting events.&&&
if not self.readmap and not self.writemap:
rlist = list(self.readmap)
wlist = list(self.writemap)
rlist, wlist, _ = select.select(rlist, wlist, [], timeout)
except select.error:
_, e, _ = sys.exc_info()
errno = e.args[0]
if errno == EINTR:
for fd in rlist:
handler = self.readmap[fd]
handler(fd, self)
for fd in wlist:
handler = self.writemap[fd]
handler(fd, self)
def wakeup_handler(self, fd, iomap):
&&&Handles read events on the signal wakeup pipe.
This ensures that SIGCHLD signals aren't lost.
os.read(fd, READ_SIZE)
except (OSError, IOError):
_, e, _ = sys.exc_info()
errno, message = e.args
if errno != EINTR:
sys.stderr.write('Fatal error reading from wakeup pipe: %s\n'% message)
raise FatalError
class Task(object):
&&&docstring for Task&&&
def __init__(self,):
self.stdout = &&
self.stderr = &&
def run(self, io_map):
&&&run command in Popen
print stdout and stderr
test_pipe = subprocess.Popen('i=0;while [ $i -lt 1000 ];do echo &hello world $i&;let i++;done', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
self.stdout = test_pipe.stdout
self.stderr = test_pipe.stderr
io_map.register_read(self.stdout.fileno(), self.handle_stdout)
io_map.register_read(self.stderr.fileno(), self.handle_stderr)
while True:
io_map.poll()
except KeyboardInterrupt:
# This exception handler doesn't print out any fancy status
# information--it just stops.
self.interrupted()
def handle_stdout(self, fd, iomap):
&&& handle Popen return stdout
buf = os.read(fd, BUFFER_SIZE)
print &stdout : & + buf,
self.close_stdout(iomap)
except (OSError, IOError):
_, e, _ = sys.exc_info()
if e.errno != EINTR:
self.close_stdout(iomap)
def handle_stderr(self, fd, iomap):
&&& handle Popen return stderr
buf = os.read(fd, BUFFER_SIZE)
print &stderr : & + buf,
self.close_stderr(iomap)
except (OSError, IOError):
_, e, _ = sys.exc_info()
if e.errno != EINTR:
self.close_stderr(iomap)
def close_stderr(self, iomap):
if self.stderr:
iomap.unregister(self.stderr.fileno())
def close_stdout(self, iomap):
if self.stdout:
iomap.unregister(self.stdout.fileno())
def interrupted(self):
&&&Cleans up after a keyboard interrupt.&&&
sys.exit(255)
if __name__ == '__main__':
iomap = IOMap()
task = Task()
task.run(iomap)
已发表评论数()
请填写推刊名
描述不能大于100个字符!
权限设置: 公开
仅自己可见
正文不准确
标题不准确
排版有问题
主题不准确
没有分页内容
图片无法显示
视频无法显示
与原文不一致}

我要回帖

更多关于 中画幅和全画幅换算 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信