Network programing question

06/20/2016 09:28 theking200051#1
hello guys ,
i got 2 question's confused me alot :-

first , sro is based on tcp and as i know tcp is responsible to deliver all packets and arrange them but some times my program miss some packets. an example of alchemy bot :- i send alchemy packet 0x7150 and suppose to receive 0xb150 after ~ 4 sec but sometimes the bot w8 forever for 0xb150 without getting it .

second , high bandwidth consuming as example i create a clientless app just to login character to game server , it suppose to send the 0x2002 ping packet every ~5 sec
Size of Ethernet frame - 24 Bytes
Size of IPv4 Header (without any options) - 20 bytes
Size of TCP Header (without any options) - 20 Bytes
size of data = 6 bytes
so ping packet = 70 bytes but by monitoring network traffic by microsoft resource monitor , my app send more than 250 bytes per second .
here is the clientless code :-
Code:
class Clientless
    {
public Clientless(int _No)
        {
Current_Sec = Gate_sec;
            Current_Sock = Gate_socket;
        }
 private Security Gate_sec = new Security();
        private Security Agent_sec = new Security();

        private Security Current_Sec;
        //**********************************************
        private Socket Gate_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        private Socket Agent_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        private Socket Current_Sock;

private TransferBuffer buffer = new TransferBuffer(8192);
        private List<Packet> packets = new List<Packet>();
        Stopwatch ping = new Stopwatch();
 private bool firststart= true;
uint ID ;

public void Start(string ip , int port)
        {
            try
            {
                IPAddress IP = IPAddress.Parse(ip);
                Current_Sock.Connect(IP, port);
                Current_Sock.Blocking = false;
                Current_Sock.NoDelay = true;
               
                if (firststart)
                {
                    MainMethod();
                }
                
            }
 catch (Exception)
            {
        throw;
                
            }

           
        }
private void MainMethod()
        {
            while (!Exit)
            {

                if (Current_Sock.Poll(0, SelectMode.SelectRead))
                {

                    buffer.Size = Current_Sock.Receive(buffer.Buffer, 0, buffer.Buffer.Length, SocketFlags.None);
                    if (buffer.Size == 0)
                    {
                      
                        break;
                    }
                    Current_Sec.Recv(buffer);
                }
                List<Packet> packets = Current_Sec.TransferIncoming();
                if (packets != null)
                {
                    Receive(packets);
                    packets.Clear();
                }
                if (ping != null && ping.ElapsedMilliseconds >= 4999)
                {
                    Packet response = new Packet(0x2002, false, false);
                    Current_Sec.Send(response);
                    ping.Restart();
                }

                if (Current_Sock.Poll(0, SelectMode.SelectWrite))
                {
                    SendLogic();
                }


                Thread.Sleep(1);
            }
            dipose();
           
        }
and here is the 0xA102
Code:
else if (packet.Opcode == 0xA102)
                    {
                        byte result = packet.ReadUInt8();
                      
                        if (result == 0x01)
                        {
                           ID = packet.ReadUInt32();
                            string IP = packet.ReadAscii();
                            int port = packet.ReadUInt16();
                            Current_Sec = Agent_sec;
                            Current_Sock = Agent_socket;
                        
                            try
                            {
                                Gate_socket.Close();
                            }
                            catch (Exception)
                            {

                                throw;
                            }
                        firststart = false;
                        Start(IP, port);
                       
                            break;
                        }
Sorry for my bad english and Thanks om advance.
06/20/2016 10:02 AceSpace#2
Alright..

What is
Code:
private List<Packet> packets = new List<Packet>();
is declared for exactly? It has no use.


* Use a timer to send ping packet instead; Refer to this: [Only registered and activated users can see links. Click Here To Register...], code example:

Code:
<= Has to be in the packet handling =>

if (packet.Opcode == 0x2001)
{
aTimer.Enabled = true;
aTimer.Start();
Console.WriteLine("Ping Timer has been enabled!");
}

########################
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed+=new ElapsedEventHandler(PingEvent);
aTimer.Interval=5000;
aTimer.Enabled=false;

 // Specify what you want to happen when the Elapsed event is raised.
 private static void PingEvent(object source, ElapsedEventArgs e)
 {
     security.Send(new Packet(0x2002));
 }
* Remove the socket.poll related code, it's useless in such a thing.

If possible just re-code the whole thing, look at Supermike filter, you can use the base and adjust it a little to fit the clientless.

My A102 in case it could help even a little:

Code:
                        if (packet.Opcode == 0xA102)
                        {
                            byte flag = packet.ReadUInt8();
                            if (flag == 1)
                            {
                                uint m_sessionId = packet.ReadUInt32();
                                string m_serverIp = packet.ReadAscii();
                                ushort m_serverPort = packet.ReadUInt16();
                                GameContext game = new GameContext();
                                game.Connect(m_serverIp, m_serverPort, m_sessionId, m_username, m_password);
                            }
                        }
06/20/2016 18:13 mrnoad#3
Quote:
Originally Posted by Skipper* View Post
Code:
<= Has to be in the packet handling =>

if (packet.Opcode == 0x2001)
{
aTimer.Enabled = true;
aTimer.Start();
Console.WriteLine("Ping Timer has been enabled!");
}

########################
System.Timers.Timer aTimer = new System.Timers.Timer();
aTimer.Elapsed+=new ElapsedEventHandler(PingEvent);
aTimer.Interval=5000;
aTimer.Enabled=false;

 // Specify what you want to happen when the Elapsed event is raised.
 private static void PingEvent(object source, ElapsedEventArgs e)
 {
     security.Send(new Packet(0x2002));
 }
I dont think this code is right, 0x2001 opcode is a part of hankshake process, you get that package twice, one for GS one for AG.
06/20/2016 18:52 theking200051#4
thanks for fast response guys ,

Quote:
What is
Code:

private List<Packet> packets = new List<Packet>();

is declared for exactly? It has no use.
i used it in the Receive(packets) function :-

Code:
private void Receive(List<Packet> Packetlist)
foreach (Packet packet in Packetlist)
            {
            if (packet.Opcode==0x5000||packet.Opcode==0x9000)
                {
                   
                    continue;
                }
// ETC ......................................

            }
I dont think this code is right, 0x2001 opcode is a part of hankshake process, you get that package twice, one for GS one for AG.
Here is my 0x2001
Code:
#region 0x2001
                if (packet.Opcode == 0x2001)
                    {
                        string str= packet.ReadAscii();
                        if (str== "GatewayServer")
                        {
                            Packet response = new Packet(0x6100, true, false);
                            response.WriteUInt8(0x16);
                            response.WriteAscii("SR_Client");
                            response.WriteUInt32(Globals.version);
                            Current_Sec.Send(response);
                            ping.Start();
                        }
                        else
                        {
                         
                            Packet response = new Packet(0x6103, true, false);
                            response.WriteUInt32(ID);
                            response.WriteAscii(username);
                            response.WriteAscii(password);
                            response.WriteUInt8(0x16);
                            response.WriteUInt32(0);
                            response.WriteUInt16(0);
                            Current_Sec.Send(response);
                        }
                    }
                    #endregion
Quote:
Use a timer to send ping packet instead
i was using timer's but by little searching i found that timer execute on different Thread and some one advise me to avoid use multi threading if i can , so my question does my code rly need timers ?

Quote:
Remove the socket.poll related code, it's useless in such a thing.
ok i will remove it .
06/20/2016 19:18 mrnoad#5
Quote:
Originally Posted by theking200051 View Post
i was using timer's but by little searching i found that timer execute on different Thread and some one advise me to avoid use multi threading if i can , so my question does my code rly need timers ?


ok i will remove it .



No you dont need timers, you dont even need a StopWatch. This is from my working code;


Code:
    public class SilkroadClient
    {
       private static readonly Packet Ping = new Packet(0x2002);
       //....

       private void Connection_Loop()
        {
            long now, lastPing = now = Environment.TickCount;
            while (true)
            {

                //handle incoming packets


                now = Environment.TickCount;
                if (now - lastPing >= 5000)
                {
                    _security.Send(Ping);
                    lastPing = now;
                }

                //handle outgoing packets
                var tmp_buffers = _security.TransferOutgoing();
                //...
                Thread.Sleep(1);
            }
        }
        //...
    }
06/21/2016 08:11 mxii#6
Quote:
Originally Posted by theking200051 View Post
i send alchemy packet 0x7150 and suppose to receive 0xb150 after ~ 4 sec but sometimes the bot w8 forever for 0xb150 without getting it .
Sometimes SRO-Server didnt got the package or just didnt handled it..
Some timeouts occured on any side.. lags.. whatever!

So you will need a timeout-timer .. after x seconds (time should be editable!) without receiving the desired answer RESEND your fuse packet!
06/21/2016 16:17 theking200051#7
Quote:
Originally Posted by mxii View Post
Sometimes SRO-Server didnt got the package or just didnt handled it..
Some timeouts occured on any side.. lags.. whatever!

So you will need a timeout-timer .. after x seconds (time should be editable!) without receiving the desired answer RESEND your fuse packet!
thanks for replay ,so packet loss is something normal with any tcp connection?
and in my client side does the code is responsible too for the packet loss or just the modem & ISP & LAN & etc......
06/21/2016 16:23 mxii#8
Quote:
Originally Posted by theking200051 View Post
thanks for replay ,so packet loss is something normal with any tcp connection?
and in my client side does the code is responsible too for the packet loss or just the modem & ISP & LAN & etc......
Normally NOT!
TCP will repeat those "lost packets" but only a specific number of retries. (without your knowledge .. anywhere in the TCP-Stack!)

But in this case (already coded a alchemy tool, too) the server gets your packet but didnt handled it.
Cant tell you why..

So in all SRO-Coding cases i would highly recommend you to program all your stuff ASYNC!
And if there is no answer after a specific timeout (5-60 seconds) just retry it!

During some lags the server will not response to your alchemy packet.. to your open NPC packet.. walk packet or whatever! :)

gl!
06/21/2016 18:20 mrnoad#9
Quote:
Originally Posted by mxii View Post
Normally NOT!
TCP will repeat those "lost packets" but only a specific number of retries. (without your knowledge .. anywhere in the TCP-Stack!)
No actually TCP provides reliable, ordered, and error-checked delivery of data. If TPC fails to transmit a packet it will keep trying to deliver it. There is no "specific number of retries" If it keep failing to transmit the data you will end up with an IOException. But TCP is running at 4th(Transport) layer of 7 Layered OSI (Open Systems Interconnection) Model. Which means TCP only provides reliable, ordered, and error-checked delivery of data up to 4th layer.

5th, 6th Layer (usually the Operating System) or 7th layer which is application itself can still drop/corrupt or as in silkroad server's case discard packages.

More info on OSI Model and TCP
06/22/2016 17:31 theking200051#10
Quote:
Originally Posted by mrnoad View Post
No actually TCP provides reliable, ordered, and error-checked delivery of data. If TPC fails to transmit a packet it will keep trying to deliver it. There is no "specific number of retries" If it keep failing to transmit the data you will end up with an IOException. But TCP is running at 4th(Transport) layer of 7 Layered OSI (Open Systems Interconnection) Model. Which means TCP only provides reliable, ordered, and error-checked delivery of data up to 4th layer.

5th, 6th Layer (usually the Operating System) or 7th layer which is application itself can still drop/corrupt or as in silkroad server's case discard packages.

More info on OSI Model and TCP
so the packets is fully received error free and ordered up to the 4th layer but it drop or corrupt in the 5th or 6th or 7th layer's that handled by my app Socket right ?
so the question is the packet dropping caused 100 % by my code or something else , and how to avoid such behavior ?
06/22/2016 18:24 mrnoad#11
Quote:
Originally Posted by theking200051 View Post
so the packets is fully received error free and ordered up to the 4th layer but it drop or corrupt in the 5th or 6th or 7th layer's that handled by my app Socket right ?
so the question is the packet dropping caused 100 % by my code or something else , and how to avoid such behavior ?
The thing is if some packets dropped or corrupted at 5th(session) or 6th(presentation) layer that means its either the operating system or the hardware is faulty or firewall/antivirus is blocking your data. And unless you are a system/hardware programmer or system admin you dont deal with these kind of failures. Your job is about bugs as a software programmer.

Now about 7th(application) layer,

If your software discard some data it receives that's a choice. If your software without intention, skip/drops some data it receives or if it try to read a String while data contains an Integer, those are the bugs you should be worry.