我的winsock应用程序出现问题

时间:2013-12-28 22:47:07

标签: c++ console winsock

我的Winsock应用程序遇到了一些问题。

目前看来,当我的客户端第一次连接到服务器时,欢迎消息被发送正常,但那就是搞砸了。在该初始消息之后,它就像程序进入turbo模式。

每个客户端都有一个存储需要发送的消息的向量,要调试我输出了剩余的消息要发送的内容以及最新消息的内容:

    Successfully sent message. 1 messages left.
    Successfully sent message. 1574803 messages left
    ................... (Counts down)
    Successfully sent message. 1574647 messages left
    Client connection closed or broken

编辑:管理将一些输出代码放在正确的位置,由于某种原因,当它开始向客户端发送更新消息时,它会一遍又一遍地开始发送相同的消息。

下载一些代码,我只发布了cpp,'Network :: Update'由'Game'中的一个帖子运行

- 服务器 -

Main.cpp的

    while(true)
    {
        m_Game -> Update();
        Sleep(500);
    }

Network.cpp

    #include "Network.h"

    Network::Network()
    {
    }

    Network::~Network()
    {
        closesocket(m_Socket);
    }

    Network::Network(char* ServerIP, int ServerPort)
    {
        Initialise(ServerIP, ServerPort);
    }

    void Network::Initialise(char* ServerIP, int ServerPort)
    {
        //
        // Initialise the winsock library to 2.2
        //
        WSADATA w;
        int error = WSAStartup(0x0202, &w);
        if ((error != 0)    || (w.wVersion != 0x0202))
        {
            MessageBox(NULL, L"Winsock error. Shutting down.", L"Notification", MB_OK);
            exit(1);
        }

        //
        // Create the TCP socket
        //
        m_Socket = socket(AF_INET, SOCK_STREAM, 0);
        if (m_Socket == SOCKET_ERROR)
        {
            MessageBox(NULL, L"Failed to create socket.", L"Notification", MB_OK);
            exit(1);
        }

        //
        // Fill out the address structure
        //
        m_Address.sin_family = AF_INET;
        m_Address.sin_addr.s_addr = inet_addr(ServerIP);
        m_Address.sin_port = htons(ServerPort);

        //
        // Bind the server socket to that address.
        //
        if (bind(m_Socket, (const sockaddr *) &m_Address, sizeof(m_Address)) != 0)
        {
            MessageBox(NULL, L"Failed to bind the socket to the address.", L"Notification", MB_OK);
            exit(1);
        }

        //
        // Make the socket listen for connections.
        //
        if (listen(m_Socket, 1) != 0)
        {
            MessageBox(NULL, L"Failed to listen on the socket.", L"Notification", MB_OK);
            exit(1);
        }

        m_ID = 1;
    }

    void Network::Update()
    {
        //
        // Structures for the sockets
        //
        fd_set readable, writeable;
        FD_ZERO(&readable);
        FD_ZERO(&writeable);

        //
        // Let the socket accept connections
        //
        FD_SET(m_Socket, &readable);

        //
        // Cycle through clients allowing them to read and write
        //
        for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
        {
            Client *client = *it;

            if (client->wantRead())
            {
                FD_SET(client->sock(), &readable);
            }

            if (client->wantWrite())
            {
                FD_SET(client->sock(), &writeable);
            }
        }

        //
        // Structure defining the connection time out
        //
        timeval timeout;
        timeout.tv_sec = 2;
        timeout.tv_usec = 500000;

        //
        // Check if a socket is readable
        //
        int count = select(0, &readable, &writeable, NULL, &timeout);
        if (count == SOCKET_ERROR)
        {
            ExitProgram(L"Unable to check if the socket can be read.\nREASON: Select failed");
        }

        //
        // Check if a theres an incoming connection
        //
        if (FD_ISSET(m_Socket, &readable))
        {
            //
            // Accept the incoming connection
            //
            sockaddr_in clientAddr;
            int addrSize = sizeof(clientAddr);
            SOCKET clientSocket = accept(m_Socket, (sockaddr *) &clientAddr, &addrSize);
            if (clientSocket > 0)
            {
                // Create a new Client object, and add it to the collection.
                Client *client = new Client(clientSocket);
                m_Clients.push_back(client);

                // Send the new client a welcome message.
                NetworkMessage message;
                message.m_Type = MT_Welcome;
                client->sendMessage(message);

                m_ID++;
            }
        }

        //
        // Loop through clients
        //
        for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); )  // note no ++it here
        {
            Client *client = *it;
            bool dead = false;

            //
            // Read data
            //
            if (FD_ISSET(client->sock(), &readable))
            {
                dead = client->doRead();
            }

            //
            // Write data
            //
            if (FD_ISSET(client->sock(), &writeable))
            {
                dead = client->doWrite();
            }

            //
            // Check if the client is dead (Was unable to write/read packets)
            //
            if (dead)
            {
                delete client;
                it = m_Clients.erase(it);
            }
            else
            {
                ++it;
            }
        }
    }

    void Network::sendMessage(NetworkMessage message)
    {
        //Loop through clients and send them the message
        for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); )  // note no ++it here
        {
            Client *client = *it;
            client->sendMessage(message);
        }
    }

Client.cpp

    #include "Client.h"

    Client::Client(SOCKET sock)
    {
        m_Socket = sock;
        send_count_ = 0;
    }

    // Destructor.
    Client::~Client()
    {
        closesocket(m_Socket);
    }

    // Process an incoming message.
    void Client::processMessage(NetworkMessage message)
    {
        // PROCESSING NEEDS TO GO HERE
    }

    // Return the client's socket.
    SOCKET Client::sock()
    {
        return m_Socket;
    }

    // Return whether this connection is in a state where we want to try
    // reading from the socket.
    bool Client::wantRead()
    {
        // At present, we always do.
        return true;
    }

    // Return whether this connection is in a state where we want to try-
    // writing to the socket.
    bool Client::wantWrite()
    {
        // Only if we've got data to send.
        //return send_count_ > 0;

        return Messages.size() > 0;
    }

    // Call this when the socket is ready to read.
    // Returns true if the socket should be closed.
    bool Client::doRead()
    {
        return false;
    }

    // Call this when the socket is ready to write.
    // Returns true if the socket should be closed.
    bool Client::doWrite()
    {
        /*int count = send(m_Socket, send_buf_, send_count_, 0);
        if (count <= 0)
        {
            printf("Client connection closed or broken\n");
            return true;
        }

        send_count_ -= count;

        // Remove the sent data from the start of the buffer.
        memmove(send_buf_, &send_buf_[count], send_count_);

        return false;*/

        int count = send(m_Socket, (char*)&Messages[0], sizeof(NetworkMessage), 0);
        if( count <= 0 )
        {
            printf("Client connection closed or broken\n");
            return true;
        }
        Messages.pop_back();
        printf(" Successfully sent message. %d messages left.\n", Messages.size() );

        return false;
    }

    void Client::sendMessage(NetworkMessage message)
    {
        /*if (send_count_ + sizeof(NetworkMessage) > sizeof(send_buf_))
        {
            ExitProgram(L"Unable to send message.\nREASON: send_buf_ full");
        }
        else
        {
            memcpy(&send_buf_[send_count_], message, sizeof(NetworkMessage));
            send_count_ += sizeof(NetworkMessage);
            printf(" Size of send_count_ : %d \n", send_count_);
        }*/

        Messages.push_back(message);
    }

Game.cpp

    void Game::Update()
    {
        tempPlayer -> ChangePosition(1, 1); //Increase X and Y pos by 1

        Dispatch();
        printf("Update\n");
    }

    void Game::Dispatch()
    {
        NetworkMessage temp;
        temp.m_Type = MT_Update;
        temp.m_ID = tempPlayer->getID();
        temp.m_positionX = tempPlayer->getX();
        temp.m_positionY = tempPlayer->getY();

        m_Network->sendMessage(temp);
    }

1 个答案:

答案 0 :(得分:2)

您的代码存在一些问题。

主要问题是Network::sendMessage()运行无限循环。你的it迭代器永远不会增加(有评论说的那么多 - 注释做错了!),所以循环将相同的NetworkMessage发送到同一个Client和没有停下来。这样做:

void Network::sendMessage(NetworkMessage message)
{
    //Loop through clients and send them the message
    for (std::list<Client *>::iterator it = m_Clients.begin(); it != m_Clients.end(); ++it)
    {
        ...
    }
}

Client::doWrite()正在使用pop_back(),而应使用pop_front()。如果向量中有多个待处理消息,您将丢失消息。您应该[]第一个待处理的消息,然后NetworkMessage它,而不是使用send()运算符将pop_front()直接传递给send()

bool Client::doWrite()
{
    NetworkMessage message = Messages.pop_front();

    int count = send(m_Socket, (char*)&message, sizeof(NetworkMessage), 0);
    if( count <= 0 )
    {
        printf("Client connection closed or broken\n");
        return true;
    }

    printf(" Successfully sent message. %d messages left.\n", Messages.size() );
    return false;
}

dead签入Network::Update()时,如果doRead()返回true,然后doWrite()返回false,则会阻止您正确删除死客户端。这样做:

bool dead = false;

//
// Read data
//
if (FD_ISSET(client->sock(), &readable))
{
    if (client->doRead())
        dead = true;
}

//
// Write data
//
if (FD_ISSET(client->sock(), &writeable))
{
    if (client->doWrite())
        dead = true; 
}