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

📄 eventserver.cpp

📁 这个是网络编程
💻 CPP
📖 第 1 页 / 共 3 页
字号:
        }
    }
    if (nevents.lNetworkEvents & FD_CLOSE)
    {
        // Check for close error
        if (nevents.iErrorCode[FD_CLOSE_BIT] == 0)
        {
            // Socket has been indicated as closing so make sure all the data
            // has been read
            while (1)
            {
                rc = ReceivePendingData(sock);
                if (rc == -1)
                {
                    RemoveSocketObj(thread, sock);
                    FreeSocketObj(sock);
                    return SOCKET_ERROR;
                }
                else if (rc != 0)
                {
                    continue;
                }
                else
                {
                    break;
                }
            }
            // See if there is any data pending, if so try to send it
            rc = SendPendingData(sock);
            if (rc == -1)
            {
                RemoveSocketObj(thread, sock);
                FreeSocketObj(sock);
                return SOCKET_ERROR;
            }
        }
        else
        {
            fprintf(stderr, "HandleIo: FD_CLOSE error %d\n",
                    nevents.iErrorCode[FD_CLOSE_BIT]);
            RemoveSocketObj(thread, sock);
            FreeSocketObj(sock);
            return SOCKET_ERROR;
        }
    }
    return NO_ERROR;
}

void RenumberThreadArray(THREAD_OBJ *thread)
{
    SOCKET_OBJ *sptr=NULL;
    int         i;

    EnterCriticalSection(&thread->ThreadCritSec);
    i = 0;
    sptr = thread->SocketList;
    while (sptr)
    {
        thread->Handles[i+1] = sptr->event;

        i++;
        sptr = sptr->next;
    }
    LeaveCriticalSection(&thread->ThreadCritSec);
}

//
// Function: ChildThread
//
// Description:
//    This is the child thread that handles socket connections. Each thread
//    can only wait on a maximum of 63 sockets. The main thread will assign
//    each client connection to one of the child threads. If there is no
//    thread to handle the socket, a new thread is created to handle the 
//    connection.
//
DWORD WINAPI ChildThread(LPVOID lpParam)
{
    THREAD_OBJ *thread=NULL;
    SOCKET_OBJ *sptr=NULL,
               *sockobj=NULL;
    int         index,
                rc,
                i;

    thread = (THREAD_OBJ *)lpParam;

    while (1)
    {
        rc = WaitForMultipleObjects(
                thread->SocketCount + 1,
                thread->Handles,
                FALSE,
                INFINITE
                );
        if (rc == WAIT_FAILED || rc == WAIT_TIMEOUT)
        {
            fprintf(stderr, "ChildThread: WaitForMultipleObjects failed: %d\n", GetLastError());
            break;
        }
        else
        {
            // Multiple events may be signaled at one time so check each
            // event to see if its signaled
            //
            for(i=0; i < thread->SocketCount + 1 ;i++)
            {
                rc = WaitForSingleObject(thread->Handles[i], 0);
                if (rc == WAIT_FAILED)
                {
                    fprintf(stderr, "ChildThread: WaitForSingleObject failed: %d\n", GetLastError());
                    ExitThread(-1);
                }
                else if (rc == WAIT_TIMEOUT)
                {
                    // This event isn't signaled, continue to the next one
                    continue;
                }

                index = i;

                if (index == 0)
                {
                    // If index 0 is signaled then rebuild the array of event
                    //    handles to wait on
                    WSAResetEvent(thread->Handles[index]);

                    RenumberThreadArray(thread);
                     
                    i = 1;
                }
                else
                {
                    // Otherwise, its an event associated with a socket that
                    //    was signaled. Handle the IO on that socket.
                    //
                    sockobj = FindSocketObj(thread, index-1);
                    if (sockobj != NULL)
                    {
                        if (HandleIo(thread, sockobj) == SOCKET_ERROR)
                        {
                            RenumberThreadArray(thread);
                        }
                    }
                    else
                    {
                        printf("Unable to find socket object!\n");
                    }
                }
            }
        }
    }

    ExitThread(0);
    return 0;
}

//
// Function: AssignToFreeThread
//
// Description:
//    This routine assigns a socket connection to an available child
//    thread to handle any IO on it. If no threads are available, a 
//    new thread is spawned to handle the connection.
//
void AssignToFreeThread(SOCKET_OBJ *sock)
{
    THREAD_OBJ *thread=NULL;

    thread = gChildThreads;
    while (thread)
    {
        // If this routine returns something other than SOCKET_ERROR
        //    that it was successfully assigned to a child thread.
        if (InsertSocketObj(thread, sock) != SOCKET_ERROR)
            break;
        thread = thread->next;
    }

    if (thread == NULL)
    {
        // No thread was found to assign the client socket to, create a new thread
        //
        printf("Creating new thread object\n");

        thread = GetThreadObj();

        thread->Thread = CreateThread(NULL, 0, ChildThread, (LPVOID)thread, 0, NULL);
        if (thread->Thread == NULL)
        {
            fprintf(stderr, "AssignToFreeThread: CreateThread failed: %d\n", GetLastError());
            ExitProcess(-1);
        }

        InsertSocketObj(thread, sock);

        // Insert the thread the list of threads
        if (gChildThreads == NULL)
        {
            gChildThreads = thread;
        }
        else
        {
            thread->next = gChildThreads;
            gChildThreads = thread;
        }

        gChildThreadsCount++;

    }
 
    // signal child thread to rebuild the event list
    WSASetEvent(thread->Event);

    return;
}

//
// 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;
    THREAD_OBJ      *thread=NULL;
    SOCKET_OBJ      *sockobj=NULL,
                    *newsock=NULL;
    int              index,
                     rc;
    struct addrinfo *res=NULL,
                    *ptr=NULL;

    // Validate the command line
    ValidateArgs(argc, argv);

    // Load Winsock
    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;
    }

    thread = GetThreadObj();

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

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

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

        InsertSocketObj(thread, 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;
            }

            // Register events on the socket
            rc = WSAEventSelect(
                    sockobj->s,
                    sockobj->event,
                    FD_ACCEPT | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }
        else
        {
            // Register events on the socket
            rc = WSAEventSelect(
                    sockobj->s,
                    sockobj->event,
                    FD_READ | FD_WRITE | FD_CLOSE
                    );
            if (rc == SOCKET_ERROR)
            {
                fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                return -1;
            }
        }

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

    gStartTime = gStartTimeLast = GetTickCount();

    while (1)
    {
        rc = WaitForMultipleObjects(
                thread->SocketCount + 1,
                thread->Handles,
                FALSE,
                5000
                );
        if (rc == WAIT_FAILED)
        {
            fprintf(stderr, "WaitForMultipleObjects failed: %d\n", GetLastError());
            break;
        }
        else if (rc == WAIT_TIMEOUT)
        {
            PrintStatistics();
        }
        else
        {
            index = rc - WAIT_OBJECT_0;

            sockobj = FindSocketObj(thread, index-1);

            if (gProtocol == IPPROTO_TCP)
            {
                SOCKADDR_STORAGE sa;
                WSANETWORKEVENTS ne;
                SOCKET           sc;
                int              salen;

                rc = WSAEnumNetworkEvents(
                        sockobj->s,
                        thread->Handles[index],
                       &ne
                        );
                if (rc == SOCKET_ERROR)
                {
                    fprintf(stderr, "WSAEnumNetworkEvents failed: %d\n", WSAGetLastError());
                    break;
                }

                while (1)
                {
                    sc = INVALID_SOCKET;
                    salen = sizeof(sa);

                    //
                    // For TCP, accept the connection and hand off the client socket
                    // to a worker thread
                    //

                    sc = accept(
                            sockobj->s, 
                            (SOCKADDR *)&sa,
                            &salen
                               );
                    if ((sc == INVALID_SOCKET) && (WSAGetLastError() != WSAEWOULDBLOCK))
                    {
                        fprintf(stderr, "accept failed: %d\n", WSAGetLastError());
                        break;
                    }
                    else if (sc != INVALID_SOCKET)
                    {
                        newsock = GetSocketObj(INVALID_SOCKET, FALSE);

                        // Copy address information
                        memcpy(&newsock->addr, &sa, salen);
                        newsock->addrlen = salen;

                        newsock->s = sc;

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

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

                        // Register for read, write and close on the client socket
                        rc = WSAEventSelect(
                                newsock->s,
                                newsock->event,
                                FD_READ | FD_WRITE | FD_CLOSE
                                           );
                        if (rc == SOCKET_ERROR)
                        {
                            fprintf(stderr, "WSAEventSelect failed: %d\n", WSAGetLastError());
                            break;
                        }

                        AssignToFreeThread(newsock);

                    }
                    else
                    {
                        // Failed with WSAEWOULDBLOCK -- just continue
                        break;
                    }
                }


            }
            else
            {
                // For UDP all we have to do is handle events on the main
                //    threads.
                if (HandleIo(thread, sockobj) == SOCKET_ERROR)
                {
                    RenumberThreadArray(thread);
                }
            }
        }
    }

    WSACleanup();
    return 0;
}

⌨️ 快捷键说明

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