Step by step Game server development (2) Complete login, chat, and step by step game
I know that many of you don't want to read this article in the blog Park, but this is the beginning of my series of articles. Please forgive me.
Multithreading, thread actuator (For details, refer to), socket communication (For details, refer)
My blog-related article test code, example, full svn address. Http://code.taobao.org/svn/flynetwork_csharp/trunk/Flynetwork/BlogTest)
Provides all source code functional blocks. I hope you can provide valuable comments.
Mo Qian completed the complete functions of the multi-threaded auxiliary class library (or bugs may need to be fixed or optimized later), and socket completed the tcp and http service listening functions, udp and websocket are still in perfect state.
If you want to complete this auxiliary class library with me, contact me to activate svn authorization.
Therefore, the source code is provided for free. You are welcome to join the project, regardless of the individual, enterprise, or commercial use. The only requirement is to keep the following words. Thank you for your cooperation ~!
1 /**
2 *
3 * @author stumbled programmer
4 * @Blog http://www.cnblogs.com/ty408/
5 * @mail 492794628@qq.com
6 * @phone 13882122019
7 *
8 */
Okay to start our topic
In the development of server projects, the most important thing is the login problem or the authorization problem.
We first create a console program
Reference to my two libraries Sz.Network.SocketPool, Sz.Network.ThreadPool are socket help library thread help library.
Sz means stumble. Please excuse me. I like this code-named "Falling Programmer"
We first create a message processor MessagePool
1 public class MessagePool: ISocketPool 2 {3 public void ActiveSocket (IOSession client) 4 {5} 6 7 public void CloseSocket (IOSession client) 8 {9 10} 11 12 public void ReadMessage (IOSession client, SocketMessage message) 13 {14 15 } 16 17 18 public void ActiveHttp (HttpClient client, string bind, Dictionary <string, string> parms) 19 {20 if (bind.Equals ("/ test /")) 21 {22 ThreadManager.GetInstance.AddTask (ServerManager.LoginThreadID , new LoginHttpHandler (client, parms)); 23} 24} 25 26 public void IOSessionException (IOSession client, Exception exception) 27 {28 Logger.Error ("Internal Error", exception); 29} 30 31 public void HttpException (HttpClient client, Exception exception) 32 {33 Logger.Error ("Internal Error", exception); 34} 35} View Code
Then add in the mian function
1 Sz.Network.SocketPool.ListenersBox.GetInstance.SetParams (new MessagePool (), typeof (MarshalEndian));
2 Sz.Network.SocketPool.ListenersBox.GetInstance.Start ("tcp: *: 9527", "http: // *: 8001 / test /");
In this way, we started the server monitoring, here is a brief introduction to why I created two monitoring of tcp and http?
This is because of experience and working relationship, because I am committed to game development, the server needs to create two tcp usually used for normal communication, and http listening login module, or some non-essential data exchange and third parties Login authorization needs to be enabled. Also because http is a short connection, there is no need to save the communication object, which reduces system consumption and TCP order of magnitude consumption.
If you do not understand, you can not join http monitoring. Look directly at the socket of tcp.
1 [2015-04-15 18: 12: 09: 899: Info] Start Listen Tcp Socket-> 0.0.0.0:9527
2 [2015-04-15 18: 12: 09: 906: Info] Start Listen Http Socket-> 0.0.0.0:8001/test/
Run the program and output.
The monitoring of tcp and http is turned on. Let's ignore the role of http for now.
We started to prepare for the development of the login module. Students all knew that the first thing to face when logging in was the problem of multiple simultaneous logins.
If lock is added to prevent multiple logins at the same time, then the server is bound to freeze. Factors such as low throughput. Then we consider adding this piece to a separate thread surprise handling. That is to help log in and log out, put in the same thread processing. It is possible to prevent multiple simultaneous logins without locking.
Next we need to take a thread from the Sz.Network.ThreadPool library
public static readonly long LoginThreadID = ThreadManager.GetInstance.GetThreadModel ("Login Processor");
Used to control login and logout
Create a CloseTcpHandler to handle the link port handler needs to inherit TaskBase under Sz.Network.ThreadPool
1 public class CloseTcpHandler: TaskBase 2 {3 4 IOSession client; 5 SocketMessage message; 6 7 public CloseTcpHandler (IOSession client) 8: base ("Tcp login processing") 9 {10 this.client = client; 11} 12 13 14 public override void TaskRun () 15 {16 17} 18} View Code
Then we modify the MessagePool class
public void ActiveSocket (IOSession client)
{
//client.SendMsg(new SocketMessage (1, System.Text.UTF8Encoding.Default.GetBytes ("Holle Server! client")));
}
public void CloseSocket (IOSession client)
{
ThreadManager.GetInstance.AddTask (ServerManager.LoginThreadID, new CloseTcpHandler (client));
}
In this way, the disconnection process is handed over to the ServerManager.LoginThreadID thread.
Let's create another LoginTcpHandler to handle the login program. Need to inherit TaskBase under Sz.Network.ThreadPool
View Code
Modify the MessagePool class to handle login messages
1 public void ReadMessage (IOSession client, SocketMessage message)
2 {
3 switch (message.MsgID)
4 {
5 case 1: // Login
6 case 2:
7 ThreadManager.GetInstance.AddTask (ServerManager.LoginThreadID, new LoginTcpHandler (client, message));
8 break;
9 default:
10 Logger.Error ("Unbound Message ID" + message.MsgID);
11 break;
12}
13}
Here is my custom message ID is 1 and 2 one is login and one is logout.
In this way, the login event is also handed over to the ServerManager.LoginThreadID thread
LoginTcpHandler taskrun method
1 public override void TaskRun () 2 {3 using (MemoryStream msReader = new MemoryStream (message.MsgBuffer)) 4 {5 using (System.IO.BinaryReader srReader = new BinaryReader (msReader, UTF8Encoding.Default)) 6 {7 using ( MemoryStream msWriter = new MemoryStream ()) 8 {9 using (System.IO.BinaryWriter srWriter = new BinaryWriter (msWriter, UTF8Encoding.Default)) 10 {11 switch (message.MsgID) 12 {13 case 1: // Login 14 string username = srReader.ReadString (); 15 if (! LoginManager.GetInstance.LoginNames.Contains (username)) 16 {17 LoginManager.GetInstance.LoginNames.Add (username); 18 if (! LoginManager.GetInstance.LoginIPs.ContainsKey (client .ID)) 19 {20 LoginManager.GetInstance.LoginIPs [client.ID] = username; 21 LoginManager.GetInstance.Sessions.Add (client); 22} 23 srWriter.Write (true); 24 srWriter.Write (username + " Log into the chat room "); 25 Logger.Info (client.RemoteEndPoint +" "+ username +" Login successful "); 26 SocketMessage sm = new SocketMessage (message.MsgID, msWriter.GetBuffer ()); 27 Serv erManager.GetInstance.Tell_All (sm); 28} 29 else 30 {31 srWriter.Write (false); 32 srWriter.Write ("Login name is duplicated, please change one"); 33 Logger.Info (client.RemoteEndPoint + "" + username + "Duplicate login name!"); 34 SocketMessage sm = new SocketMessage (message.MsgID, msWriter.GetBuffer ()); 35 client.SendMsg (sm); 36} 37 break; 38 case 2: // logout 39 40 break; 41 default: 42 43 break; 44} 45} 46} 47} 48} 49} View Code
CloseTcpHandler taskrun method
1 public override void TaskRun () 2 {3 if (LoginManager.GetInstance.LoginIPs.ContainsKey (client.ID)) 4 {5 string username = LoginManager.GetInstance.LoginIPs [client.ID]; 6 LoginManager.GetInstance.LoginIPs.Remove (client.ID); 7 LoginManager.GetInstance.LoginIPs.Remove (username); 8 LoginManager.GetInstance.Sessions.Remove (client); 9 using (MemoryStream msWriter = new MemoryStream ()) 10 {11 using (System.IO.BinaryWriter srWriter = new BinaryWriter (msWriter, UTF8Encoding.Default)) 12 {13 srWriter.Write (username + "quit chat room"); 14 SocketMessage sm = new SocketMessage (3, msWriter.GetBuffer ()); /// 3 means to send a message 15 ServerManager.GetInstance.Tell_All (sm); 16} 17 } 18} 19} View Code
Since the code is not complete here, if you are interested, you can download the source code to try
After starting the two clients, I saw that two links were created and logged in to the server.
Because chat and login are two different modules, in order to improve efficiency, we create a chat thread again
public static readonly long ChatThreadID = ThreadManager.GetInstance.GetThreadModel ("chat processor");
Next we add in the switch of MessagePool's ReadMessage method
case 3: // chat
ThreadManager.GetInstance.AddTask (ServerManager.ChatThreadID, new Chat.ChatHandler (client, message));
break;
In this way, we will process all the chat messages forwarded by ServerManager.ChatThreadID. Even if it is stuck, it will not affect the client's chat sending message and the new client's request to log in.
Here we can also consider grouping and chat grouping functions. For example, private chat, group chat and other group threads are executed.
Creating a ChatHandler needs to inherit TaskBase under Sz.Network.ThreadPool
1 public class ChatHandler: TaskBase 2 {3 IOSession client; 4 5 SocketMessage message; 6 7 8 public ChatHandler (IOSession client, SocketMessage message) 9: base ("chat processing task") 10 {11 this.client = client; 12 this .message = message; 13} 14 15 16 public override void TaskRun () 17 {18 using (MemoryStream msWriter = new MemoryStream ()) 19 {20 using (System.IO.BinaryWriter srWriter = new BinaryWriter (msWriter, UTF8Encoding.Default) ) 21 {22 // Build input buffer 23 // Verify login status 24 if (LoginManager.GetInstance.LoginIPs.ContainsKey (client.ID)) 25 {26 string username = LoginManager.GetInstance.LoginIPs [client.ID]; 27 using (MemoryStream msReader = new MemoryStream (message.MsgBuffer)) 28 {29 using (System.IO.BinaryReader srReader = new BinaryReader (msReader, UTF8Encoding.Default)) 30 {31 string msg = srReader.ReadString (); 32 msg = client .RemoteEndPoint + "" + username + "" + msg; 33 Logger.Info (msg); 34 srWriter.Write (msg); 35 SocketMessage sm = new SocketMessage (mess age.MsgID, msWriter.GetBuffer ()); 36 ServerManager.GetInstance.Tell_All (sm); 37} 38} 39} 40 else 41 {42 srWriter.Write ("Not yet logged in"); 43 SocketMessage sm = new SocketMessage (message .MsgID, msWriter.GetBuffer ()); 44 client.SendMsg (sm); 45} 46} 47} 48} 49} View Code
Try a message
Here is a simple chat server. After logging in to chat, the client is a wpf program. There is no source code and process posted. If you need or want to study, please download the svn source code and check the situation yourself.