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

📄 nbserver.cpp

📁 这个是网络编程
💻 CPP
📖 第 1 页 / 共 2 页
字号:
               &buffobj->addrlen
                );
    }
    if (rc == SOCKET_ERROR)
    {
        if (WSAGetLastError() != WSAEWOULDBLOCK)
        {
            // Socket connection has failed, close the socket
            fprintf(stderr, "recv(from) failed: %d\n", WSAGetLastError());

            closesocket(sockobj->s);

            ret = -1;
        }
        FreeBufferObj(buffobj);
    }
    else if (rc == 0)
    {
        // Graceful close
        if (gProtocol == IPPROTO_TCP)
        {
            FreeBufferObj(buffobj);
        }
        else
        {
            buffobj->buflen = 0;
            EnqueueBufferObj(sockobj, buffobj, FALSE);
        }

        sockobj->closing = TRUE;

        if (sockobj->pending == NULL)
        {
            // If no sends are pending, close the socket for good
            closesocket(sockobj->s);

            ret = -1;
        }
    }
    else
    {
        // Read data, updated the counters and enqueue the buffer for sending
        gBytesRead += rc;
        gBytesReadLast += rc;

        buffobj->buflen = rc;
        EnqueueBufferObj(sockobj, buffobj, FALSE);
    }
    return ret;
}

//
// Function: SendPendingData
//
// Description:
//    Send any data pending on the socket. This routine goes through the 
//    queued buffer objects within the socket object and attempts to
//    send all of them. If the send fails with WSAEWOULDBLOCK, put the
//    remaining buffer back in the queue (at the front) for sending
//    later when select indicates sends can be made. This routine returns
//    -1 to indicate that an error has occured on the socket and the
//    calling routine should remove the socket structure; otherwise, zero
//    is returned.
//
int SendPendingData(SOCKET_OBJ *sock)
{
    BUFFER_OBJ *bufobj=NULL;
    BOOL        breakouter;
    int         nleft,
                idx,
                ret,
                rc;

    // Attempt to dequeue all the buffer objects on the socket
    ret = 0;
    while (bufobj = DequeueBufferObj(sock))
    {
        if (gProtocol == IPPROTO_TCP)
        {
            breakouter = FALSE;

            nleft = bufobj->buflen;
            idx = 0;

            // In the event not all the data was sent we need to increment
            // through the buffer. This only needs to be done for stream
            // sockets since UDP is datagram and its all or nothing for that.
            while (nleft)
            {
                rc = send(
                        sock->s,
                       &bufobj->buf[idx],
                        nleft,
                        0
                        );
                if (rc == SOCKET_ERROR)
                {
                    if (WSAGetLastError() == WSAEWOULDBLOCK)
                    {
                        BUFFER_OBJ *newbuf=NULL;

                        // Copy the unsent portion of the buffer and put it back
                        // at the head of the send queue
                        newbuf = GetBufferObj(nleft);
                        memcpy(newbuf->buf, &bufobj->buf[idx], nleft);

                        EnqueueBufferObj(sock, newbuf, TRUE);
                    }
                    else
                    {
                        // The connection was broken, indicate failure
                        ret = -1;
                    }
                    breakouter = TRUE;

                    break;
                }
                else
                {
                    // Update the stastics and increment the send counters
                    gBytesSent += rc;
                    gBytesSentLast += rc;

                    nleft -= rc;
                    idx += 0;
                }
            }
            FreeBufferObj(bufobj);

            if (breakouter)
                break;
        }
        else
        {
            rc = sendto(
                    sock->s,
                    bufobj->buf,
                    bufobj->buflen,
                    0,
                    (SOCKADDR *)&bufobj->addr,
                    bufobj->addrlen
                    );
            if (rc == SOCKET_ERROR)
            {
                if (WSAGetLastError() == WSAEWOULDBLOCK)
                {
                    // If the send couldn't be made, put the buffer
                    // back at the head of the queue
                    EnqueueBufferObj(sock, bufobj, TRUE);

                    ret = 0;
                }
                else
                {
                    // Socket error occured so indicate the error to the caller
                    ret = -1;
                }
                break;
            }
            else
            {
                FreeBufferObj(bufobj);
            }
        }
    }
    // If no more sends are pending and the socket was marked as closing (the
    // receiver got zero bytes) then close the socket and indicate to the caller
    // to remove the socket structure.
    if ((sock->pending == NULL) && (sock->closing))
    {
        closesocket(sock->s);
        ret = -1;

        printf("Closing connection\n");
    }
    return ret;
}

//
// 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("Current Connections: %lu\n", gCurrentConnections);

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

    gStartTimeLast = tick;
}

//
// Function: main
//
// Description:
//      This is the main program. It parses the command line and creates
//      the main socket. For UDP this socket is used to receive datagrams.
//      For TCP the socket is used to accept incoming client connections.
//      Each client TCP connection is handed off to a worker thread which
//      will receive any data on that connection until the connection is
//      closed.
//
int __cdecl main(int argc, char **argv)
{
    WSADATA          wsd;
    SOCKET           s;
    SOCKET_OBJ      *sockobj=NULL,
                    *sptr=NULL,
                    *tmp=NULL;
    ULONG            lastprint=0;
    int              rc;
    struct fd_set    fdread,
                     fdwrite,
                     fdexcept;
    struct timeval   timeout;
    struct addrinfo *res=NULL,
                    *ptr=NULL;

    ValidateArgs(argc, argv);

    if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
    {
        fprintf(stderr, "unable to load Winsock!\n");
        return -1;
    }

    printf("Local address: %s; Port: %s; Family: %d\n",
            gBindAddr, gBindPort, gAddressFamily);

    res = ResolveAddress(gBindAddr, gBindPort, gAddressFamily, gSocketType, gProtocol);
    if (res == NULL)
    {
        fprintf(stderr, "ResolveAddress failed to return any addresses!\n");
        return -1;
    }

    // For each local address returned, create a listening/receiving socket
    ptr = res;
    while (ptr)
    {
        PrintAddress(ptr->ai_addr, ptr->ai_addrlen); printf("\n");

        // create the socket
        s = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
        if (s == INVALID_SOCKET)
        {
            fprintf(stderr,"socket failed: %d\n", WSAGetLastError());
            return -1;
        }

        sockobj = GetSocketObj(s, (gProtocol == IPPROTO_TCP) ? TRUE : FALSE);

        InsertSocketObj(sockobj);

        // bind the socket to a local address and port
        rc = bind(sockobj->s, ptr->ai_addr, ptr->ai_addrlen);
        if (rc == SOCKET_ERROR)
        {
            fprintf(stderr, "bind failed: %d\n", WSAGetLastError());
            return -1;
        }

        if (gProtocol == IPPROTO_TCP)
        {
            rc = listen(sockobj->s, 200);
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "listen failed: %d\n", WSAGetLastError());
                return -1;
            }
        }

        ptr = ptr->ai_next;
    }
    // free the addrinfo structure for the 'bind' address
    freeaddrinfo(res);

    gStartTime = gStartTimeLast = lastprint = GetTickCount();

    while (1)
    {
        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcept);

        sptr = gSocketList;

        // Set each socket in the FD_SET structures
        while (sptr)
        {
            FD_SET(sptr->s, &fdread);
            FD_SET(sptr->s, &fdwrite);
            FD_SET(sptr->s, &fdexcept);

            sptr = sptr->next;
        }

        timeout.tv_sec = 5;
        timeout.tv_usec = 0;

        rc = select(0, &fdread, &fdwrite, &fdexcept, &timeout);
        if (rc == SOCKET_ERROR)
        {
            fprintf(stderr, "select failed: %d\n", WSAGetLastError());
            return -1;
        }
        else if (rc == 0)
        {
            // timeout
            PrintStatistics();
        }
        else
        {
            // Go through all the socket and see if they're present in the
            // fd_set structures.
            sptr = gSocketList;
            while (sptr)
            {
                if (FD_ISSET(sptr->s, &fdread))
                {
                    if (sptr->listening)
                    {
                        // Read is indicated on a listening socket, accept the connection
                        sockobj = GetSocketObj(INVALID_SOCKET, FALSE);

                        s = accept(sptr->s, (SOCKADDR *)&sockobj->addr, &sockobj->addrlen);
                        if (s == INVALID_SOCKET)
                        {
                            fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
                            return -1;
                        }

                        InterlockedIncrement(&gCurrentConnections);

                        sockobj->s = s;
                        
                        /*
                        printf("Accepted connection from: ");
                        PrintAddress((SOCKADDR *)&sockobj->addr, sockobj->addrlen);
                        printf("\n");
                        */

                        InsertSocketObj(sockobj);
                    }
                    else
                    {
                        // Read is indicated on a client socket, receive data
                        if (ReceivePendingData(sptr) != 0)
                        {
                            printf("ReceivePendingData indicated to remove obj\n");
                            tmp = sptr;
                            sptr = sptr->next;

                            RemoveSocketObj(tmp);
                            FreeSocketObj(tmp);

                            // At the end of the list
                            if (sptr == NULL)
                                continue;
                        }

                        // Attempt to send pending data
                        if (SendPendingData(sptr) != 0)
                        {
                            tmp = sptr;
                            sptr = sptr->next;

                            RemoveSocketObj(tmp);
                            FreeSocketObj(tmp);

                            // At the end of the list
                            if (sptr == NULL)
                                continue;
                        }
                    }
                }
                if (FD_ISSET(sptr->s, &fdwrite))
                {
                    // Write is indicated so attempt to send the pending data
                    if (SendPendingData(sptr) != 0)
                    {
                        tmp = sptr;
                        sptr = sptr->next;

                        RemoveSocketObj(tmp);
                        FreeSocketObj(tmp);

                        // At the end of the list
                        if (sptr == NULL)
                            continue;
                    }
                }
                if (FD_ISSET(sptr->s, &fdexcept))
                {
                    // Not handling OOB data so just close the connection
                    tmp = sptr;
                    sptr = sptr->next;

                    RemoveSocketObj(tmp);
                    FreeSocketObj(tmp);

                    // At the end of the list
                    if (sptr == NULL)
                        continue;
                }

                sptr = sptr->next;
            }
        }

        // See if we should print statistics
        if ( (GetTickCount() - lastprint) > 5000)
        {
            PrintStatistics();

            lastprint = GetTickCount();
        }
    }

    WSACleanup();
    return 0;
}

⌨️ 快捷键说明

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