Legacy GM Networking: client <-> server miscommunication

Simon Gust

Member
Hello,
Having a problem with networking I decided to look into.
Problems with TCP:
- server steals packets it sends to the client and claims them for itself offsetting the buffer seek and causing errors.

Problems with UPD:
- Once the client sends a packet, the server will read that packet forever every step. The buffer does not seem to be illegal long after the client hasn't sent anything.
- The client anwsers his own network_send_udp() making the async event trigger everytime, however when asked who's socket is sending, it says that it isn't it's own socket. The test was made with the server unable to send any packets.
TCP
server create
Code:
tick = 0;
port = 6510;
writePing = 0;
serverID = network_create_server(network_socket_tcp, port, 12);
while (serverID < 0 && port < 65535)
{
    port++
    serverID = network_create_server(network_socket_tcp, port, 12);
}

socketList = ds_list_create();
server async
Code:
var SID = async_load[? "id"];
if (SID == serverID)
{
    show_debug_message("client update");
    var type = async_load[? "type"];
    switch(type)
    {
        case network_type_connect:
        {
            var cSocketID = async_load[? "socket"];
            addClient(cSocketID);       
        }
        break;
        case network_type_disconnect:
        {
            var cSocketID = async_load[? "socket"];
            delClient(cSocketID);
        }
        break;
    }
}
else
{
    var cBufferID = async_load[? "buffer"];
    if (cBufferID < 0)
    {
        show_debug_message("buffer illegal");
        exit;
    }
 
    show_debug_message("server new data");
    buffer_seek(cBufferID, 0, 0);
    var messageID = buffer_read(cBufferID, buffer_u8);
    switch (messageID)
    {
        case CMD.PING:
        {
            // read ping
            var ping = current_time - writePing;
            show_debug_message("ping: " + string(ping));
        }
    }
}
server step
Code:
tick++;
// send ping
if (tick mod 90 == 0)
{
    writePing = current_time;
    show_debug_message("server ask ping");
    var sBufferID = buffer_create(256, buffer_grow, 1);
    buffer_seek(sBufferID, buffer_seek_start, 0);
    buffer_write(sBufferID , buffer_u8, CMD.PING);
 
    // send to all clients
    var size = ds_list_size(socketList);
    for (var i = 0; i < size; i++)
    {
        var sock = socketList[| i];
        var ip = "127.0.0.1";
        var send = network_send_packet(sock, sBufferID, buffer_tell(sBufferID));
        if (send < 0) show_debug_message("server ask ping failed");
    }
 
    // free memory
    buffer_delete(sBufferID);
}
client create
Code:
cSocketID = network_create_socket(network_socket_tcp);
while (cSocketID < 0)
{
    cSocketID = network_create_socket(network_socket_tcp);
}

port = 0;
var con = network_connect(cSocketID, "127.0.0.1", port);
while (con < 0)
{
    port++;
    con = network_connect(cSocketID, "127.0.0.1", port);
}

// client map
clientMap = ds_map_create();
returnPing = false;
client async
Code:
var SID = async_load[? "id"];
if (SID == cSocketID)
{
    show_debug_message("client new message");
    var sBufferID = async_load[? "buffer"];
    if (sBufferID < 0)
    {
        show_debug_message("buffer illegal");
        exit;
    }
 
    buffer_seek(sBufferID, 0, 0);
    var type = buffer_read(sBufferID, buffer_u8);
    switch (type)
    {
        case CMD.PING:
        {
            // anwser ping
            show_debug_message("client return ping");
            returnPing = true;
        }
        break;
        case CMD.ADDCLIENT:
        {
            // get socketID
            show_debug_message("add client called");
            var sock = buffer_read(sBufferID, buffer_u16);
       
            // add to client map
            var inst = instance_create(60, 60, obj_player_client);
                inst.socketID = sock;
            socketMap[? sock] = inst;
        }
        break;
        case CMD.DELCLIENT:
        {
            // get socketID
            show_debug_message("del client called");
            var sock = buffer_read(sBufferID, buffer_u16);

            // add to client map
            var inst = socketMap[? sock];
            with (inst) instance_destroy();
        }
        break;
    }
}
client step
Code:
if (returnPing)
{
    show_debug_message("client writing ping");
    var cBufferID = buffer_create(256, buffer_grow, 1);
    buffer_seek(cBufferID, 0, 0);
    buffer_write(cBufferID , buffer_u8, CMD.PING);
 
    // send to server
    var send = network_send_packet(cSocketID, cBufferID, buffer_tell(cBufferID));
    if (send < 0) show_debug_message("client return ping failed");

    // free memory
    buffer_delete(cBufferID);
    returnPing = false;
}

UDP
server create
Code:
tick = 0;

var type = network_socket_udp;
var port = 8000;
sSocketID = network_create_socket_ext(type, port);
remotePort = 0;
remoteIP = "0.0.0.0";

var size = 1024;
var type = buffer_fixed;
sBufferID = buffer_create(size, type, 1);
server async
Code:
//Get the port and ip of the client
remotePort = async_load[? "port"];
remoteIP = string(async_load[? "ip"]);

// get buffer
var cBufferID = async_load[? "buffer"];
buffer_seek(cBufferID, 0, 0);

// read buffer
var type = buffer_read(cBufferID, buffer_u8);
switch (type)
{
    case CMD.PING:
    {
        // return ping
        show_debug_message("return ping");
        buffer_seek(sBufferID, 0, 0);
        buffer_write(sBufferID, buffer_u8, CMD.PING);
        var send = network_send_udp(sSocketID, remoteIP, remotePort, sBufferID, buffer_tell(sBufferID));
        if (send < 0) show_debug_message("packet lost");
    }
    break;
}
client create
Code:
readPing = 0;
tick = 0;

cSocketID = network_create_socket(network_socket_udp);
remoteIP = "127.0.0.1";
remotePort = 8000;

var size = 1024;
var type = buffer_fixed;
cBufferID = buffer_create(size, type, 1);
client async
Code:
//check for data
var sBufferID = async_load[? "buffer"];
buffer_seek(sBufferID, buffer_seek_start, 0);

// read
var type = buffer_read(sBufferID, buffer_u8);
switch (type)
{
    case CMD.PING:
    {   
        // seek ping
        var ping = current_time - readPing;
        show_debug_message("ping: " + string(ping));
    }
    break;
}
client step
Code:
tick++;
//send ping
if (tick mod 90 == 0)
{
    readPing = current_time;
    show_debug_message("send ping");
    buffer_seek(cBufferID, 0, 0);
    buffer_write(cBufferID, buffer_u8, CMD.PING);
    var send = network_send_udp(cSocketID, remoteIP, remotePort, cBufferID, buffer_tell(cBufferID));
    if (send < 0) show_debug_message("packet lost");
}
 
Last edited:

Simon Gust

Member
Add a default in the switch just to check. Or a message that show that the network async event trigger.
Thank you,
I will do that once I get home.
Just seeing now that the client's async event does not have a check for if the "type" is data transfer. Does it need that?
 

Simon Gust

Member
No idea. I usually use UDP. TCP use streams that I don't like. UDP is packet oriented. TCP may end up getting just a half package now and then.
I just read about tcp vs udp and I think I am more of a udp type.
And I think I'm misunderstanding the tcp. Does the server and client need to send data every step so the connection isn't lost?
 

The-any-Key

Member
client need to send data every step
You don't need to send anything with TCP. It handles everything.

In UDP you need to send a ping around every 30 seconds. Depending on what internet you use. For mobile networks it's good to send around a ping every 30 seconds. In LAN you can send around every 60 seconds.

Note that UDP don't have an insurance. Packets may be lost. So you need to keep track. Usually it's enough to send a count. Ex start with nr 1 and the receiver expect nr 1. And if the receiver get nr 3 we know that 2 was lost so send a message back and request a resend of 2 before we read 3.

I use GMnet for this. It use a counter and resend system that makes each message be read in the send order. It's like TCP but use UDP.
 

Simon Gust

Member
You don't need to send anything with TCP. It handles everything.

In UDP you need to send a ping around every 30 seconds. Depending on what internet you use. For mobile networks it's good to send around a ping every 30 seconds. In LAN you can send around every 60 seconds.

Note that UDP don't have an insurance. Packets may be lost. So you need to keep track. Usually it's enough to send a count. Ex start with nr 1 and the receiver expect nr 1. And if the receiver get nr 3 we know that 2 was lost so send a message back and request a resend of 2 before we read 3.

I use GMnet for this. It use a counter and resend system that makes each message be read in the send order. It's like TCP but use UDP.
Ah I see, I've set this up and now it works. Testing with sending ping every 1.5 seconds. <Updating Thread> (getting a ping of 17, is that anything to be alarmed of?, guessing no)
 

PNelly

Member
Ah I see, I've set this up and now it works. Testing with sending ping every 1.5 seconds. <Updating Thread> (getting a ping of 17, is that anything to be alarmed of?, guessing no)
A one frame processing delay will give you a ping of ~16/17 with a room speed of 60
 

Simon Gust

Member
Actually, not quite solved, I got mugged. When I send the call ping from the server to the client, the server actually sends it to itself. No wonder I have 16 ping.
I still can't send anything to the client nor from the client to the server.

Made more tests. When I send packets from the server the async event ->
Code:
var SID = async_load[? "id"];
if (SID != serverID)
{
    var type = async_load[? "type"];
    switch(type)
    {
        case network_type_data:
        {
            show_debug_message("server new data");
            var cBufferID = async_load[? "buffer"];
            var messageID = buffer_read(cBufferID, buffer_u8);
            switch (messageID)
            {
                case CMD.PING:
                {
                    // read ping
                    var ping = current_time - writePing;
                    show_debug_message("ping: " + string(ping));
                }
            }
        }
        break;
        default: show_debug_message("default"); break;
    }
}
Is getting called into the SID is not the serverID branch even though I just sent a pack from the server to all clients in the client list. What is the meaning of this?
The same thing happens even without the switch (type).

On top of that, I check if network_send_packets fail and they do not fail.
 
Last edited:

Simon Gust

Member
Ok, now I am fully confused. I managed to get the server and client to communitcate. But there are some problems:
- I get out of bounds buffer errors on a buffer that is called when a client connects, even though I just sent ping.
- The server, for some reason not only sends the packets to the clients but also to himself which probably gives me the error above.
I'm check if the internal buffer is less than 0 and call a "illegal buffer" but I guess that doesn't help that much.

EDIT: solved out of bounds error by seeking the built in buffer -.-
But why the server steals every client message is a mistery to me.
 
Last edited:

Simon Gust

Member
Do you use TCP or UDP now? just so we know what we are dealing with.
UDP, just edited the last post of mine. It's just the server stealing messages now, they are not lost however.
No, it was still TCP I didn't actually change it like I said I was going to.
 

Bingdom

Googledom
Here's some networking code I grabbed from some tutorial that no longer exists, due to dropbox broken links. (Using TCP)

oServer
Network Event
Code:
var type_event = ds_map_find_value( async_load, "type" );
switch( type_event ) {
    case network_type_connect:
        var socket = ds_map_find_value( async_load, "socket" );
        ds_list_add( SocketList , socket);
    break;
 
    case network_type_disconnect:
        var socket = ds_map_find_value( async_load, "socket" );
        var findsocket = ds_list_find_index( SockLiskt, socket );
    
        if ( findsocket >= 0 ) {
            ds_list_delete( SockList, findsocket);
        }
    break;
 
    case network_type_data:
        var buffer = ds_map_find_value( async_load, "buffer" );
        var socket = ds_map_find_value( async_load, "id");
        buffer_seek( buffer, buffer_seek_start, 0);
        ReceivedPacket( buffer, socket );
    break;
}
Recieve Packet
Code:
///ReceivedPacket( buffer, socket )
var buffer = argument0;
var socket = argument1;
var msgid = buffer_read( buffer , buffer_u8 );

switch( msgid ) {
    case 1:
        var time = buffer_read( buffer, buffer_u32 );
        buffer_seek( Buffer, buffer_seek_start, 0 );
        buffer_write( Buffer, buffer_u8, 1 );
        buffer_write( Buffer, buffer_u32, time );
        network_send_packet( socket, Buffer, buffer_tell( Buffer ));
    break;
}
oClient
Step Event
Code:
buffer_seek( Buffer, buffer_seek_start, 0);
buffer_write( Buffer, buffer_u8, 1 );
buffer_write( Buffer, buffer_u32, current_time );
var Result = network_send_packet( Socket, Buffer, buffer_tell( Buffer ));
Network Event
Code:
var type_event = ds_map_find_value( async_load, "type" );
switch( type_event ) {
    case network_type_data:
        var buffer = ds_map_find_value( async_load, "buffer" );
        buffer_seek( buffer, buffer_seek_start, 0 );
        ReceivedPacket_Client( buffer );
    break
}
Recieve Packet
Code:
///ReceivedPacket_Client( buffer )
var buffer = argument0;
var msgid = buffer_read( buffer, buffer_u8 );

switch( msgid ) {
    case 1:
        time = buffer_read( buffer, buffer_u32 );
        Ping = current_time - time;
    break;
}

Edit: I see a few issues with your current code. Will post about the issues when I find the time and remember or not if someone already mentions it.
For now, just see how the code I provided was set up. It does the same thing (except ping is sent every step).
 
Last edited:

Simon Gust

Member
So. Right now it's? TCP?
I've set up both, one for tcp and one for udp.
the tcp one still has the problem of the server stealing it's own packets it is sending
the udp one works except that once the client sent a packet, the server will do something with it every frame.
Updating main thread in a sec
 
J

jaydee

Guest
I would guess this is the problem with your tcp example:
Code:
var send = network_send_udp(sock, ip, port, sBufferID, buffer_tell(sBufferID));
       //var send = network_send_packet(sock, sBufferID, buffer_tell(sBufferID));
       if (send < 0) show_debug_message("server ask ping failed");
You've got the wrong code commented out.
 

Simon Gust

Member
I would guess this is the problem with your tcp example:
Code:
var send = network_send_udp(sock, ip, port, sBufferID, buffer_tell(sBufferID));
       //var send = network_send_packet(sock, sBufferID, buffer_tell(sBufferID));
       if (send < 0) show_debug_message("server ask ping failed");
You've got the wrong code commented out.
I forgot to change this code back to the original state when I tried udp, I ended up making 2 seperate udp objects and left this accidentally, but the tests I made did not have this code.
 
Top