Socket 客户端与服务器的架构初步构想

先分享一篇不错的socket的文章

Linux Socket过程详细解释(包括三次握手建立连接,四次握手断开连接)

近期一直在考虑如何做一个多人同时在线的游戏,对于服务器这一块肯定是需要用到socket的,于是先将游戏想的简单一点,比如,这个多人在线的游戏是一个打麻将的,那么只需要最多先支持4个人同时在线就行了,那么服务器要做的事情有:

  • 跟多台客户端保持着长连接(多人同时在线)
  • 将一些信息同时发给每个客户端(洗牌)
  • 将某个客户端发送给服务器的消息传递给其它的客户端(出牌)

那么我先需要的是一个支持多人连接的socket服务器,然后我要将每个新增的连接存起来,并且能够在任意情况下对这个连接的客户端发送消息,服务器代码如下:

服务端:C#控制台程序



using System;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.Text;

namespace socket
{
	class MainClass
	{
		static byte[] result = new byte[1024];//接收数据
	    static int myProt = 9527;   //端口  
		static string socketip = "127.0.0.1";
		static Socket serverSocket; //socket对象
		static object[] collectArray = new object[4];//连接对象池
		public static void Main(string[] args)
		{

			//服务器IP地址  
			IPAddress ip = IPAddress.Parse(socketip);
			//创建服务端socket对象
			serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
			//绑定IP地址:端口 
			serverSocket.Bind(new IPEndPoint(ip, myProt));   
			//设定最多连接
			serverSocket.Listen(collectArray.Length);    
			Console.WriteLine("启动监听【{0}】成功", serverSocket.LocalEndPoint.ToString());
			//监听线程  
			Thread myThread = new Thread(ListenClientConnect);
			//启动监听
			myThread.Start();
		}

		///   
		/// 监听客户端连接  
		///   
		private static void ListenClientConnect()
		{
			while (true)
			{
				Socket clientSocket = serverSocket.Accept();
				string say = "Server Say Hello";
				clientSocket.Send(Encoding.Default.GetBytes(say),say.Length,0);
				Thread receiveThread = new Thread(ReceiveMessage);


				//创建连接对象,并加入collect池中
				for (int i = 0; i < collectArray.Length; i++)
				{
					if (collectArray[i] == null)
					{
						CollectObject collect = new CollectObject();
						collect.t_socket = clientSocket;
						collect.t_index = i;
						collect.t_userid = "tid_" + i;
						collectArray[i] = collect;
						receiveThread.Start(i);
						Console.WriteLine("新增链接【{0}】", collect.t_userid);
						break;
					}
				}


			}
		}

		///   
		/// 接收消息  
		///   
		///   
		private static void ReceiveMessage(object index)
		{
			CollectObject Mycollect = collectArray[Convert.ToInt32(index)] as CollectObject;
			while (true)
			{
				try
				{
					//通过clientSocket接收数据  
					int receiveNumber = Mycollect.t_socket.Receive(result, result.Length, 0);
					byte[] bt = Encoding.Convert(Encoding.UTF8, Encoding.Unicode, result, 0, receiveNumber);
					string content = Encoding.Unicode.GetString(bt);
					Console.WriteLine("接收消息:【{0}】",content);
					sendData(Mycollect.t_socket, content);
				}
				catch
				{
					//关闭连接
					Mycollect.t_socket.Close();

					Console.WriteLine("链接【{0}】已断开",Mycollect.t_userid);
					//从连接池中删除
					collectArray[Convert.ToInt32(index)] = null;
					break;
				}
			}
		}

		/// 
		/// 发送数据
		/// 
		/// 客服端socket对象
		/// 消息内容
		private static void sendData(Socket clientSocket,string message)
		{
			//发送消息给服务器
			string responStr = "";
			if (message == "a")
			{
				responStr = "尼玛";
			}
			else if (message == "b")
			{
				responStr = "这是密码呀";
			}
			else if (message == "c")
			{
				responStr = "为所欲为";
			}
			else
			{
				responStr = "别以为你发了个("+message+")我就要回复你,滚粗~~~";
			}
			byte[] responBTs = Encoding.Default.GetBytes(responStr);
			clientSocket.Send(responBTs, responBTs.Length, 0);
			Console.WriteLine("发送消息:【{0}】", responStr);
		}

	}




	/// 
	/// 链接对象
	/// 
	class CollectObject
	{
		/// 
		/// socket对象
		/// 
		public Socket t_socket { get; set;}
		/// 
		/// 连接池下标
		/// 
		public int t_index { get; set; }
		/// 
		/// 用户ID
		/// 
		public string t_userid { get; set; }
	}
}

这个简单的服务器最多支持4个客户端同时连接,使用一个固定长度的全局数组和自定义了一个连接对象的类,将每一个新增的连接创建为一个连接对象保存在数组中,然后任意一个客户端发送消息触发某些操作时,或者服务器需要广播消息,都可以通过这个数组将将消息传递给其它客户端,这里的每一个连接都有一个单独线程,安全性有待下一步将客户端做好之后再来实验一下。

Next 使用cocoa2d来开发一个麻将游戏

END