• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook pagefor updates, or we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.)

[C#]Few Socket Problems

(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Okay so here is my simple&small test server using asynchronious sockets.

So far it can do following:
- Handle multiple clients
- Receive messages from clients
- Send message to all clients or specific client

But here is problem. When client closes connection it starts to send bunch of null packets. How can I close socket and remove client from the list once he disconnects?

I have a check for packet lenght
Code:
                if (bytesReceived > 0)
                {
                    Console.WriteLine("[" + clientIP + "](" + bytesReceived.ToString() + "): " + BitConverter.ToString(clientBuffer, 0, bytesReceived));
                }

And I tried adding else statement which would mean that server received null/empty packet and that would mean client for closed connection.
Now how would I properly close socket/connection with that client, cause he still sends bunch of empty packets to server?

Main.cs:
ServerSocket.cs
Client.cs
 
Experienced Elementalist
Joined
Apr 12, 2009
Messages
241
Reaction score
32
Code:
if (BytesReceived==0)
{
   Client is Disconnected... you can clean up now, nothing more can be sent or received
   Do not read more data
}
else
{
   Process whatever you got, and make the call to read more data
}


---------- Post added at 05:32 PM ---------- Previous post was at 05:29 PM ----------

For clarity, what i'm saying is... don't call BeginReceive again, if bytesReceived == 0

Returning bytesreceived = 0 is how sockets tell you that they're now disconnected.

If you call .Close or .Disconnect or .Dispose or whatever on a socket, the outstanding read will finish right away and you'll get bytesreceived = 0

So, you can handle all your disconnect handling inside the "dataArrival" function after you call EndReceive and get bytesreceived==0

Which also means, if you need to close a socket, you can just call .Close and forget about it - and your dataArrival function will take care of the cleanup.
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Code:
if (BytesReceived==0)
{
   Client is Disconnected... you can clean up now, nothing more can be sent or received
   Do not read more data
}
else
{
   Process whatever you got, and make the call to read more data
}


---------- Post added at 05:32 PM ---------- Previous post was at 05:29 PM ----------

For clarity, what i'm saying is... don't call BeginReceive again, if bytesReceived == 0

Returning bytesreceived = 0 is how sockets tell you that they're now disconnected.

If you call .Close or .Disconnect or .Dispose or whatever on a socket, the outstanding read will finish right away and you'll get bytesreceived = 0

So, you can handle all your disconnect handling inside the "dataArrival" function after you call EndReceive and get bytesreceived==0

Which also means, if you need to close a socket, you can just call .Close and forget about it - and your dataArrival function will take care of the cleanup.

Ohhh :$:

That's where it got messed up. Good eye there:thumbup:

But thank you, gonna test now :thumbup:

---------- Post added at 06:06 PM ---------- Previous post was at 06:02 PM ----------

Just checked and yes it works like charm now =)

As you noted, I had BeginReceive even if bytesReceived was 0 and it was causing error.

Thank you much :)

For now gonna continue editing :p
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Okay another question.

Login server has three or four OP codes. Should I just go for switch or delegates?

Is method explained below acceptable?
Create a dictionary with OP code => function
Then when packet arrives just call
functionsDictionary["opcode"]();
 
Experienced Elementalist
Joined
Apr 12, 2009
Messages
241
Reaction score
32
for 3 or 4 opcodes, use switch()

The overhead of a dictionary and the added complexity dont make it worth it. Few dozen? Hundreds? maybe go to the delegates.

And if you do go to delegates.. if your opcodes are integers, like 0-100 (as opposed to random numbers)... Consider just doing a range check, and holding your delegates in a simple array, instead of in a dictionary
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
That's the thing I am unsure about, yet.

The OP codes are are short int.
Tho they go as following
Code:
recv_packets = {
    'account': {
        0x0201: ['auth', 'AccountAuth'],
        0x0203: ['request_world_list', 'RequestWorldList'],
        0x0205: ['select_world', 'SelectWorld'],
    }

But I think I would just loop thru whole array to check.

P.S. I am asking for future development (game server)
 
YEy i has custom title^_^
Joined
Sep 29, 2006
Messages
452
Reaction score
67
Well easiest way would be just enum for packetids, convert to ids from hex to decimal using windows calculator, create switch for the packet op that invokes event/sends required packet.
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Ya thats what I did for login server. It's weird that game developers went that way.

One more question so far.
Username field has 17 bytes reserved for 17 characters.
But if username length is less than 17 it creates bunch of gebrish after login.
Example
Code:
6A 6D 32 6D 65 00 72 00 7A 76 72 00 98 FD 18 00 A0

Only first 5 bytes have username the rest is just random I guess.
How would I read username only from that?
 
Moderator
Staff member
Moderator
Joined
Feb 22, 2008
Messages
2,404
Reaction score
724
do not use a switch if you are building an emulator. Use a combination of Custom Attributes + Dictionary, and do something like I made:

[Packet(OPCODE HERE,DESCRIPTION)]
func goes here
[Packet(ANOTHER ONE,DESCRIPTION)]
another one

Then, when your program starts, load them into a dictionar, with the OPcode and the MethodInfo, so when a packet is received you can get the MethodInfo passing the opcode, and further use the Invoke function to call it. :D
 
Joined
Jan 27, 2007
Messages
1,201
Reaction score
1,067
do not use a switch if you are building an emulator. Use a combination of Custom Attributes + Dictionary, and do something like I made:

[Packet(OPCODE HERE,DESCRIPTION)]
func goes here
[Packet(ANOTHER ONE,DESCRIPTION)]
another one

Then, when your program starts, load them into a dictionar, with the OPcode and the MethodInfo, so when a packet is received you can get the MethodInfo passing the opcode, and further use the Invoke function to call it. :D


That's a great idea, sorry to hijack the thread lol
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
do not use a switch if you are building an emulator. Use a combination of Custom Attributes + Dictionary, and do something like I made:

[Packet(OPCODE HERE,DESCRIPTION)]
func goes here
[Packet(ANOTHER ONE,DESCRIPTION)]
another one

Then, when your program starts, load them into a dictionar, with the OPcode and the MethodInfo, so when a packet is received you can get the MethodInfo passing the opcode, and further use the Invoke function to call it. :D

Yes I am going to do something like this for game server. Login server has only 3 OP codes only but still might change in future.

Also here is answer to my previous questions:
Code:
        public string ReadString(short length)
        {
            string tempBuff = BitConverter.ToString(packetData, index, length).Split("00".ToCharArray())[0].Replace("-", "");
            byte[] stringBytes = new byte[tempBuff.Length / 2];
            for (int i = 0; i < stringBytes.Length; i++)
            {
                stringBytes[i] = Convert.ToByte(tempBuff.Substring(i * 2, 2), 16);
            }
            index += length;
            return Encoding.ASCII.GetString(stringBytes);
        }

It's not the best solution but I might think of something other in future.
 
Experienced Elementalist
Joined
Apr 12, 2009
Messages
241
Reaction score
32
Ya thats what I did for login server. It's weird that game developers went that way.

One more question so far.
Username field has 17 bytes reserved for 17 characters.
But if username length is less than 17 it creates bunch of gebrish after login.
Example
Code:
6A 6D 32 6D 65 00 72 00 7A 76 72 00 98 FD 18 00 A0

Only first 5 bytes have username the rest is just random I guess.
How would I read username only from that?


They aren't all random. It's null terminated. You can stop reading after the first "00" byte.

If it's C# and allowing unsafe code, you can pass in a char* to the string constructor to make it easy. I think it takes byte* too
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
They aren't all random. It's null terminated. You can stop reading after the first "00" byte.

If it's C# and allowing unsafe code, you can pass in a char* to the string constructor to make it easy. I think it takes byte* too

Ya thats kinda hard way and im not really good with pointers in C# yet.
Look at my message above. I made it work but in kinda stupid way.
Converted 17bytes to string, split into array using "00" then blah. Just see the code. :lol:
 
Experienced Elementalist
Joined
Apr 12, 2009
Messages
241
Reaction score
32
or if you've got a 17 byte array, you could parse it just like

byte[] usernamebuffer = new byte[17];
// fill up the usernamebuffer;

string username = UTF8Encoding.UTF8.GetString(usernamebuffer).Split((char)0)[0];

...or, if the username buffer is just somewhere inside a larger buffer, like position 1234 out of a byte[2048] array...

string username = UTF8Encoding.UTF8.GetString(buffer, 1234, 17).Split((char)0)[0];

---------- Post added at 07:31 PM ---------- Previous post was at 07:31 PM ----------

doh, didn't read above closely enough :p whatever :)
 
(oO (||||) (||||) Oo)
Loyal Member
Joined
Aug 6, 2009
Messages
2,132
Reaction score
429
Okay so I got to the game server point and now have to figure out this thing for multiple OP codes.

Consider code provided below:


Where would be good place to declare dictionary with methods and where would it be sufficient to write methods?

I assume GameClient.cs since its where functions will be called.
 
YEy i has custom title^_^
Joined
Sep 29, 2006
Messages
452
Reaction score
67
Nice, this is kinda off topic but whats up with all the florensia emus. i think theres like 3 new ones in development currently : D

And yes you should add it inside the client as you get the packets there but the event should be inside server itself where you can access multiple stuff like clients, monsters and other important data(dunno tho if this is good but thats how i do it)
 
Last edited:
Back
Top