Raised This Month: $7 Target: $400
 1% 

More efficient way to read socket data forever?


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
HLM
Senior Member
Join Date: Apr 2008
Location: C:\WINDOWS\System32
Old 05-05-2019 , 14:16   More efficient way to read socket data forever?
Reply With Quote #1

Hello. I am developing a chat application loosely based on the ideas from Kost's cross server admin chat.
https://forums.alliedmods.net/showthread.php?t=29073

It appears that there is no way to watch a socket for new data, you must check if data exists, which is not inherently a problem.. however I am having an extremely hard time figuring out why this code is causing +20ms ping to all connected client (I expect a socket transport to cause some overhead on the server, but isnt that quite a bit for no data being sent?)

Anyways.. heres the code causing me my stress.
PHP Code:
public read_socket()
{

    if(
socket_is_readable(g_socket))
    {
        new 
buf[512];
        new 
recv socket_recv(g_socketbufcharsmax(buf));
        
server_print("Readable: %d RECV: %d"1recv);
        
//server_print("SiR = %d", readable);

        
if(recv 0)
        {
            
//socket_recv(g_socket, buf, 512);
            
server_print(buf);
            if (
strlen(g_inbuffer) + strlen(buf) > 2560)
            {
                
server_print("Error: Socket message overflow.");
                
disconnect_socket(1.0);
            }
            
strcat(g_inbufferbufcharsmax(buf));
            new 
pos strfind(g_inbuffer"^n");
            while (
pos!= -1)
            {
                new 
msg[512];
                
format(msgpos"%s"g_inbuffer);

                if(
msg[0]=='a')
                {
                    
//Authorize
                    
if(msg[2]=='S')
                    {
                        
//a.Success
                        //client_print(0, print_chat, "[ESN] Connected to master server!");
                        
server_print("Authorized with master server.");
                        for(new 
i=0get_maxplayers(); i++)
                        {
                            if(
g_NeedsAuth[i])
                            {
                                
AUTHORIZE(i);
                                
g_NeedsAuth[i] = false;
                            }
                        }
                    }
                }

                if(
msg[0]=='s')
                {
                    
//SYSTEM MSG
                    
if(msg[1]=='.')
                    {
                        
//c.Mesg (to all)
                        //client_print(0, print_chat, "%s", msg[2]);
                        
copy(g_sockbuf[g_sbindex], MAX_MSG_BUF-1msg);
                        
g_sbindex++;
                    }
                }
                if(
msg[0]=='p')
                {
                    
//pSTEAM_0:1:901100|SYSTEM|Mesg\n
                    
server_print(msg);
                    
copy(g_sockbuf[g_sbindex], MAX_MSG_BUF-1msg);
                    
server_print("%s"g_sockbuf[g_sbindex]);
                    
g_sbindex++;
                }
                if( (
msg[0]=='m') || (msg[0]=='c') )
                {
                    
//mSTEAM_0:1:901100|Hey Admins! What's up?\n
                    
copy(g_sockbuf[g_sbindex], MAX_MSG_BUF-1msg);
                    
g_sbindex++;
                }
                
format(g_inbuffercharsmax(g_inbuffer), "%s"g_inbuffer[pos+1]);
                
pos strfind(g_inbuffer"^n");
            }
            
//End of readable messages.. 
            
set_task(0.2"read_socket");
            
server_print("Inbuffer Cleared.");
        }
        else
        {
            
server_print("Socket error!");
            
disconnect_socket(3.0);
        }
    }
    else 
set_task(0.5"read_socket");

I don't *THINK* theres a more efficient way to poll a socket for a new message, the issue isnt even the data.. at most theres about 200-300 bytes sent down the stream once about every 2 seconds.. but I do want to be capable of handling up to 4+ messages a second as can be seen by the standard goldsrc chat protocol, but currently trying to set up a 0.5s manual looped task (set_task with flag "b" didn't give me much better results BTW) to read the data from the socket causes a +20ms ping, and that's only when there is one client connected.

I have heard that some people use entities instead of tasks, does this work better? or will I still see a big overhead like with the task system?

Any and all input is greatly appreciated. I have confirmed 100% that the lag is caused by this function as a whole, as disabling it will not increase my ping, and setting the delay higher seems to help subside the ping issue, however it still is present with 1.0s delay (which kind of defeats the purpose of a real time chat)
__________________
+|- KARMA Respectively

HLM is offline
Bugsy
AMX Mod X Moderator
Join Date: Feb 2005
Location: NJ, USA
Old 05-06-2019 , 17:52   Re: More efficient way to read socket data forever?
Reply With Quote #2

The regular sockets module is synchronous (blocking), which can create a lag/freeze when using commands. This type of socket should have never been implemented for use on a game server.

Try implementing your plugin with this, which uses non-blocking (asynchronous) sockets. There is an example cross-server chat plugin included.

I also started something similar but I forgot about it: https://forums.alliedmods.net/showthread.php?t=169315
__________________

Last edited by Bugsy; 05-06-2019 at 17:54.
Bugsy is offline
HLM
Senior Member
Join Date: Apr 2008
Location: C:\WINDOWS\System32
Old 05-07-2019 , 21:21   Re: More efficient way to read socket data forever?
Reply With Quote #3

I forgot to mention, im currently on AMXX 1.9 and using the new socket natives (including nonblocking flag on socket_open)

Unfortunately the server communication native will not work for me as I have one server controller that will broadcast that message to all other servers (cross server admin chat) and I don't think it is easy to implement this across 3+ (running 5, want to expand still) servers

Unfortunately, I think my current best case is to stick to the set_task loop, with that in mind.. is there a more efficient way of writing what I have? or perhaps theres an alternative still to set_task that would be more efficient? any and all input is appreciate, thanks.
__________________
+|- KARMA Respectively

HLM is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 07:34.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode