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

📄 overserver.cpp

📁 这个是网络编程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
}

//
// Function: ValidateArgs
//
// Description:
//      Parses the command line arguments and sets up some global 
//      variables.
//
void ValidateArgs(int argc, char **argv)
{
    int     i;

    for(i=1; i < argc ;i++)
    {
        if (((argv[i][0] != '/') && (argv[i][0] != '-')) || (strlen(argv[i]) < 2))
            usage(argv[0]);
        else
        {
            switch (tolower(argv[i][1]))
            {
                case 'a':               // address family - IPv4 or IPv6
                    if (i+1 >= argc)
                        usage(argv[0]);
                    if (argv[i+1][0] == '4')
                        gAddressFamily = AF_INET;
                    else if (argv[i+1][0] == '6')
                        gAddressFamily = AF_INET6;
                    else
                        usage(argv[0]);
                    i++;
                    break;
                case 'b':               // buffer size for send/recv
                    if (i+1 >= argc)
                        usage(argv[0]);
                    gBufferSize = atol(argv[++i]);
                    break;
                case 'e':               // endpoint - port number
                    if (i+1 >= argc)
                        usage(argv[0]);
                    gBindPort = argv[++i];
                    break;
                case 'l':               // local address for binding
                    if (i+1 >= argc)
                        usage(argv[0]);
                    gBindAddr = argv[++i];
                    break;
                case 'o':               // overlapped count
                    if (i+1 >= argc)
                        usage(argv[0]);
                    gOverlappedCount = atol(argv[++i]);
                    break;
                case 'p':               // protocol - TCP or UDP
                    if (i+1 >= argc)
                        usage(argv[0]);
                    if (_strnicmp(argv[i+1], "tcp", 3) == 0)
                    {
                        gProtocol = IPPROTO_TCP;
                        gSocketType = SOCK_STREAM;
                    }
                    else if (_strnicmp(argv[i+1], "udp", 3) == 0)
                    {
                        gProtocol = IPPROTO_UDP;
                        gSocketType = SOCK_DGRAM;
                    }
                    else
                        usage(argv[0]);
                    i++;
                    break;
                default:
                    usage(argv[0]);
                    break;
            }
        }
    }
}

//
// Function: PrintStatistics
//
// Description:
//    Print the send/recv statistics for the server
//
void PrintStatistics()
{
    ULONG       bps, tick, elapsed;

    tick = GetTickCount();

    elapsed = (tick - gStartTime) / 1000;

    if (elapsed == 0)
        return;

    printf("\n");

    bps = gBytesSent / elapsed;
    printf("Average BPS sent: %lu [%lu]\n", bps, gBytesSent);

    bps = gBytesRead / elapsed;
    printf("Average BPS read: %lu [%lu]\n", bps, gBytesRead);

    elapsed = (tick - gStartTimeLast) / 1000;

    if (elapsed == 0)
        return;

    bps = gBytesSentLast / elapsed;
    printf("Current BPS sent: %lu\n", bps);

    bps = gBytesReadLast / elapsed;
    printf("Current BPS read: %lu\n", bps);

    printf("Total Connections  : %lu\n", gTotalConnections);
    printf("Current Connections: %lu\n", gCurrentConnections);

    InterlockedExchange(&gBytesSentLast, 0);
    InterlockedExchange(&gBytesReadLast, 0);

    gStartTimeLast = tick;
}

//
// Function: PostRecv
// 
// Description:
//    Post an overlapped receive operation on the socket.
//
int PostRecv(BUFFER_OBJ *recvobj)
{
    WSABUF  wbuf;
    DWORD   bytes,
            flags;
    int     rc=NO_ERROR;


    EnterCriticalSection(&recvobj->Socket->SockCritSec);

    recvobj->operation = OP_READ;

    wbuf.buf = recvobj->buf;
    wbuf.len = recvobj->buflen;

    flags = 0;

    if (gProtocol == IPPROTO_TCP)
    {
        rc = WSARecv(
                recvobj->Socket->s,
               &wbuf,
                1,
               &bytes,
               &flags,
               &recvobj->ol,
                NULL
                );
    }
    else
    {
        rc = WSARecvFrom(
                recvobj->Socket->s,
               &wbuf,
                1,
               &bytes,
               &flags,
                (SOCKADDR *)&recvobj->addr,
               &recvobj->addrlen,
               &recvobj->ol,
                NULL
                );
    }
    if (rc == SOCKET_ERROR)
    {
        rc = NO_ERROR;
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            fprintf(stderr, "PostRecv: WSARecv* failed: %d\n", WSAGetLastError());
            rc = SOCKET_ERROR;
        }
    }

    // Increment outstanding overlapped operations
    InterlockedIncrement(&recvobj->Socket->OutstandingOps);

    LeaveCriticalSection(&recvobj->Socket->SockCritSec);

    return NO_ERROR;
}

//
// Function: PostSend
//
// Description:
//    Post an overlapped send operation on the socket.
//
int PostSend(BUFFER_OBJ *sendobj)
{
    WSABUF  wbuf;
    DWORD   bytes;
    int     rc;

    rc = NO_ERROR;

    sendobj->operation = OP_WRITE;

    wbuf.buf = sendobj->buf;
    wbuf.len = sendobj->buflen;

    EnterCriticalSection(&sendobj->Socket->SockCritSec);
    if (gProtocol == IPPROTO_TCP)
    {
        rc = WSASend(
                sendobj->Socket->s,
               &wbuf,
                1,
               &bytes,
                0,
               &sendobj->ol,
                NULL
                );
    }
    else
    {
        rc = WSASendTo(
                sendobj->Socket->s,
               &wbuf,
                1,
               &bytes,
                0,
                (SOCKADDR *)&sendobj->addr,
                sendobj->addrlen,
               &sendobj->ol,
                NULL
                );
    }
    if (rc == SOCKET_ERROR)
    {
        rc = NO_ERROR;
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            fprintf(stderr, "PostSend: WSASend* failed: %d\n", WSAGetLastError());
            rc = SOCKET_ERROR;
        }
    }

    // Increment the outstanding operation count
    InterlockedIncrement(&sendobj->Socket->OutstandingOps);

    LeaveCriticalSection(&sendobj->Socket->SockCritSec);

    return rc;
}

//
// Function: PostAccept
//
// Description:
//    Post an overlapped accept on a listening socket.
//
int PostAccept(BUFFER_OBJ *acceptobj)
{
    DWORD   bytes;
    int     rc=NO_ERROR;

    acceptobj->operation = OP_ACCEPT;

    EnterCriticalSection(&acceptobj->Socket->SockCritSec);

    // Create the client socket for an incoming connection
    acceptobj->sclient = socket(acceptobj->Socket->af, SOCK_STREAM, IPPROTO_TCP);
    if (acceptobj->sclient == INVALID_SOCKET)
    {
        fprintf(stderr, "PostAccept: socket failed: %d\n", WSAGetLastError());
        return -1;
    }

    rc = acceptobj->Socket->lpfnAcceptEx(
            acceptobj->Socket->s,
            acceptobj->sclient,
            acceptobj->buf,
            acceptobj->buflen - ((sizeof(SOCKADDR_STORAGE) + 16) * 2),
            sizeof(SOCKADDR_STORAGE) + 16,
            sizeof(SOCKADDR_STORAGE) + 16,
           &bytes,
           &acceptobj->ol
            );
    if (rc == FALSE)
    {
        rc = NO_ERROR;
        if (WSAGetLastError() != WSA_IO_PENDING)
        {
            fprintf(stderr, "PostAccept: AcceptEx failed: %d\n",
                    WSAGetLastError());
            rc = SOCKET_ERROR;
        }
    }

    // Increment the outstanding overlapped count for this socket
    InterlockedIncrement(&acceptobj->Socket->OutstandingOps);

    LeaveCriticalSection(&acceptobj->Socket->SockCritSec);

    return rc;
}

//
// Function: HandleIo
//
// Description:
//    This function handles the IO on a socket. First, the events signaled
//    on the socket are enuemrated, then the appropriate handler routine
//    for the event is called.
//
void HandleIo(BUFFER_OBJ *buf)
{
    SOCKET_OBJ *sock=NULL,
               *clientobj=NULL;     // New client object for accepted connections
    BUFFER_OBJ *recvobj=NULL,       // Used to post new receives on accepted connections
               *sendobj=NULL;       // Used to post sends for data received
    DWORD       bytes,
                flags;
    BOOL        bFreeSocketObj;
    int         error,
                rc;

    // Extract the SOCKET_OBJ from the BUFFER_OBJ for easy reference
    sock = buf->Socket;
    error = NO_ERROR;

    bFreeSocketObj = FALSE;

    InterlockedDecrement(&sock->OutstandingOps);

    // Get the results of the overlapped operation that completed
    rc = WSAGetOverlappedResult(
            sock->s,
           &buf->ol,
           &bytes,
            FALSE,
           &flags
            );
    if (rc == FALSE)
    {
        error = WSAGetLastError();

        fprintf(stderr, "HandleIo: WSAGetOverlappedResult failed: %d\n", error);
        if (gProtocol == IPPROTO_TCP)
        {
            // An error occured on a TCP socket, so remove this I/O and if no
            //    more I/O is outstanding, free the socket object. Otherwise,
            //    wait for the remaining I/O on this socket to complete as well.
            RemoveBufferFromThread(sock, buf);
            FreeBufferObj(buf);

            if (InterlockedDecrement(&sock->OutstandingOps) == 0)
            {
                printf("Freeing socket obj in GetOverlapepdResult\n");
                FreeSocketObj(sock);
            }

            return;
        }
    }

    if (buf->operation == OP_ACCEPT)
    {
        SOCKADDR_STORAGE *LocalSockaddr=NULL,
                         *RemoteSockaddr=NULL;
        int               LocalSockaddrLen,
                          RemoteSockaddrLen;


        //  Update the counters
        InterlockedExchangeAdd(&gBytesRead, bytes);
        InterlockedExchangeAdd(&gBytesReadLast, bytes);

        InterlockedIncrement(&gTotalConnections);
        InterlockedIncrement(&gCurrentConnections);

        //  Retrieve the client's address
        sock->lpfnGetAcceptExSockaddrs(
                buf->buf,
                buf->buflen - ((sizeof(SOCKADDR_STORAGE) + 16) * 2),
                sizeof(SOCKADDR_STORAGE) + 16,
                sizeof(SOCKADDR_STORAGE) + 16,
                (SOCKADDR **)&LocalSockaddr,
               &LocalSockaddrLen,
                (SOCKADDR **)&RemoteSockaddr,
               &RemoteSockaddrLen
                );

        // Under high connection stress this print slows things down

        /*
        printf("Received connection from: ");
        PrintAddress((SOCKADDR *)RemoteSockaddr, RemoteSockaddrLen);
        printf("\n");
        */

        // Create a new SOCKET_OBJ for client socket
        clientobj = GetSocketObj(buf->sclient, buf->Socket->af);

        // Echo back any data received with the AcceptEx call
        sendobj = GetBufferObj(clientobj, gBufferSize);

        // Copy the data from the accept buffer to the send buffer
        sendobj->buflen = bytes;
        memcpy(sendobj->buf, buf->buf, bytes);

        // Assign the send operation to a thread
        AssignIoToThread(sendobj);

        // Initiate the overlapped send
        if (PostSend(sendobj) != NO_ERROR)
        {
            // In the event of an error, clean up the socket object
            RemoveBufferFromThread(clientobj, sendobj);
            FreeBufferObj(sendobj);

            closesocket(clientobj->s);
            clientobj->s = INVALID_SOCKET;

            FreeSocketObj(clientobj);
        }
        PostAccept(buf);
    }
    else if ((buf->operation == OP_READ) && (error == NO_ERROR))
    {
        //
        // Receive compeleted successfully
        //
        if ((bytes > 0) || (gProtocol == IPPROTO_UDP))
        {
            // Increment the counters
            InterlockedExchangeAdd(&gBytesRead, bytes);
            InterlockedExchangeAdd(&gBytesReadLast, bytes);

            // Create a buffer to send
            sendobj = buf;

            sendobj->buflen = bytes;

            // Initiate the send 
            if (PostSend(sendobj) != NO_ERROR)
            {
                // In the event of an error, clean up the socket object
                RemoveBufferFromThread(sock, sendobj);
                FreeBufferObj(sendobj);

                closesocket(sock->s);
                sock->s = INVALID_SOCKET;

                bFreeSocketObj = TRUE;
            }
        }
        else
        {
            // Graceful close
            sock->bClosing = TRUE;

            // Free the completed operation
            RemoveBufferFromThread(sock, buf);
            FreeBufferObj(buf);

            // Check to see if there are more outstanding operations. If so, wait
            //    for them to complete; otherwise, clean up the socket object.
            EnterCriticalSection(&sock->SockCritSec);
            if (sock->OutstandingOps == 0)
            {
                closesocket(sock->s);

                bFreeSocketObj = TRUE;
            }
            LeaveCriticalSection(&sock->SockCritSec);
        }
    }
    else if ((buf->operation == OP_READ) && (error != NO_ERROR) && (gProtocol == IPPROTO_UDP))
    {
        // If a UDP receive failed, we really don't care. Just re-post it - that is
        //    we probably got an ICMP error.
        if (PostRecv(buf) != NO_ERROR)
        {
            // In the event of an error, clean up the socket object
            RemoveBufferFromThread(sock, buf);
            FreeBufferObj(buf);

            closesocket(sock->s);
            sock->s = INVALID_SOCKET;

            bFreeSocketObj = TRUE;
        }
    }
    else if (buf->operation == OP_WRITE)
    {
        // Increment the counters
        InterlockedExchangeAdd(&gBytesSent, bytes);
        InterlockedExchangeAdd(&gBytesSentLast, bytes);

        // See if the socket is closing, if so check to see if there are any outstanding

⌨️ 快捷键说明

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