C++服务器重叠I/O+事件通告模型

#include
#include
#include 
#include
using namespace std;
#pragma comment(lib,"Ws2_32.lib")
#pragma comment (lib, "mswsock.lib")
const int nPort=10000;
const int buf_len=1024;
//对于同一个客户连接套接字,任意时刻只能有一个为完成的异步I/O操作,要么是
//WSASend(IoWrite),要么是WSARecv(IoRead)
typedef enum _IO_OPERATION{
	IoRead,
	IoWrite
}IO_OPERATION;
//每一个连接都有一个Connection对象Connection对象包含一个WSAOVERLAPPED结构
//同时由于一个Connection只有一个WSAOVERLAPPED结构,并且由于一个I/O异步请求
//必须有一个唯一的WSAOVERLAPPED结构,因此任意时刻对于一个连接只能有一个未完成的
//异步I/O操作
struct Connection{
	SOCKET hSocket;
	char Buffer[buf_len];
	int nBytes;
	//调用WSASend或者WSARecv是需要一个WSABUF结构的指针
	WSABUF wsaBuffer;
	WSAOVERLAPPED overlap;
	IO_OPERATION op;
	Connection(SOCKET socket):hSocket(socket),nBytes(0)
	{
		wsaBuffer.buf=Buffer;
		wsaBuffer.len=buf_len;
		ZeroMemory(&overlap,sizeof(WSAOVERLAPPED));
		//由于程序使用事件完成通知,因此需要为WSAOVERLAPPED结构创建一个时间内核对象
		overlap.hEvent=WSACreateEvent();
	}
};
typedef vector ConnectionList;
// 重置conns,把其中无效的套接字移除
void ResetConns(ConnectionList& conns){
    ConnectionList::iterator it = conns.begin();
    while(it != conns.end()){
        if((*it)->hSocket == INVALID_SOCKET){
            delete (*it);
            it = conns.erase(it);
        }
        else
            ++it;
    }
}
// 为WSAWaitForMultipleEvents填充好需要等待的事件内核对象数组
int FillEventArray(HANDLE hEvents[], HANDLE hListenEvent, 
                   ConnectionList& conns){
    // 监听套接字的事件对象放在最前面,之后依次填入当前所有客户连接套接字
	// 的事件对象
    hEvents[0] = hListenEvent;
    int nEvents = 1;
    ConnectionList::iterator it = conns.begin();
    while(it != conns.end()){
        // 使用WSAOVERLAPPED结构中的hEvent填充数组
        hEvents[nEvents] = (*it)->overlap.hEvent;
        ++nEvents;
        ++it;
    }
    return (int)(conns.size() + 1);
}
// 异步AcceptEx请求已完成,获取结果
bool HandleAccept(SOCKET hListenSocket, SOCKET hAcceptSocket, LPOVERLAPPED
                  lpOverlapListen, ConnectionList& conns) {
    DWORD flags = 0;
    DWORD bytes = 0;
    // 获取异步I/O的结果
    if(!WSAGetOverlappedResult(hListenSocket, lpOverlapListen, &bytes, 
                               FALSE, &flags))
    {
        cout<<"WSAGetOverlappedResult error "<< WSAGetLastError() << endl;
        return false;
    }
	// 超出单线程所能处理的连接数
    if(conns.size() + 1 >= WSA_MAXIMUM_WAIT_EVENTS){
        cout << "exceed connection limit" << endl;
        // 关闭已接受的客户连接,即拒绝服务
        closesocket(hAcceptSocket);
        return true;
    }
    // 为新接受的客户连接创建一个Connection对象
    conns.push_back(new Connection(hAcceptSocket));
    Connection* pConn = conns.back();
	// 第一次的异步I/O请求是IoRead,因为对于回显服务器来说,必须先接收到数据后
    // 才能回显数据
    pConn->op = IoRead;
    flags = 0;
    // 对这个新的客户连接发出第一个异步I/O请求
    int nRet = WSARecv(pConn->hSocket, &(pConn->wsaBuffer), 1, NULL, 
                       &flags, &pConn->overlap, NULL);
    int lastErr = WSAGetLastError();
    // 如果WSARecv失败并且错误代码不是ERROR_IO_PENDING
    if(nRet == SOCKET_ERROR && WSA_IO_PENDING != lastErr){
        cout<<"WSARecv error "<< lastErr << endl;
        return false;
    }
    return true;
}

// 异步的WSASend或者WSARecv已完成,获取结果
bool HandleSendRecv(Connection* pConn){
    DWORD flags = 0;
    DWORD bytes = 0;
    // 获取异步I/O的结果
    if(!WSAGetOverlappedResult(pConn->hSocket, &pConn->overlap, &bytes, 
                               FALSE, &flags)) {
        int lastErr = WSAGetLastError();
        cout<<"WSAGetOverlappedResult error "<< lastErr << endl;
        // 连接被对方意外关闭
        if(lastErr == WSAECONNRESET)
            cout<<"Connection was reset."<op == IoRead){
        // 更新可用数据的大小
        pConn->nBytes += bytes;
        // 为即将调用的WSASend准备好缓冲区参数
        pConn->wsaBuffer.len = pConn->nBytes;
        pConn->wsaBuffer.buf = pConn->Buffer;
        flags = 0;
        // 由于WSARecv已成功接收了数据,现在可以发出异步WSASend请求来回显数据
        pConn->op = IoWrite;
        int nRet = WSASend(pConn->hSocket, &(pConn->wsaBuffer), 1, NULL, 
                           flags, &pConn->overlap, NULL);
        int lastErr = WSAGetLastError();
        if(nRet == SOCKET_ERROR && WSA_IO_PENDING != lastErr) {
            cout<<"WSASend error "<< lastErr << endl;
            return false;
        }
    }
    // 如果当前已完成的异步I/O是WSASend
    else if(pConn->op == IoWrite){
        // 更新可用数据的大小
        pConn->nBytes -= bytes;
        // 计算缓冲区空闲空间的大小
        pConn->wsaBuffer.len = nBuffSize - pConn->nBytes;
        // 如果缓冲区还有剩余数据没有发送出去,则需要把它们移到缓冲区的头部
        if(pConn->nBytes > 0) {
            memmove(pConn->Buffer, pConn->Buffer + bytes, pConn->nBytes);
        }
        // 计算缓冲区空闲空间的偏移
        pConn->wsaBuffer.buf = pConn->Buffer + pConn->nBytes;
        flags = 0;
        pConn->op = IoRead;
        // 发出异步WSARecv请求
        int nRet = WSARecv(pConn->hSocket, &(pConn->wsaBuffer), 1, NULL, 
                           &flags, &pConn->overlap, NULL);
        int lastErr = WSAGetLastError();
        if(nRet == SOCKET_ERROR && WSA_IO_PENDING != lastErr) {
            cout<<"WSARecv error "<< lastErr << endl;
            return false;
        }
    }
    return true;
}
//创建一个WSA_FLAG_OVERLAPPED套接字
SOCKET CreateOverlappedSocket()
{
	SOCKET hSocket=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
	if(hSocket==INVALID_SOCKET)
	{
		cout<<"WSASocket 错误"<hEvent=hListenEvent;
	//发出异步AcceptEx请求
	if(!AcceptEx(hListenSocket,hAcceptSocket,bAcceptBuffer,0,sizeof(SOCKADDR_IN)+16,sizeof(SOCKADDR_IN)+16,&dwAcceptBytes,lpOverlapListen))
	{
		//如果AcceptEx失败并且错误代码不是ERROR_IO_PENDING
		int lastErr=WSAGetLastError();
		if(lastErr!=ERROR_IO_PENDING)
		{
			cout<<"AcceptEx 错误"<hSocket);
                    pConn->hSocket = INVALID_SOCKET;
                    WSACloseEvent(pConn->overlap.hEvent);
                }
            }
        }
    }
    // 释放资源
cleanup:
    ConnectionList::iterator it = conns.begin();
    for(;it != conns.end();++it){
        closesocket((*it)->hSocket);
        WSACloseEvent((*it)->overlap.hEvent);
        delete (*it);
    }
    if(hListenSocket != INVALID_SOCKET)
        closesocket(hListenSocket);
    WSACloseEvent(hListenEvent);
}
int main(int argc, char* argv[]){
    WSAData wsaData;
	int nCode;
    if ((nCode = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0) {
		cout << "WSAStartup error " << nCode << endl;
        return -1;
    }
    DoWork();
    WSACleanup();
    return 0;
} 

你可能感兴趣的:(C++,网络编程,服务器)