代码组织上不是很合理,很多细节没有注意,只是作为一个演示记下反应式I/O的一种使用模式,通过telnet作为客户端演示之。
/**
* 基于反应式I/O的echo服务器。监听端口5432,CTRL+C优雅结束服务。
*
*
* 完成:
* 1)通过单线程为多个客户提供服务。
* 2)通过信号机制优雅的结束服务。
* 3)减少fd_set的构建。
* 4)避免资源泄露。
*
* 未完成:
* 1)链接数受系统限制。
* 2)错误处理不一致。
*/
//#include <vld.h>
#include < assert.h >
#include < signal.h >
#include < iostream >
#include < list >
using namespace std;
#ifdef WIN32
/// 去掉下面注释,更改其默认值
#define FD_SETSIZE 1024
# include < WinSock2.h >
# pragma comment(lib, " ws2_32.lib " )
# include < mswsock.h >
# pragma comment(lib, " Mswsock.lib " )
# define PRINT_SOCKET_ERROR(FUNC)
do
{
cout << "<" << #FUNC << "> Call Error!" << " "
<< "Error Number : " << WSAGetLastError() << endl;
} while ( 0 )
#endif // WIN32
#define PORT 5432
// = 类型定义
struct Connection
{
enum {BufSize = 1024 * 4};
Connection(SOCKET fd)
: mFd(fd)
, mReadPos(0)
, mWritePos(0)
{
}
SOCKET mFd;
int mReadPos;
int mWritePos;
char mBuffer[BufSize];
} ;
struct FdSets
{
fd_set mRead;
fd_set mWrite;
fd_set mException;
} ;
typedef list < Connection *> ConnectionRepository;
typedef ConnectionRepository::iterator ConnectionRepositoryIterator;
// = 全局数据
ConnectionRepository gConnRep;
///
FdSets gFdSets;
///
SOCKET gReadPipe;
SOCKET gWritePipe;
BOOL gIsShutDown = FALSE;
// =
int createListenFd(SOCKADDR_IN & addr, SOCKET & fd)
{
int nRet = 0;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
PRINT_SOCKET_ERROR(socket);
return -1;
}
if ((nRet = bind(fd, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN))) != 0) {
PRINT_SOCKET_ERROR(bind);
return nRet;
}
if ((nRet = listen(fd, 5)) != 0) {
PRINT_SOCKET_ERROR(listen);
return nRet;
}
else {
cout << "Listening at " << inet_ntoa(addr.sin_addr)
<< ":" << ntohs(addr.sin_port) << endl;
}
return nRet;
}
int createPipe( void )
{
int nRet = 0;
SOCKADDR_IN addr;
int addr_size = sizeof(SOCKADDR_IN);
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
SOCKET fd;
if(createListenFd(addr, fd) != 0)
goto error_return;
if (getsockname(fd, (PSOCKADDR)&addr, &addr_size) != 0)
goto error_return;
if ((gWritePipe = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))
== INVALID_SOCKET)
goto error_return;
if (connect(gWritePipe, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN)) != 0)
goto error_return;
if ((gReadPipe = accept(fd, 0, 0)) == INVALID_SOCKET)
goto error_return;
FD_SET(gReadPipe, &gFdSets.mRead);
closesocket(fd);
return 0;
error_return:
return -1;
}
void performRead(fd_set & set )
{
if (set.fd_count == 0)
return;
ConnectionRepositoryIterator it = gConnRep.begin();
ConnectionRepositoryIterator end = gConnRep.end();
int read_bytes = 0;
for ( ;it != end; )//++it)
{
Connection *conn = *it;
if (FD_ISSET(conn->mFd, &set))
{
read_bytes = recv(conn->mFd, conn->mBuffer + conn->mReadPos,
Connection::BufSize, 0);
if (read_bytes > 0)
{
/// !!!NOTE
conn->mReadPos += read_bytes;
FD_SET(conn->mFd, &gFdSets.mWrite);
}
else
{
if (read_bytes == 0)
cout << conn->mFd << " Closed!" << endl;
else
cout << conn->mFd << " recv Error!Error code:" << WSAGetLastError() << endl;
it = gConnRep.erase(it);
FD_CLR(conn->mFd, &gFdSets.mRead);
closesocket(conn->mFd);
delete conn;
continue;
}
}
++it;
}
}
void performWrite(fd_set & set )
{
if (set.fd_count == 0)
return;
ConnectionRepositoryIterator it = gConnRep.begin();
ConnectionRepositoryIterator end = gConnRep.end();
int send_bytes = 0;
for ( ;it != end; )
{
Connection *conn = *it;
if (FD_ISSET(conn->mFd, &set))
{
int len = conn->mReadPos - conn->mWritePos;
assert(len > 0);
send_bytes = send(conn->mFd, conn->mBuffer + conn->mWritePos, len, 0);
if (send_bytes == len)
{
conn->mWritePos = conn->mReadPos = 0;
FD_CLR(conn->mFd, &gFdSets.mWrite);
}
else if (send_bytes > 0)
{
cout << "Not send all data out!!!" << endl;
conn->mWritePos += send_bytes;
}
else
{
/// !!!NOTE
cout << "FD:" << conn->mFd << " send data error!" << endl;
it = gConnRep.erase(it);
FD_CLR(conn->mFd, &gFdSets.mRead);
FD_CLR(conn->mFd, &gFdSets.mWrite);
closesocket(conn->mFd);
delete conn;
continue;
}
}
++it;
}
}
void perfromException(fd_set & set )
{
}
void signal_handler( int signum)
{
char buffer[] = "c";
int c = send(gWritePipe, buffer, 2, 0);
}
class Initializer
{
public:
Initializer() {
WSAData wsaData;
mRet = WSAStartup(0x0202, &wsaData);
if (mRet == 0)
mRet = createPipe();
signal(SIGINT, signal_handler);
}
~Initializer() {
closesocket(gReadPipe);
closesocket(gWritePipe);
mRet = WSACleanup();
}
int Ret(void) const {
return mRet;
}
private:
int mRet;
} ;
int main( int argc, char * argv[])
{
// = 初始化
Initializer iws2;
int nRet = iws2.Ret();
if (nRet != 0)
return -1;
// = 设置监听socket句柄
SOCKET fdListen;
SOCKADDR_IN hostAddr;
{
hostAddr.sin_family = AF_INET;
hostAddr.sin_port = htons(PORT);
hostAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
createListenFd(hostAddr, fdListen);
FD_SET(fdListen, &gFdSets.mRead);
// =
SOCKET fdAccepted;
int n;
while (1)
{
FdSets dispatchSets;
memcpy(&dispatchSets, &gFdSets, sizeof(FdSets));
if ((n = select(0, &dispatchSets.mRead,
&dispatchSets.mWrite, &dispatchSets.mException, NULL)) == SOCKET_ERROR)
{
PRINT_SOCKET_ERROR(select);
break;
}
if (FD_ISSET(gReadPipe, &dispatchSets.mRead))
{
char buf[32];
recv(gReadPipe, buf, 32, 0);
ConnectionRepositoryIterator end = gConnRep.end();
for (ConnectionRepositoryIterator it = gConnRep.begin();
it != end; ++it)
{
Connection* conn = *it;
if (shutdown(conn->mFd, SD_SEND)!= 0)
cout << "fd[" << conn->mFd << "] shutdown error!!!" << endl;
}
gIsShutDown = TRUE;
}
if (FD_ISSET(fdListen, &dispatchSets.mRead))
{
SOCKADDR_IN remoteAddr;
int remote_addr_size = sizeof(SOCKADDR_IN);
if ((fdAccepted = accept(fdListen,
(PSOCKADDR)&remoteAddr, &remote_addr_size)) == INVALID_SOCKET)
{
PRINT_SOCKET_ERROR(accept);
break;
}
FD_SET(fdAccepted, &gFdSets.mRead);
Connection* conn = new Connection(fdAccepted);
gConnRep.push_back(conn);
//continue;
}
performWrite(dispatchSets.mWrite);
performRead(dispatchSets.mRead);
perfromException(dispatchSets.mException);
if (gIsShutDown && gConnRep.empty())
break;
}
closesocket(fdListen);
return 0;
} ;
* 基于反应式I/O的echo服务器。监听端口5432,CTRL+C优雅结束服务。
*
*
* 完成:
* 1)通过单线程为多个客户提供服务。
* 2)通过信号机制优雅的结束服务。
* 3)减少fd_set的构建。
* 4)避免资源泄露。
*
* 未完成:
* 1)链接数受系统限制。
* 2)错误处理不一致。
*/
//#include <vld.h>
#include < assert.h >
#include < signal.h >
#include < iostream >
#include < list >
using namespace std;
#ifdef WIN32
/// 去掉下面注释,更改其默认值
#define FD_SETSIZE 1024
# include < WinSock2.h >
# pragma comment(lib, " ws2_32.lib " )
# include < mswsock.h >
# pragma comment(lib, " Mswsock.lib " )
# define PRINT_SOCKET_ERROR(FUNC)
do
{
cout << "<" << #FUNC << "> Call Error!" << " "
<< "Error Number : " << WSAGetLastError() << endl;
} while ( 0 )
#endif // WIN32
#define PORT 5432
// = 类型定义
struct Connection
{
enum {BufSize = 1024 * 4};
Connection(SOCKET fd)
: mFd(fd)
, mReadPos(0)
, mWritePos(0)
{
}
SOCKET mFd;
int mReadPos;
int mWritePos;
char mBuffer[BufSize];
} ;
struct FdSets
{
fd_set mRead;
fd_set mWrite;
fd_set mException;
} ;
typedef list < Connection *> ConnectionRepository;
typedef ConnectionRepository::iterator ConnectionRepositoryIterator;
// = 全局数据
ConnectionRepository gConnRep;
///
FdSets gFdSets;
///
SOCKET gReadPipe;
SOCKET gWritePipe;
BOOL gIsShutDown = FALSE;
// =
int createListenFd(SOCKADDR_IN & addr, SOCKET & fd)
{
int nRet = 0;
if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
PRINT_SOCKET_ERROR(socket);
return -1;
}
if ((nRet = bind(fd, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN))) != 0) {
PRINT_SOCKET_ERROR(bind);
return nRet;
}
if ((nRet = listen(fd, 5)) != 0) {
PRINT_SOCKET_ERROR(listen);
return nRet;
}
else {
cout << "Listening at " << inet_ntoa(addr.sin_addr)
<< ":" << ntohs(addr.sin_port) << endl;
}
return nRet;
}
int createPipe( void )
{
int nRet = 0;
SOCKADDR_IN addr;
int addr_size = sizeof(SOCKADDR_IN);
addr.sin_family = AF_INET;
addr.sin_port = htons(0);
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
SOCKET fd;
if(createListenFd(addr, fd) != 0)
goto error_return;
if (getsockname(fd, (PSOCKADDR)&addr, &addr_size) != 0)
goto error_return;
if ((gWritePipe = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))
== INVALID_SOCKET)
goto error_return;
if (connect(gWritePipe, (PSOCKADDR)&addr, sizeof(SOCKADDR_IN)) != 0)
goto error_return;
if ((gReadPipe = accept(fd, 0, 0)) == INVALID_SOCKET)
goto error_return;
FD_SET(gReadPipe, &gFdSets.mRead);
closesocket(fd);
return 0;
error_return:
return -1;
}
void performRead(fd_set & set )
{
if (set.fd_count == 0)
return;
ConnectionRepositoryIterator it = gConnRep.begin();
ConnectionRepositoryIterator end = gConnRep.end();
int read_bytes = 0;
for ( ;it != end; )//++it)
{
Connection *conn = *it;
if (FD_ISSET(conn->mFd, &set))
{
read_bytes = recv(conn->mFd, conn->mBuffer + conn->mReadPos,
Connection::BufSize, 0);
if (read_bytes > 0)
{
/// !!!NOTE
conn->mReadPos += read_bytes;
FD_SET(conn->mFd, &gFdSets.mWrite);
}
else
{
if (read_bytes == 0)
cout << conn->mFd << " Closed!" << endl;
else
cout << conn->mFd << " recv Error!Error code:" << WSAGetLastError() << endl;
it = gConnRep.erase(it);
FD_CLR(conn->mFd, &gFdSets.mRead);
closesocket(conn->mFd);
delete conn;
continue;
}
}
++it;
}
}
void performWrite(fd_set & set )
{
if (set.fd_count == 0)
return;
ConnectionRepositoryIterator it = gConnRep.begin();
ConnectionRepositoryIterator end = gConnRep.end();
int send_bytes = 0;
for ( ;it != end; )
{
Connection *conn = *it;
if (FD_ISSET(conn->mFd, &set))
{
int len = conn->mReadPos - conn->mWritePos;
assert(len > 0);
send_bytes = send(conn->mFd, conn->mBuffer + conn->mWritePos, len, 0);
if (send_bytes == len)
{
conn->mWritePos = conn->mReadPos = 0;
FD_CLR(conn->mFd, &gFdSets.mWrite);
}
else if (send_bytes > 0)
{
cout << "Not send all data out!!!" << endl;
conn->mWritePos += send_bytes;
}
else
{
/// !!!NOTE
cout << "FD:" << conn->mFd << " send data error!" << endl;
it = gConnRep.erase(it);
FD_CLR(conn->mFd, &gFdSets.mRead);
FD_CLR(conn->mFd, &gFdSets.mWrite);
closesocket(conn->mFd);
delete conn;
continue;
}
}
++it;
}
}
void perfromException(fd_set & set )
{
}
void signal_handler( int signum)
{
char buffer[] = "c";
int c = send(gWritePipe, buffer, 2, 0);
}
class Initializer
{
public:
Initializer() {
WSAData wsaData;
mRet = WSAStartup(0x0202, &wsaData);
if (mRet == 0)
mRet = createPipe();
signal(SIGINT, signal_handler);
}
~Initializer() {
closesocket(gReadPipe);
closesocket(gWritePipe);
mRet = WSACleanup();
}
int Ret(void) const {
return mRet;
}
private:
int mRet;
} ;
int main( int argc, char * argv[])
{
// = 初始化
Initializer iws2;
int nRet = iws2.Ret();
if (nRet != 0)
return -1;
// = 设置监听socket句柄
SOCKET fdListen;
SOCKADDR_IN hostAddr;
{
hostAddr.sin_family = AF_INET;
hostAddr.sin_port = htons(PORT);
hostAddr.sin_addr.s_addr = htonl(INADDR_ANY);
}
createListenFd(hostAddr, fdListen);
FD_SET(fdListen, &gFdSets.mRead);
// =
SOCKET fdAccepted;
int n;
while (1)
{
FdSets dispatchSets;
memcpy(&dispatchSets, &gFdSets, sizeof(FdSets));
if ((n = select(0, &dispatchSets.mRead,
&dispatchSets.mWrite, &dispatchSets.mException, NULL)) == SOCKET_ERROR)
{
PRINT_SOCKET_ERROR(select);
break;
}
if (FD_ISSET(gReadPipe, &dispatchSets.mRead))
{
char buf[32];
recv(gReadPipe, buf, 32, 0);
ConnectionRepositoryIterator end = gConnRep.end();
for (ConnectionRepositoryIterator it = gConnRep.begin();
it != end; ++it)
{
Connection* conn = *it;
if (shutdown(conn->mFd, SD_SEND)!= 0)
cout << "fd[" << conn->mFd << "] shutdown error!!!" << endl;
}
gIsShutDown = TRUE;
}
if (FD_ISSET(fdListen, &dispatchSets.mRead))
{
SOCKADDR_IN remoteAddr;
int remote_addr_size = sizeof(SOCKADDR_IN);
if ((fdAccepted = accept(fdListen,
(PSOCKADDR)&remoteAddr, &remote_addr_size)) == INVALID_SOCKET)
{
PRINT_SOCKET_ERROR(accept);
break;
}
FD_SET(fdAccepted, &gFdSets.mRead);
Connection* conn = new Connection(fdAccepted);
gConnRep.push_back(conn);
//continue;
}
performWrite(dispatchSets.mWrite);
performRead(dispatchSets.mRead);
perfromException(dispatchSets.mException);
if (gIsShutDown && gConnRep.empty())
break;
}
closesocket(fdListen);
return 0;
} ;