Winsock2 - 如何在客户端使用 IOCP

2023-11-23

我最近开始学习 Windows 上的 IOCP 并阅读了以下文章:

http://www.codeproject.com/Tips/95363/Another-TCP-echo-server-using-IOCP

您可以从以下位置下载本文的示例:

http://dl.dropbox.com/u/281215/documentation/iocp-1.00.html

该示例包含两个简单的应用程序 –iocp_echo_服务器 and TcpEcho客户端.

我知道 IOCP 通常用在客户端/服务器模型的服务器端,但我想使用 IOCP 创建一个客户端。

到目前为止,我已经尝试修改上面的客户端示例,以便每当服务器向客户端发送响应时,它都会被自动接收,但是它不起作用。

我保留了 iocp_echo_server.c 原样。我的 TcpEchoClient.c 修改版本如下所示:

//TcpEchoClient.c - a minimalistic echo client
// -----------------------------------------------------------------------------

// C language includes
#include <stdio.h>
#include <winsock2.h>
#include "mswsock.h"  // for AcceptEx
#include <stdlib.h> // exit
#include <string.h>

// Windows includes
#include <windows.h>

#pragma warning(disable: 4996) // sprintf

// -----------------------------------------------------------------------------

// configuration
enum
{
    BUFLEN = 1000,
    SERVICE_PORT = 4000,
    SERVER_ADDRESS = INADDR_LOOPBACK
};

enum // socket operations
{
    OP_NONE,
    OP_ACCEPT,
    OP_READ,
    OP_WRITE
};

typedef struct _SocketState // socket state & control
{
    char operation;
    SOCKET socket;
    DWORD length;
    char buf[1024];
} SocketState;

// variables
static HANDLE cpl_port;

static SOCKET sock;
static SocketState sock_state;
static WSAOVERLAPPED sock_ovl;

static LPFN_ACCEPTEX pfAcceptEx;
static GUID GuidAcceptEx = WSAID_ACCEPTEX;

static int msgNumber;
static char msgBuf[BUFLEN];
static struct sockaddr_in sin;

// prototypes
static void createConnection(void);
static void createSocket(void);
static void init(void);
static void initWinsock(void);
static void prepareEndpoint(void);
static void recvBuffer(void);
static void run(void);
static void sendBuffer(void);

static SOCKET create_accepting_socket(void);
static void create_io_completion_port(void);
static BOOL get_completion_status(DWORD*, SocketState**,WSAOVERLAPPED**);

// -----------------------------------------------------------------------------

void main(void)
{
    init();
    run();
}

// -----------------------------------------------------------------------------

static void createConnection(void)
{
    printf("* connecting\n");
    if (WSAConnect(sock, (LPSOCKADDR)&sin, sizeof(sin), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
    {
        int err = WSAGetLastError();
        printf("* error %d in connect\n", err);
        exit(1);
    }
    printf("* connected\n");
}

// -----------------------------------------------------------------------------

static void createSocket(void)
{
    sock = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    if (sock == INVALID_SOCKET)
    {
        int err = WSAGetLastError();
        printf("* error %d creating socket\n", err);
        exit(1);
    }

    // for use by AcceptEx
    sock_state.socket = 0; // to be updated later
    sock_state.operation = OP_ACCEPT;

    if (CreateIoCompletionPort((HANDLE)sock, cpl_port, (ULONG_PTR)&sock_state, 0) != cpl_port)
    {
        int err = WSAGetLastError();
        printf("* error %d in listener\n", err);
        exit(1);
    }
}

// -----------------------------------------------------------------------------

static void init(void)
{
    initWinsock();
    create_io_completion_port();
    createSocket();
    prepareEndpoint();
    createConnection();
}

// -----------------------------------------------------------------------------

static void initWinsock(void)
{
    WSADATA wsaData;

    if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
    {
        int err = WSAGetLastError();
        printf("* error %d in WSAStartup\n", err);
        exit(1);
    }
}
// -----------------------------------------------------------------------------

static void prepareEndpoint(void)
{
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(SERVER_ADDRESS);
    sin.sin_port = htons(SERVICE_PORT);

    // bind_listening_socket()
    {
        //if (bind(sock, (SOCKADDR*)&sin, sizeof(sin)) == SOCKET_ERROR)
        //{
        //    printf("* error in bind!\n");
        //    exit(1);
        //}
    }

    // start_listening()
    {
        //if (listen(sock, 100) == SOCKET_ERROR)
        //{
        //    printf("* error in listen!\n");
        //    exit(1);
        //}
        //printf("* started listening for connection requests...\n");
    }

    // load_accept_ex()
    {
        //DWORD dwBytes;

        // black magic for me!!!
        // You do not need to call in your code WSAIoctl. You can directly use AcceptEx and adds Mswsock.lib.
        //WSAIoctl(sock, SIO_GET_EXTENSION_FUNCTION_POINTER, &GuidAcceptEx, sizeof(GuidAcceptEx), &pfAcceptEx, sizeof(pfAcceptEx), &dwBytes, NULL, NULL);
    }

    // start_accepting()
    {
        //SOCKET acceptor = create_accepting_socket();
        //DWORD expected = sizeof(struct sockaddr_in) + 16;

        //printf("* started accepting connections...\n");

        // uses listener's completion key and overlapped structure
        //sock_state.socket = acceptor;
        //memset(&sock_ovl, 0, sizeof(WSAOVERLAPPED));

        // starts asynchronous accept
        //if (!pfAcceptEx(sock, acceptor, sock_state.buf, 0 /* no recv */, expected, expected, NULL, &sock_ovl))
        //{
        //    int err = WSAGetLastError();
        //    if (err != ERROR_IO_PENDING)
        //    {
        //        printf("* error %d in AcceptEx\n", err);
        //        exit(1);
        //    }
        //}
    }
}

// -----------------------------------------------------------------------------

static void recvBuffer(void)
{
    char* buf = msgBuf;
    int pendingLen = BUFLEN;

    printf("* receiving reply\n");

    while (pendingLen > 0)
    {
        int partialLen = recv(sock, buf, pendingLen, 0);

        if (partialLen > 0)
        {
            pendingLen -= partialLen;
            buf += partialLen;
            continue;
        }

        // ------

        if (partialLen == 0)
        {
            printf("* connection closed by the server\n");
        }
        else // partialLen < 0
        {
            int err = WSAGetLastError();
            printf("* error %d in recv\n", err);
        }

        exit(1);
    }
}

// -----------------------------------------------------------------------------

static void run(void)
{
    DWORD length;
    BOOL resultOk;
    WSAOVERLAPPED* ovl_res;
    SocketState* socketState;

    for (;;)
    {
        sendBuffer();

        resultOk = get_completion_status(&length, &socketState, &ovl_res);

        recvBuffer();
    }
}

// -----------------------------------------------------------------------------

static void sendBuffer(void)
{
    char* buf = msgBuf;
    int pendingLen = BUFLEN;

    printf("* sending message\n");
    sprintf(msgBuf, "%05 *****", msgNumber++);

    while (pendingLen > 0)
    {
        int partialLen = send(sock, buf, pendingLen, 0);

        if (partialLen > 0)
        {
            pendingLen -= partialLen;
            buf += partialLen;
            continue;
        }

        // -----------

        if (partialLen == 0)
        {
            printf("* connection closed by the server\n");
        }
        else // partialLen < 0
        {
            int err = WSAGetLastError();
            printf("* error %d in send\n", err);
        }

        exit(1);
    }
}

// -----------------------------------------------------------------------------

static SOCKET create_accepting_socket(void)
{
    SOCKET acceptor = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (acceptor == INVALID_SOCKET)
    {
        printf("* error creating accept socket!\n");
        exit(1);
    }
    return acceptor;
}

// -----------------------------------------------------------------------------

static void create_io_completion_port(void)
{
    cpl_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if (!cpl_port)
    {
        int err = WSAGetLastError();
        printf("* error %d in line %d CreateIoCompletionPort\n", err, __LINE__);
        exit(1);
    }
}

// -----------------------------------------------------------------------------

static BOOL get_completion_status(DWORD* length, SocketState** socketState, WSAOVERLAPPED** ovl_res)
{
    BOOL resultOk;
    *ovl_res = NULL;
    *socketState = NULL;

    resultOk = GetQueuedCompletionStatus(cpl_port, length, (PULONG_PTR)socketState, ovl_res, INFINITE);

    if (!resultOk)
    {
        DWORD err = GetLastError();
        printf("* error %d getting completion port status!!!\n", err);
    }

    if (!*socketState || !*ovl_res)
    {
        printf("* don't know what to do, aborting!!!\n");
        exit(1);
    }

    return resultOk;
}

// -----------------------------------------------------------------------------
// the end

当服务器通过调用发送响应时:

WSASend(socketState->socket, &wsabuf, 1, NULL, 0, ovl, NULL)

我希望客户能在这条线上收到它:

resultOk = get_completion_status(&length, &socketState, &ovl_res);

但事实并非如此……

有人能告诉我我做错了什么吗?

Edit:

我采取了以下几点:

  • 在客户端,您使用 WSAConnect() 创建出站连接。
  • 需要时调用WSARecv()和WSASend()开始读/写操作
  • 如果你想使用 I/O 完成端口,你必须使用 WSASend/WSARecv。

并尝试创建一个简单的基于 IOCP 的客户端:

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

static DWORD WINAPI ClientWorkerThread(LPVOID lpParameter);

int main(void)
{
    WSADATA WsaDat;
    if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != NO_ERROR)
        return 0;

    // Step 1 - Create an I/O completion port.
    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if (!hCompletionPort)
        return 0;

    // Step 2 - Find how many processors.
    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);
    const int nNumberOfProcessors = systemInfo.dwNumberOfProcessors;

    // Step 3 - Create worker threads.
    for (int i = 0; i < nNumberOfProcessors; i++)
    {
        HANDLE hThread = CreateThread(NULL, 0, ClientWorkerThread, hCompletionPort, 0, NULL);
        CloseHandle(hThread);
    }

    // Step 4 - Create a socket.
    SOCKET Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    if (Socket == INVALID_SOCKET)
        return 0;

    struct hostent *host;
    if ((host = gethostbyname("localhost")) == NULL)
        return 0;

    SOCKADDR_IN SockAddr;
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
    SockAddr.sin_port = htons(8888);

    // Step 5 - Associate the socket with the I/O completion port.
    CreateIoCompletionPort((HANDLE)Socket, hCompletionPort, (ULONG_PTR)0, 0);

    if (WSAConnect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
        return 0;

    char buffer[1000];
    memset(buffer, 0, 999);
    WSABUF wsaBuf = {strlen(buffer), buffer};
    DWORD dwSendBytes = 0;
    DWORD dwReceivedBytes = 0;
    DWORD dwFlags = 0;
    WSAOVERLAPPED wsaOverlapped;
    SecureZeroMemory((PVOID)&wsaOverlapped, sizeof(wsaOverlapped));
    wsaOverlapped.hEvent = WSACreateEvent();

    for(;;)
    {
        WSARecv(Socket, &wsaBuf, 1, &dwReceivedBytes, &dwFlags, &wsaOverlapped, NULL);
        std::cout << wsaBuf.buf;

        //WSASend(Socket, &wsaBuf, 1, &dwSendBytes, 0, &wsaOverlapped, NULL);

        int nError = WSAGetLastError();
        if(nError != WSAEWOULDBLOCK&&nError != 0)
        {
            std::cout << "Winsock error code: " << nError << "\r\n";
            std::cout << "Server disconnected!\r\n";
            shutdown(Socket, SD_SEND);
            closesocket(Socket);

            break;
        }
        Sleep(1000);
    }

    WSACleanup();
    system("PAUSE");
    return 0;
}

static DWORD WINAPI ClientWorkerThread(LPVOID lpParameter)
{
    HANDLE hCompletionPort = (HANDLE)lpParameter;
    DWORD dwBytesTransferred = 0;

    while (TRUE)
    {
        BOOL bRet = GetQueuedCompletionStatus(hCompletionPort, &dwBytesTransferred, (LPDWORD)0, (LPOVERLAPPED*)0, INFINITE);
    }

    return 0;
}

我知道我做错了几件事,但我不知道它们是什么。

有人可以看一下我的代码并给我一些提示吗?

非常感谢

Edit 2:

抱歉这篇文章太长了。

在阅读了下面 Remy 的评论后,我再次尝试实现基于 IOCP 的客户端,但我仍然不确定我是否走在正确的轨道上。

如果有人可以看一下我的新代码(在 VS2010 下编译良好并且省略错误检查)并给我一些反馈,我将非常感激。

非阻塞客户端:

#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")

static DWORD WINAPI ClientWorkerThread(LPVOID lpParameter);

typedef struct _PER_HANDLE_DATA 
{
    SOCKET Socket;
} PER_HANDLE_DATA, * LPPER_HANDLE_DATA;

typedef struct
{
    WSAOVERLAPPED wsaOverlapped;
    WSABUF wsaBuf;
    int OperationType;
} PER_IO_DATA, * LPPER_IO_DATA;

int main(void)
{
    WSADATA WsaDat;
    WSAStartup(MAKEWORD(2, 2), &WsaDat);

    // Step 1 - Create an I/O completion port.
    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);

    // Step 2 - Find how many processors.
    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);

    // Step 3 - Create worker threads.
    for (int i = 0; i < (int)systemInfo.dwNumberOfProcessors; i++)
    {
        HANDLE hThread = CreateThread(NULL, 0, ClientWorkerThread, hCompletionPort, 0, NULL);
        CloseHandle(hThread);
    }

    // Step 4 - Create a socket.
    SOCKET Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

    PER_HANDLE_DATA *pPerHandleData = new PER_HANDLE_DATA;
    pPerHandleData->Socket = Socket;

    struct hostent *host;
    host = gethostbyname("localhost");

    SOCKADDR_IN SockAddr;
    SockAddr.sin_family = AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
    SockAddr.sin_port = htons(8888);

    // Step 5 - Associate the socket with the I/O completion port.
    CreateIoCompletionPort((HANDLE)Socket, hCompletionPort, (DWORD)pPerHandleData, 0);

    WSAConnect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr), NULL, NULL, NULL, NULL);

    static char buffer[1000];
    memset(buffer, 0, 999);

    PER_IO_DATA *pPerIoData = new PER_IO_DATA;

    pPerIoData->wsaBuf.buf = buffer;
    pPerIoData->wsaBuf.len = sizeof(buffer);

    DWORD dwSendBytes = 0;
    DWORD dwReceivedBytes = 0;
    DWORD dwFlags = 0;

    SecureZeroMemory((PVOID)&pPerIoData->wsaOverlapped, sizeof(pPerIoData->wsaOverlapped));
    pPerIoData->wsaOverlapped.hEvent = WSACreateEvent();

    WSARecv(Socket, &pPerIoData->wsaBuf, 1, &dwReceivedBytes, &dwFlags, &pPerIoData->wsaOverlapped, NULL);
    std::cout << pPerIoData->wsaBuf.buf;

    for (;;)
    {
        int nError = WSAGetLastError();
        if (nError != WSAEWOULDBLOCK&&nError != 0)
        {
            std::cout << "Winsock error code: " << nError << "\r\n";
            std::cout << "Server disconnected!\r\n";
            shutdown(Socket, SD_SEND);
            closesocket(Socket);

            break;
        }

        Sleep(1000);
    }

    delete pPerHandleData;
    delete pPerIoData;
    WSACleanup();
    return 0;
}

static DWORD WINAPI ClientWorkerThread(LPVOID lpParameter)
{
    HANDLE hCompletionPort = (HANDLE)lpParameter;
    DWORD bytesCopied = 0;
    OVERLAPPED *overlapped = 0;
    LPPER_HANDLE_DATA PerHandleData;
    LPPER_IO_DATA PerIoData;
    DWORD SendBytes, RecvBytes;
    DWORD Flags;
    BOOL bRet;

    while (TRUE)
    {
        bRet = GetQueuedCompletionStatus(hCompletionPort, &bytesCopied, (LPDWORD)&PerHandleData, (LPOVERLAPPED*)&PerIoData, INFINITE);

        if (bytesCopied == 0)
        {
            break;
        }
        else
        {
            Flags = 0;
            ZeroMemory(&(PerIoData->wsaOverlapped), sizeof(WSAOVERLAPPED));

            PerIoData->wsaBuf.len = 1000;
            WSARecv(PerHandleData->Socket, &(PerIoData->wsaBuf), 1, &RecvBytes, &Flags, &(PerIoData->wsaOverlapped), NULL);
        }
    }

    return 0;
}

非阻塞服务器:

#include <iostream>
#include <winsock2.h>
#pragma comment(lib,"ws2_32.lib")

int main()
{
    WSADATA WsaDat;
    WSAStartup(MAKEWORD(2,2), &WsaDat);

    SOCKET listenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);

    SOCKADDR_IN server;
    server.sin_family = AF_INET;
    server.sin_addr.s_addr = INADDR_ANY;
    server.sin_port = htons(8888);

    bind(listenSocket, (SOCKADDR*)(&server), sizeof(server));

    listen(listenSocket, 1);

    SOCKET acceptSocket = SOCKET_ERROR;
    sockaddr_in saClient;
    int nClientSize = sizeof(saClient);
    while (acceptSocket == SOCKET_ERROR)
    {
        std::cout << "Waiting for incoming connections...\r\n";
        acceptSocket = WSAAccept(listenSocket, (SOCKADDR*)&saClient, &nClientSize, NULL, NULL);
    }

    std::cout << "Client connected!\r\n\r\n";

    char *szMessage = "Welcome to the server!\r\n";
    WSAOVERLAPPED SendOverlapped;
    DWORD SendBytes;

    WSABUF DataBuf;
    DataBuf.len = 1000;
    DataBuf.buf = szMessage;

    SecureZeroMemory((PVOID)&SendOverlapped, sizeof(WSAOVERLAPPED));
    SendOverlapped.hEvent = WSACreateEvent();

    for (;;)
    {
        WSASend(acceptSocket, &DataBuf, 1, &SendBytes, 0, &SendOverlapped, NULL);

        int nError = WSAGetLastError();
        if (nError != WSAEWOULDBLOCK && nError != 0)
        {
            std::cout << "Winsock error code: " << nError << "\r\n";
            std::cout << "Client disconnected!\r\n";

            shutdown(acceptSocket, SD_SEND);
            closesocket(acceptSocket);

            break;
        }

        Sleep(1000);
    }

    WSACleanup();
    return 0;
}

再次感谢!


尝试这样的事情:

Client:

#include <iostream>
#include <string>
#include <winsock2.h> 
#pragma comment(lib, "ws2_32.lib") 

typedef struct 
{ 
    WSAOVERLAPPED Overlapped; 
    SOCKET Socket; 
    WSABUF wsaBuf; 
    char Buffer[1024];
    DWORD Flags;
} PER_IO_DATA, * LPPER_IO_DATA; 

static DWORD WINAPI ClientWorkerThread(LPVOID lpParameter) 
{ 
    HANDLE hCompletionPort = (HANDLE)lpParameter; 
    DWORD NumBytesRecv = 0; 
    ULONG CompletionKey; 
    LPPER_IO_DATA PerIoData; 

    while (GetQueuedCompletionStatus(hCompletionPort, &NumBytesRecv, &CompletionKey, (LPOVERLAPPED*)&PerIoData, INFINITE))
    {
        if (!PerIoData)
            continue;

        if (NumBytesRecv == 0) 
        {
            std::cout << "Server disconnected!\r\n\r\n";  
        }
        else
        {
            // use PerIoData->Buffer as needed...
            std::cout << std::string(PerIoData->Buffer, NumBytesRecv);

            PerIoData->wsaBuf.len = sizeof(PerIoData->Buffer); 
            PerIoData->Flags = 0; 

            if (WSARecv(PerIoData->Socket, &(PerIoData->wsaBuf), 1, &NumBytesRecv, &(PerIoData->Flags), &(PerIoData->Overlapped), NULL) == 0)
                continue;

            if (WSAGetLastError() == WSA_IO_PENDING)
                continue;
        }

        closesocket(PerIoData->Socket);
        delete PerIoData;
    } 

    return 0; 
} 

int main(void) 
{ 
    WSADATA WsaDat; 
    if (WSAStartup(MAKEWORD(2, 2), &WsaDat) != 0)
        return 0; 

    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); 
    if (!hCompletionPort)
        return 0;

    SYSTEM_INFO systemInfo; 
    GetSystemInfo(&systemInfo); 

    for (DWORD i = 0; i < systemInfo.dwNumberOfProcessors; ++i) 
    { 
        HANDLE hThread = CreateThread(NULL, 0, ClientWorkerThread, hCompletionPort, 0, NULL); 
        CloseHandle(hThread); 
    } 

    SOCKET Socket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED); 
    if (Socket == INVALID_SOCKET)
        return 0;

    SOCKADDR_IN SockAddr; 
    SockAddr.sin_family = AF_INET; 
    SockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    SockAddr.sin_port = htons(8888); 

    CreateIoCompletionPort((HANDLE)Socket, hCompletionPort, 0, 0); 

    if (WSAConnect(Socket, (SOCKADDR*)(&SockAddr), sizeof(SockAddr), NULL, NULL, NULL, NULL) == SOCKET_ERROR)
        return 0;

    PER_IO_DATA *pPerIoData = new PER_IO_DATA;
    ZeroMemory(pPerIoData, sizeof(PER_IO_DATA)); 

    pPerIoData->Socket = Socket; 
    pPerIoData->Overlapped.hEvent = WSACreateEvent(); 
    pPerIoData->wsaBuf.buf = pPerIoData->Buffer; 
    pPerIoData->wsaBuf.len = sizeof(pPerIoData->Buffer); 

    DWORD dwNumRecv;
    if (WSARecv(Socket, &(pPerIoData->wsaBuf), 1, &dwNumRecv, &(pPerIoData->Flags), &(pPerIoData->Overlapped), NULL) == SOCKET_ERROR)
    {
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            delete pPerIoData;
            return 0;
        }
    } 

    while (TRUE) 
        Sleep(1000); 

    shutdown(Socket, SD_BOTH); 
    closesocket(Socket); 

    WSACleanup(); 
    return 0; 
} 

Server:

#include <iostream>  
#include <winsock2.h>  
#pragma comment(lib,"ws2_32.lib")  

typedef struct
{
    WSAOVERLAPPED Overlapped;
    SOCKET Socket;
    WSABUF wsaBuf;
    char Buffer[1024];
    DWORD BytesSent;
    DWORD BytesToSend;
} PER_IO_DATA, * LPPER_IO_DATA; 


static DWORD WINAPI ServerWorkerThread(LPVOID lpParameter)
{
    HANDLE hCompletionPort = (HANDLE)lpParameter;
    DWORD NumBytesSent = 0;
    ULONG CompletionKey;
    LPPER_IO_DATA PerIoData;

    while (GetQueuedCompletionStatus(hCompletionPort, &NumBytesSent, &CompletionKey, (LPOVERLAPPED*)&PerIoData, INFINITE))    
    {
        if (!PerIoData)
            continue;

        if (NumBytesSent == 0)
        {
            std::cout << "Client disconnected!\r\n\r\n";
        }
        else
        {
            PerIoData->BytesSent += NumBytesSent;
            if (PerIoData->BytesSent < PerIoData->BytesToSend)
            {
                PerIoData->wsaBuf.buf = &(PerIoData->Buffer[PerIoData->BytesSent]);
                PerIoData->wsaBuf.len = (PerIoData->BytesToSend - PerIoData->BytesSent);
            }
            else
            {
                PerIoData->wsaBuf.buf = PerIoData->Buffer;
                PerIoData->wsaBuf.len = strlen(PerIoData->Buffer);
                PerIoData->BytesSent = 0;
                PerIoData->BytesToSend = PerIoData->wsaBuf.len;
            }

            if (WSASend(PerIoData->Socket, &(PerIoData->wsaBuf), 1, &NumBytesSent, 0, &(PerIoData->Overlapped), NULL) == 0)
                continue;

            if (WSAGetLastError() == WSA_IO_PENDING)
                continue;
        }

        closesocket(PerIoData->Socket);
        delete PerIoData;
    }

    return 0;
} 

int main()  
{  
    WSADATA WsaDat;  
    if (WSAStartup(MAKEWORD(2,2), &WsaDat) != 0)
        return 0;  

    HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);
    if (!hCompletionPort)
        return 0;

    SYSTEM_INFO systemInfo;
    GetSystemInfo(&systemInfo);

    for (DWORD i = 0; i < systemInfo.dwNumberOfProcessors; ++i)
    {
        HANDLE hThread = CreateThread(NULL, 0, ServerWorkerThread, hCompletionPort, 0, NULL);
        CloseHandle(hThread);
    } 

    SOCKET listenSocket = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);  
    if (listenSocket == INVALID_SOCKET)
        return 0;  

    SOCKADDR_IN server;
    ZeroMemory(&server, sizeof(server));
    server.sin_family = AF_INET;  
    server.sin_addr.s_addr = INADDR_ANY;  
    server.sin_port = htons(8888);  

    if (bind(listenSocket, (SOCKADDR*)(&server), sizeof(server)) != 0)
        return 0;  

    if (listen(listenSocket, 1) != 0)
        return 0;  

    std::cout << "Waiting for incoming connection...\r\n";  

    SOCKET acceptSocket;  
    do  
    {  
        sockaddr_in saClient;  
        int nClientSize = sizeof(saClient);  
        acceptSocket = WSAAccept(listenSocket, (SOCKADDR*)&saClient, &nClientSize, NULL, NULL);  
    }
    while (acceptSocket == INVALID_SOCKET);

    std::cout << "Client connected!\r\n\r\n";  

    CreateIoCompletionPort((HANDLE)acceptSocket, hCompletionPort, 0, 0); 

    LPPER_IO_DATA pPerIoData = new PER_IO_DATA;
    ZeroMemory(pPerIoData, sizeof(PER_IO_DATA));

    strcpy(pPerIoData->Buffer, "Welcome to the server!\r\n");  

    pPerIoData->Overlapped.hEvent = WSACreateEvent(); 
    pPerIoData->Socket = acceptSocket; 
    pPerIoData->wsaBuf.buf = pPerIoData->Buffer;  
    pPerIoData->wsaBuf.len = strlen(pPerIoData->Buffer);  
    pPerIoData->BytesToSend = pPerIoData->wsaBuf.len;  

    DWORD dwNumSent;
    if (WSASend(acceptSocket, &(pPerIoData->wsaBuf), 1, &dwNumSent, 0, &(pPerIoData->Overlapped), NULL) == SOCKET_ERROR)
    {
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            delete pPerIoData;
            return 0;
        }
    }  

    while (TRUE)  
        Sleep(1000);  

    shutdown(acceptSocket, SD_BOTH);  
    closesocket(acceptSocket);  

    WSACleanup();  
    return 0;  
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Winsock2 - 如何在客户端使用 IOCP 的相关文章

随机推荐

  • 在 Python 中连接字符串的首选方法是什么? [复制]

    这个问题在这里已经有答案了 自从Python的string无法更改 我想知道如何更有效地连接字符串 我可以这样写 s stringfromelsewhere 或者像这样 s s append somestring later s join
  • 为什么要在打印之前读取输入?

    I m having some problems with some basic I O stuff Specifically the text Please enter your name is written to the output
  • Java Swing 中的 PropertyGrid

    Java Swing 是否有类似于 NET 中 PropertyGrid 的控件 如果有 是哪一个 或者至少哪一个最接近它 Thanks 没有用于此目的的内置组件 但有几个第三方项目 尤其 Java Bean 检查器 GPL 看起来很有前途
  • 具有 MaterialComponents 主题的 ActionBar 背景

    我想自定义我的 ActionBar 我的主题如下所示 在值文件夹中
  • SQLAlchemy ORM:“AttributeError:无法在行中找到列”

    我现在正在学习 SQLAlchemy 但遇到了一个令我困惑的错误 是的 这里已经有类似的问题了 但似乎没有一个得到解决 我的目标是使用ORM模式来查询数据库 所以我创建了一个模型 from sqlalchemy import Column
  • Android SecurityException:管理员不拥有该配置文件

    我有一个设备管理器应用程序 我正在尝试使用自 API 21 以来可用的 DevicePolicyManager 类的 setScreenCaptureDisabled 函数 DevicePolicyManager pManager andr
  • 在 Eclipse 中使用和测试 Web 服务

    您能告诉我们如何在 Eclipse 中测试和使用 Web 服务的最佳方法吗 我对 Web 服务的经验很少 也就是说 我使用了一个生成客户端存根的 Apache Axis 插件 我现在不需要编写自己的 Web 服务 只需使用现有的 我有 Ec
  • 计算围绕多点线的多边形

    我正在尝试计算围绕连接多个点的线 例如 GPX 轨道 的多边形 下图显示了一个示例 其中轨道为红线 所需的多边形为蓝色 为了简化 红点由 x 和 y 表示 而不是纬度 经度 如果我只有指定路径的三个点的列表 如何计算这样的环境 浅蓝色多边形
  • boost::any 的访问者模式

    我找到了这个https gist github com 2945472但我需要一个不依赖于 c 11 的实现 我尝试将其转换为仅使用升压 但遇到了一些麻烦 这是我想出的 include
  • 即使使用 Web Font Loader,如何避免出现无样式文本 (FOUT) 的 Flash?

    我使用的是大约 100kb 的自定义字体 正如您可以想象的那样 浏览器文本从不可见文本闪烁到可见文本 因此我开始使用 webfontloader https github com typekit webfontloader 然而 即使使用此
  • MapKit 权利奇怪之处

    我有一个简单的 Mac 应用程序 不用于任何类型的分发 只是个人使用 该应用程序是一个NSWindow其中包含一个MKMapView 由于我没有 Mac 开发帐户 也不想要一个 请参阅 仅限个人使用 因此我不会进行任何形式的代码签名或配置
  • MYSQL:SELECT 方法 - 但不显示重复项/组或 DISTINCT?

    如何选择并且不显示重复项 实际上 它的显示是这样的 apple 苹果 苹果 苹果 这是我的代码 search GET q query SELECT FROM query WHERE searchquery LIKE search AND s
  • 当应用程序从 Xcode 停止时,applicationWillTerminate 不会被调用

    我遇到了一个奇怪的问题 其中 void applicationWillTerminate UIApplication application and void applicationDidEnterBackground UIApplicat
  • 如何将字符串中所有单词的第一个字母大写?

    首先 我所有的城市都以大写形式返回 因此我将它们切换为小写 现在如何将第一个字母变为大写 谢谢你的帮助 List
  • `#[lang = "..."]` 属性有什么作用?

    我正在阅读代码https doc rust lang org 1 56 0 src core str mod rs html 120 122 lang str cfg not test impl str 我找不到对此属性的引用lang 与声
  • 如何从非托管 C++ 调用托管 C++ 方法

    请参阅下面的更新 已解决 我也将其扩展为第二个问题在非托管 C 程序中实现 C DLL COM 文件 我已经在互联网的尽头对此进行了研究 但没有找到一个真实的 可理解的 人类的例子来说明如何做到这一点 我有一个用于加密和解密文本的 C DL
  • 如何检查多维 Twig 数组的值?

    要简单地检查数组是否包含某个值 我会这样做 if myVar in someOtherArray keys endif 但是 我的数组是多维的 tasks array someKey gt someValue tags gt array 0
  • 安卓模拟器有电话号码吗?

    我正在开发一个客户端 服务器 Android 应用程序 并试图找出如何明确识别服务器的不同手机 用户 我的第一次尝试是使用 SIM 卡上的电话号码 尽管现在我想起来了 现在你的电话号码发生变化是多么普遍 例如 当你更换运营商 我想这取决于国
  • 在 Qt 中的两个不同布局中使用相同的小部件

    我想在 Qt 的两个不同布局中使用相同的小部件 这是我的代码 QWidget myWidget new QWidget QFormLayout layout1 new QFormLayout layout1 gt addWidget myW
  • Winsock2 - 如何在客户端使用 IOCP

    我最近开始学习 Windows 上的 IOCP 并阅读了以下文章 http www codeproject com Tips 95363 Another TCP echo server using IOCP 您可以从以下位置下载本文的示例