it's a daunting task to design, develop and implement a robust Managed Game Network Library, can be totally mind boggling and may cause loss of hair :-D, but when you really need something specific to suits your different needs or if you think you can do better implementation than using the tools that are already available in the wild and least but not last curiosity and for educational purposes alone, you force yourself to code from scratch or at least you try to roll your own implementation.
Of course, I know the notion of 'reinventing the wheel' and I'm also aware that there are lots of great network library project already been created out there and ready to use, but most of them I've seen so far, only offers a single network implementation or using only a one specific .NET network technology features and you feel like your still working at the socket level. This is one of the main reason I wanted to try and create my own network library to find out which network technology and socket processing scheme will be best suited to different types of multi-user applications. What I really wanted to do, is to develop a network library which is interchangeable with ease of use and to be able to test other networking technology and different kinds of socket processing scheme in the simplest form.
A configurable network computing implementation seems to be a good idea to start designing a network library, and here's my implementation on how to configure the server side that uses different kinds of enumerated network technology and socket processing scheme. The port is the only one that needs to be set manually, other implementations are all enumerated to lessen the hard-coding hassle, whether I wanted to use IPv4 or IPv6, UDP or TCP, .NetClients or Raw Socket Berkely, IPv4-Broadcasting or IPv4/IPv6-Multicasting and other network settings. The most interesting part in this project so far, it can choose what type of socket processing scheme for a specific application requirements or game type by selecting socket cores processing mode to work Synchronously, Asynchronously, IOCP model, OVERLAPPED I/O model, Per player thread, Per player asynchronous mode or a single thread for Socket selecting or Polling mode with or without Asynchronous IOCP or OVERLAPPED I/O events.
Before starting listening for connecting clients, first It needs to set the Network Setting parameters when creating a new Lobby Server instance and sets the Server configuration parameters when starting a lobby service, that's it and the server is ready to start listening to any incoming client connection.
The code snippet below used the following using directives.
Using ZNC = ZGDK.Net.Core;
Using ZNE = ZGDK.Net.Enum;
Using ZNH = ZGDK.Net.Helper;
Network setting codes implementation:
//--> Creating lobby server network settings.
//
ZNC.SNetSetting m_NetSetting = new ZNC.SNetSetting();
//--> Frequencies and latency in Ms.
// m_NetSetting.Frequencies.SendingFrequency = 200; m_NetSetting.Frequencies.ResendFrequency = 400; m_NetSetting.Frequencies.KeepAliveFrequency = 3000; //--> MpTU Maximum payload Transmission Unit
// m_NetSetting.MpTU.Small = 1400; // 7KBps-for- 56kbps m_NetSetting.MpTU.Medium = 2800; // 14KBps-for-128kbps m_NetSetting.MpTU.Larger = 5600; // 28KBps-for-256kbps and above //--> Intervals in Ms
// m_NetSetting.Intervals.SelectPollReadWait = 32; m_NetSetting.Intervals.SyncronouseSendTimeOut = 5000; m_NetSetting.Intervals.MaxPlayerIdleTime = 15000; m_NetSetting.Intervals.PlayerRemovalCountDown = 4000; //--> Initial table capacity
// m_NetSetting.Thresholds.MaxNumberOfGames = 1; m_NetSetting.Thresholds.ReceivedQueTblSize = 16; m_NetSetting.Thresholds.MessageQueTblSize = 32; m_NetSetting.Thresholds.SendQueTblSize = 64; //--> Max fails alert before disconnecting client
// m_NetSetting.FailsAlerts.MaxPlayerResendFailsCount = 16; m_NetSetting.FailsAlerts.MaxPlayerSendFailsCount = 12; m_NetSetting.FailsAlerts.MaxPlayerReceiveFailsCount = 24; m_NetSetting.FailsAlerts.MaxPlayerGarbageFailsCount = 32; //--> Logger Debugger
// m_NetSetting.LoggerConsole.Enable = true; m_NetSetting.LoggerConsole.EchoEnable = true; m_NetSetting.LoggerConsole.ShowReceivePacketInfo = false; m_NetSetting.LoggerConsole.ShowSendPacketInfo = false; m_NetSetting.LoggerConsole.ShowPlayerTrafficFlow = false;
Server configuration codes implementation:
//--> Preparing server configuration
//
ZNC.ServerConfig m_ServerConfig = new ZNC.ServerConfig();
// m_ServerConfig.ApplicationName = "Super Game Server"; m_ServerConfig.LobbyName = "Dexter Z Channel"; // m_ServerConfig.EnableIPv6 = false; m_ServerConfig.Connection = ZNE.ConnectionType.Internet; m_ServerConfig.Protocol = ZNE.Protocol.UDP; m_ServerConfig.SocketType = ZNE.SocketType.Berkely; m_ServerConfig.IPAddress = ZNH.GetMachineLocalIP(ZNE.IPVersion.IPv4); m_ServerConfig.ServerPort = 60055; // m_ServerConfig.CasterPort = 60057; m_ServerConfig.CasterType = ZNE.CasterType.Multicast; m_ServerConfig.CasterGroup = ZNE.CasterGroup.IPv4_WORKGROUP; // m_ServerConfig.AcceptorMode = ZNE.SAcceptorMode.UsingUDP; m_ServerConfig.ReceiverMode = ZNE.SReceiverMode.UdpThreadOnly; m_ServerConfig.SenderMode = ZNE.SenderMode.AsyncIOCP;
Finally server creation codes using the above Network settings and Server settings :
//--> Lobby server creation with preferred network settings. // ZNC.LobbyServer _Server = new ZNC.LobbyServer( m_NetSetting );
//--> Start lobby server service with prefered server settings.
//
_Server.StartLobbyService( m_ServerConfig );
//--> Start accepting new client connection.
//
_Server.AcceptorMngr.StartAccepting();
SERVER CONFIGURATION :
Application Name
Why I need to specify the name of the application in server configuration? though, this is irrelevant when using connection type over the internet, but working on local area network the client needs to specify the game or application name when searching for available games accross the local subnet.
m_ServerConfig.ApplicationName = "Super Gsme Server";
The client should retrieves all available machine's hosting "Super Game Server" game as an example on the local sub-net. I will ellaborate more on this later on when I tackle my implementation for Boadcasting and Multicasting messages accross the local sub-net and how game sessions can be automatically discover.
ZNC.LocalGames[] m_LocalGames = ZNH.SearchLocalGames( "Super Game Server",1000);
Lobby name
Whether hosting a game over the internet or on the local sub-net, assigning a lobby name is one way to identify the host machine, for instance multiple machine created a game session, the client looking for available games, should retrieve all created game sessions along with lobby name for host distinction, though, from using over the internet I intend to use Lobby name as a Server channel description hosting the same game over the internet using different server machine.
m_ServerConfig.LobbyName = "Dexter Z Channel";
Internet Protocol Version
I may say socket works through a network layers like the Internet Protocol (IP), IP is the main core that provides to transport data in various network environment such as local area network (LAN) and wide area network (WAN) particularly the internet. The two well known network layers Internet Protocol version are IPv4 and IPv6. I will not tackle here what ever happened to the IPv5, but the next generation Internet Protocol is IPv6 and it's the latest version of the Internet Protocol. I'm supporting both IPv4 and IPv6 on my network library, I believe it's a good decision to add a support to IPv6 rather than to deal with it later on, the functionality of my network library works on both Internet Protocol version 4 and 6.
m_ServerConfig.EnableIPv6 = false; // Using IPv4 only
Network connection type
The more, the merrier! playing games on LAN (Local area network) is definitely cool and imagine how much fun it would be to play the same game you are playing on LAN that can also be played by others over the internet. Though, connection type should only be configured on the client end, the server end in my implementation also need to know what connection type you are intend to use for internal setting.
m_ServerConfig.Connection = ZNE.ConnectionType.Internet;
LAN
Network Protocol
The two well known Network Protocol in computer networking are Transport Connection Protocol (TCP) and the Unrealiable Datagram Protocol... Oppps! my bad, the correct one is User Datagram Protocol (UDP). TCP and UPD are the dominant protocols lurking over the internet and to most networking environments. TCP and UDP should be supported in my implementation, although some may say that if you can implement a robust reliable UDP messaging scheme there's no need for a TCP implementation, because it will just overkill the design, but never the less I'm still supporting the use of TCP protocol. The .NET framework Remoting features in my design plan will be drop due to my own implementation on sending and updating of on object remotely.
m_ServerConfig.Protocol = ZNE.Protocol.UDP;
TCP
Socket type
The .NET framework offers UdpClient, TcpClient, TcpListener and Raw Socket Berkely for it's socket interface, but which one is better and more effecient? well, the best thing to do is to run the the application and choose which socket type works best for your application. Luckily, both socket interface are supported in my implementation.
m_ServerConfig.SocketType = ZNE.SocketType.Berkely;
NetClient
IP Address
Exchanging messages needs to agree with the same protocol, whether you are using a TCP or UDP, each message has to contain the address of it's destination just like a telegrams. Shame on me, if I still need to manually hardcoded the machine's local IP address everytime I transfer and use different station to run the server application, creating a simple method that returns machine's local IP address is very handy.
m_ServerConfig.IPAddress = ZNH.GetMachineLocalIP( ZNE.IPVerion.IPv4 );
Listener port
How many ports should I need to open on the server end? In my implementation whenever the announcer is enable which will only works on the local subnet but not over the internet, a new UDP socket and port will be open and created whether the core socket is using TCP or UDP protocol. The core socket using UDP or TCP, a single server listener port is only needed.
m_ServerConfig.ListernerPort = 60055;
Broadcasting and Multicasting
The option for sending messages to all other machines across the local sub-net or group of host at the same time should not be taken for granted, implementing broadcasting or multicasting features are also included in my implementation, which can surely save a lot of bandwidht, more details on this when I discuss about the role of caster manager and it's functionality in my implementation. The following are the options to configure broadcast messaging.
m_ServerConfig.CasterPort = 60057;
m_ServerConfig.CasterType = ZNE.CasterType.Multicast;
Broadcast;
m_ServerConfig.CasterGroup = ZNE.CasterGroup.IPv4_WORKGROUP;
Here's the complete enumeration for caster group ( ZNE.CasterGroup ) address :
IPv4_WORKGROUP,IPv4_ROUTER,
IPv4_OSPF, IPv4_OSPF_ROUTER, IPv4_RIPV2,
IPv4_EIGRP,IPv4_VRRP,IPv4_IGMP,
IPv6_WORKGROUPSEGMENT, IPv6_WORKGROUPSITE,
IPv6_ROUTER, IPv6_DHCP, IPv6_NIS
Socket processing scheme
Socket processing scheme is the most important aspect in network implementation IMO. I will tackle this part on my next post including some diagram for each processing scheme that can that can be acquire by just changing the socket core processing mode.
Asynchronous;
UsingUDP;
m_ServerConfig.ReceiverMode = ZNE.SReceiverMode.TcpThreadPollOnly;
TcpThreadPollIOCP
TcpThreadPollOVERLAPPED
TcpThreadSelectOnly
TcpThreadSelectIOCP
TcpThreadSelectOVERLAPPED
TcpThreadPerPlayer
TcpAsyncIOCPPerPlayer
TcpAsyncOVERLAPPEDPerPlayer
UdpThreadOnly
UdpThreadIOCP
UdpThreadOVERLAPPED
UdpAsyncIOCP
UdpAsyncOVERLLAPED
m_ServerConfig.SenderMode = ZNE.SenderMode.Synchronous;
AsyncIOCP
AsyncOVERLAPPED
But of course by just leaving the default values setting of Network and Server configuration without tweaking some parameters, a lobby server creation can be done in just 5 lines of codes.
//--> 1. Creating lobby server network settings with default values.
//
ZNC.SNetSetting m_NetSetting = new ZNC.SNetSetting();
m_NetSetting.SetDefault();
//--> 2. Creating server configuration with default values.
//
ZNC.ServerConfig m_ServerConfig = new ZNC.ServerConfig();
m_ServerConfig.SetDefault();
//--> 3. Lobby server creation with preferred network settings. // ZNC.LobbyServer _Server = new ZNC.LobbyServer( m_NetSetting );
//--> 4. Start lobby server service with prefered server settings. // _Server.StartLobbyService( m_ServerConfig );//--> 5. Start accepting new client connection. // _Server.AcceptorMngr.StartAccepting();
Basically this is just the tip of the iceberg from the whole network implementation and I can't wait to discuss the full functionality on the server side like sender frequency tuning, error handling, buffer overrun monitoring and the following lobby server managers:
*LobbyServer.AcceptorMngr
*LobbyServer.AdapterMngr
*LobbyServer.SenderMngr
*LobbyServer.ReceiverMngr
*LobbyServer.MessageMngr
*LobbyServer.CasterMngr
*LobbyServer.LobbyMngr
*LobbyServer.GameMngr
*LobbyServer.SessionMngr