0
votes

I'm having some problems with my Winsock application.

As it currently stands, when my client first connects to the server, the welcome message is sent fine but thats when it screws up. After that initial message its like the program goes into turbo mode.

Each client has a vector that stores messages that need to be sent, to debug I have it output how many messages are left to send and heres what the latest one says:

    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

EDIT: Managed to place some output code in the right place, for some reason when it starts sending update messages to clients, it starts sending the same message over and over.

Heres some code, am only posting the cpp's, 'Network::Update' is run by a thread in 'Game'

-- Server --

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
Have you tried using the debugger to figure out what is going wrong?Retired Ninja
Have used breakpoints and printf outputs but cant figure it outuser2990037

1 Answers

2
votes

There are a few problems with your code.

The main problem is that Network::sendMessage() runs an infinite loop. Your it iterator is never incremented (there is a comment saying as much - the comment is doing the wrong thing!), so the loop sends the same NetworkMessage to the same Client over and over without ever stopping. Do this instead:

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() is using pop_back() when it should be using pop_front() instead. If there are multiple pending messages in the vector, you will lose messages. Rather than using the [] operator to pass a NetworkMessage directly to send(), you should pop_front() the first pending message and then send() it:

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;
}

Your dead check in Network::Update() has a small logic hole in it that can prevent you from deleting dead clients correctly if doRead() returns true and then doWrite() return false. Do this instead:

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; 
}