⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 eventserver.cpp

📁 这个是网络编程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
//
// Sample: WSAEventSelect IPv4/IPv6 Server
//
// Files:
//      eventserver.cpp - this file
//      resolve.cpp     - routines for resovling addresses, etc.
//      resolve.h       - header file for resolve.c
//
// Description:
//      This sample illustrates the WSAEventSelect IO for TCP and UDP for
//      both IPv4 and IPv6. This sample uses the getaddrinfo/getnameinfo
//      APIs which allows this application to be IP agnostic. That is the
//      desired address family (AF_INET or AF_INET6) can be determined
//      simply from the string address passed via the -l command.
//
//      Because of the limitation of waiting on a maximum of 64 events
//      at a time, this sample uses a thread pool to service client
//      connections. For TCP, a listening socket is created for each
//      accepted connection which registers for FD_ACCEPT notifications.
//      These sockets are assigned to a worker thread. Once a client
//      connection is established, read and write events are registered
//      and that socket is assigned to a worker thread as well. Once
//      a thread is waiting on the maximum events allowed, a new worker
//      thread will be created for additional connections, etc. For each
//      connection, data is read and then added to a send queue for that
//      connection. When data may be sent on the socket it is echoed back
//      to the client.
//
//      For UDP, this setup is similar except that only a single UDP socket
//      is created for each address family available.
//
//      For example:
//          If this sample is called with the following command lines:
//              eventserver.exe -l fe80::2efe:1234 -e 5150
//              eventserver.exe -l ::
//          Then the server creates an IPv6 socket as an IPv6 address was
//          provided.
//
//          On the other hand, with the following command line:
//              eventserver.exe -l 7.7.7.1 -e 5150
//              eventserver.exe -l 0.0.0.0
//          Then the server creates an IPv4 socket.
//
// Compile:
//      cl.exe -o eventserver.exe eventserver.cpp resolve.cpp ws2_32.lib
//
// Usage:
//      asyncserver.exe [options]
//          -a 4|6     Address family, 4 = IPv4, 6 = IPv6 [default = IPv4]
//          -b size    Size of send/recv buffer in bytes
//          -e port    Port number
//          -l addr    Local address to bind to [default INADDR_ANY for IPv4 or INADDR6_ANY for IPv6]
//          -p proto   Which protocol to use [default = TCP]
//             tcp         Use TCP protocol
//             udp         Use UDP protocol
//

#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>

#include "resolve.h"

#define DEFAULT_BUFFER_SIZE     4096    // default buffer size

int gAddressFamily = AF_UNSPEC,         // default to unspecified
    gSocketType    = SOCK_STREAM,       // default to TCP socket type
    gProtocol      = IPPROTO_TCP,       // default to TCP protocol
    gBufferSize    = DEFAULT_BUFFER_SIZE;

char *gBindAddr    = NULL,              // local interface to bind to
     *gBindPort    = "5150";            // local port to bind to

//
// Allocated for each receiver posted
//
typedef struct _BUFFER_OBJ
{
    char        *buf;           // Data buffer for data
    int          buflen;        // Length of buffer or number of bytes contained in buffer

    SOCKADDR_STORAGE addr;      // Address data was received from (UDP)
    int              addrlen;   // Length of address

    struct _BUFFER_OBJ *next;   // Used to maintain a linked list of buffers
} BUFFER_OBJ;

//
// Allocated for each socket handle
//
typedef struct _SOCKET_OBJ
{
    SOCKET      s;              // Socket handle
    HANDLE      event;          // Event handle
    int         listening;      // Socket is a listening socket (TCP)
    int         closing;        // Indicates whether the connection is closing

    SOCKADDR_STORAGE addr;      // Used for client's remote address
    int              addrlen;   // Length of the address

    BUFFER_OBJ *pending,        // List of pending buffers to be sent
               *pendingtail;    // Last entry in buffer list

    struct _SOCKET_OBJ *next,   // Used to link socket objects together
                       *prev;
} SOCKET_OBJ;

//
// Allocated for each trhead spawned
//
typedef struct _THREAD_OBJ
{
    SOCKET_OBJ *SocketList,            // Linked list of all sockets allocated
               *SocketListEnd;         // End of socket list
    int         SocketCount;           // Number of socket objects in list

    HANDLE      Event;                 // Used to signal new clients assigned
                                       //  to this thread
    HANDLE      Thread;

    HANDLE      Handles[MAXIMUM_WAIT_OBJECTS]; // Array of socket's event handles

    CRITICAL_SECTION ThreadCritSec;    // Protect access to SOCKET_OBJ lists

    struct _THREAD_OBJ *next;          // Next thread object in list
} THREAD_OBJ;

THREAD_OBJ *gChildThreads=NULL;        // List of thread objects allocated
int         gChildThreadsCount=0;      // Number of child threads created

//
// Statistics counters
//
volatile LONG gBytesRead=0,
              gBytesSent=0,
              gStartTime=0,
              gBytesReadLast=0,
              gBytesSentLast=0,
              gStartTimeLast=0,
              gTotalConnections=0,
              gCurrentConnections=0;

//
// Function: usage
//
// Description:
//      Prints usage information and exits the process.
//
void usage(char *progname)
{
    fprintf(stderr, "usage: %s [-a 4|6] [-e port] [-l local-addr] [-p udp|tcp]\n",
            progname);
    fprintf(stderr, "  -a 4|6     Address family, 4 = IPv4, 6 = IPv6 [default = IPv4]\n"
                    "  -b size    Buffer size for send/recv [default = %d]\n"
                    "  -e port    Port number [default = %s]\n"
                    "  -l addr    Local address to bind to [default INADDR_ANY for IPv4 or INADDR6_ANY for IPv6]\n"
                    "  -p tcp|udp Which protocol to use [default = TCP]\n",
                    gBufferSize,
                    gBindPort
                    );
    ExitProcess(-1);
}

//
// Function: GetBufferObj
// 
// Description:
//    Allocate a BUFFER_OBJ. Each receive posted by a receive thread allocates
//    one of these. After the recv is successful, the BUFFER_OBJ is queued for
//    sending by the send thread. Again, lookaside lists may be used to increase
//    performance.
//
BUFFER_OBJ *GetBufferObj(int buflen)
{
    BUFFER_OBJ *newobj=NULL;

    // Allocate the object
    newobj = (BUFFER_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BUFFER_OBJ));
    if (newobj == NULL)
    {
        fprintf(stderr, "GetBufferObj: HeapAlloc failed: %d\n", GetLastError());
        ExitProcess(-1);
    }
    // Allocate the buffer
    newobj->buf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BYTE) *buflen);
    if (newobj->buf == NULL)
    {
        fprintf(stderr, "GetBufferObj: HeapAlloc failed: %d\n", GetLastError());
        ExitProcess(-1);
    }
    newobj->buflen = buflen;

    newobj->addrlen = sizeof(newobj->addr);

    return newobj;
}

//
// Function: FreeBufferObj
// 
// Description:
//    Free the buffer object.
//
void FreeBufferObj(BUFFER_OBJ *obj)
{
    HeapFree(GetProcessHeap(), 0, obj->buf);
    HeapFree(GetProcessHeap(), 0, obj);
}

//
// Function: GetSocketObj
//
// Description:
//    Allocate a socket object and initialize its members. A socket object is
//    allocated for each socket created (either by socket or accept). The
//    socket objects mantain a list of all buffers received that need to
//    be sent.
//
SOCKET_OBJ *GetSocketObj(SOCKET s, int listening)
{
    SOCKET_OBJ  *sockobj=NULL;

    sockobj = (SOCKET_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SOCKET_OBJ));
    if (sockobj == NULL)
    {
        fprintf(stderr, "GetSocketObj: HeapAlloc failed: %d\n", GetLastError());
        ExitProcess(-1);
    }

    // Initialize the members
    sockobj->s = s;
    sockobj->listening = listening;
    sockobj->addrlen = sizeof(sockobj->addr);

    sockobj->event = WSACreateEvent();
    if (sockobj->event == NULL)
    {
        fprintf(stderr, "GetSocketObj: WSACreateEvent failed: %d\n", WSAGetLastError());
        ExitProcess(-1);
    }

    return sockobj;
}

//
// Function: FreeSocketObj
//
// Description:
//    Frees a socket object along with any queued buffer objects.
//
void FreeSocketObj(SOCKET_OBJ *obj)
{
    BUFFER_OBJ  *ptr=NULL,
                *tmp=NULL;

    ptr = obj->pending;
    while (ptr)
    {
        tmp = ptr;
        ptr = ptr->next;

        FreeBufferObj(tmp);
    }

    WSACloseEvent(obj->event);

    if (obj->s != INVALID_SOCKET)
    {
        closesocket(obj->s);
    }

    HeapFree(GetProcessHeap(), 0, obj);
}

//
// Function: GetThreadObj
//
// Description:
//    Allocate a thread object and initializes its members.
//
THREAD_OBJ *GetThreadObj()
{
    THREAD_OBJ *thread=NULL;

    thread = (THREAD_OBJ *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(THREAD_OBJ));
    if (thread == NULL)
    {
        fprintf(stderr, "GetThreadObj: HeapAlloc failed: %d\n", GetLastError());
        ExitProcess(-1);
    }

    thread->Event = WSACreateEvent();
    if (thread->Event == NULL)
    {
        fprintf(stderr, "GetThreadObj: WSACreateEvent failed: %d\n", WSAGetLastError());
        ExitProcess(-1);
    }

    thread->Handles[0] = thread->Event;

    InitializeCriticalSection(&thread->ThreadCritSec);

    return thread;
}

//
// Function: FreeThreadObj
//
// Description:
//    Free a thread object and is member fields.
//
void FreeThreadObj(THREAD_OBJ *thread)
{
    WSACloseEvent(thread->Event);

    CloseHandle(thread->Thread);

    DeleteCriticalSection(&thread->ThreadCritSec);

    HeapFree(GetProcessHeap(), 0, thread);
}

//
// Function: InsertSocketObj
//
// Description:
//    Insert a socket object into the list of socket objects for
//    the given thread object.
//
int InsertSocketObj(THREAD_OBJ *thread, SOCKET_OBJ *sock)
{
    int     ret;

    EnterCriticalSection(&thread->ThreadCritSec);

    if (thread->SocketCount < MAXIMUM_WAIT_OBJECTS-1)
    {
        sock->next = sock->prev = NULL;
        if (thread->SocketList == NULL)
        {
            // List is empty
            thread->SocketList = thread->SocketListEnd = sock;
        }
        else
        {
            // Non-empty; insert at the end
            sock->prev = thread->SocketListEnd;
            thread->SocketListEnd->next = sock;
            thread->SocketListEnd = sock;

        }
        // Assign the socket's event into the thread's event list
        thread->Handles[thread->SocketCount + 1] = sock->event;
        thread->SocketCount++;

        ret = NO_ERROR;
    }
    else
    {
        ret = SOCKET_ERROR;
    }

    LeaveCriticalSection(&thread->ThreadCritSec);

    return ret;
}

//
// Function: RemoveSocketObj
//
// Description:
//    Remove a socket object from the list of sockets for the given thread.
//
void RemoveSocketObj(THREAD_OBJ *thread, SOCKET_OBJ *sock)
{
    EnterCriticalSection(&thread->ThreadCritSec);
    if (sock->prev)
    {
        sock->prev->next = sock->next;
    }
    if (sock->next)
    {
        sock->next->prev = sock->prev;
    }

    if (thread->SocketList == sock)
        thread->SocketList = sock->next;
    if (thread->SocketListEnd == sock)
        thread->SocketListEnd = sock->prev;

    thread->SocketCount--;

    // Signal thread to rebuild array of events
    WSASetEvent(thread->Event);

    InterlockedDecrement(&gCurrentConnections);

    LeaveCriticalSection(&thread->ThreadCritSec);
}

//
// Function: FindSocketObj
// 
// Description:
//    Find a socket object within the list of sockets from a thread. The socket
//    object is found by index number -- this must be so because the index of
//    the event object in the thread's event array must match the order in which
//    the socket object appears in the thread's socket list.
//
SOCKET_OBJ *FindSocketObj(THREAD_OBJ *thread, int index)
{
    SOCKET_OBJ *ptr=NULL;
    int         i;

    EnterCriticalSection(&thread->ThreadCritSec);

    ptr = thread->SocketList;
    for(i=0; i < index ;i++)
    {
        ptr = ptr->next;
    }

    LeaveCriticalSection(&thread->ThreadCritSec);

    return ptr;
}

//
// Function: EnqueueBufferObj
//
// Description:
//   Queue up a receive buffer for this connection (socket).
//
void EnqueueBufferObj(SOCKET_OBJ *sock, BUFFER_OBJ *obj, BOOL AtHead)
{
    if (sock->pending == NULL)
    {
        // Queue is empty
        sock->pending = sock->pendingtail = obj;
    }
    else if (AtHead == FALSE)
    {
        // Put new object at the end 
        sock->pendingtail->next = obj;
        sock->pendingtail = obj;
    }
    else
    {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -