為了准備畢業設計,學習了服務器與客戶端之間傳輸的一些簡單的知識,並跟着網絡上的教程制作了一個簡易的Unity聊天室
服務器:用C# .Net Framework寫的
結構分為:main(主函數)、Server類(用於服務器的開啟和接收客戶端連接)、Client類(接收消息和發送消息)、Message類(用於消息的解析和包裝)
main:
class Program { static void Main(string[] args) { string ip = "127.0.0.1";//這個ip地址表示本機 int port = 6688; //測試用的端口號,應該可以自己隨便寫吧 Server server = new Server(ip, port); server.Start(); Console.ReadKey(); } }
Server:
public class Server { private Socket serverSocket = null; private List<Client> clientList = new List<Client>(); private Socket clientSocket = null; public Server() { } public Server(string ip,int port) { //創建socket,然后綁定ip地址和端口號 //傳輸類型是流,使用的協議是Tcp serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); EndPoint point = new IPEndPoint(IPAddress.Parse(ip), port); serverSocket.Bind(point); } public void Start() { serverSocket.Listen(0); //開始監聽 0表示等待連接隊列的最大數 Console.WriteLine("開始監聽"); Console.WriteLine("等待客戶端連接"); serverSocket.BeginAccept(AcceptCallBack, null); //等待客戶端連接,AcceptCallBack是回調,第三個參數目前還沒用過,沒去了解作用 TODO } private void AcceptCallBack(IAsyncResult ar) { clientSocket = serverSocket.EndAccept(ar); Console.WriteLine("一個客戶端連接"); Client client = new Client(clientSocket,this); //當客戶端連接上后,用Client類處理消息的接收與發送 clientList.Add(client); client.Start(); serverSocket.BeginAccept(AcceptCallBack, null); //服務器繼續等待其他客戶端連接 } public void Broadcast(string message) //廣播消息 { foreach(Client client in clientList) { client.SendMessage(message); } } }
Client:
public class Client { private Socket clientSocket; private Server server; private Message msg = new Message(); public Client() { } public Client(Socket clientSocket,Server server) { this.clientSocket = clientSocket; this.server = server; } public void Start() { //判斷客戶端是否被關閉 if (clientSocket.Connected == false || clientSocket.Poll(10, SelectMode.SelectRead)) { clientSocket.Close(); return; } //等待從客戶端的消息的接收 clientSocket.BeginReceive(msg.data, 0, msg.data.Length, SocketFlags.None, ReceiveCallBack, null); } private void ReceiveCallBack(IAsyncResult ar) { try { //需要用try catch 捕捉異常,不然出現異常服務器會終止 //判斷客戶端是否被關閉 if (clientSocket.Connected==false || clientSocket.Poll(10,SelectMode.SelectRead)) { clientSocket.Close(); return; } int len = clientSocket.EndReceive(ar);//返回的len表示接收的數據長度 if (len == 0)//客戶端被關閉了 服務端會接收到0字節的消息 { clientSocket.Close(); return; } msg.Read(len, OnProessMassage);//Message類解析消息 //Console.WriteLine("receive:" + message); clientSocket.BeginReceive(msg.data, 0, msg.data.Length, SocketFlags.None, ReceiveCallBack, null); } catch (Exception e) { Console.WriteLine("ReceiveCallBack:" + e); } } private void OnProessMassage(string msg) { server.Broadcast(msg);//通過服務器廣播消息 } public void SendMessage(string message) { //判斷客戶端是否被關閉 發送的時候客戶端也可能被關閉 if (clientSocket.Connected == false || clientSocket.Poll(10, SelectMode.SelectRead)) { clientSocket.Close(); return; } //MethodInfo mi = msg.GetType().GetMethod("Pack"); clientSocket.Send(msg.Pack(message));//發送消息給客戶端 //Console.WriteLine("send:"+message); } }
Message:
//這里只是簡單的處理消息;解析:從byte[] ->string;發送:string->byte[]
class Message { public byte[] data = new byte[1024]; public void Read(int len,Action<string>OnProessMessage) { string message = Encoding.UTF8.GetString(data, 0, len); OnProessMessage(message); Array.Clear(data, 0, len); } public byte[] Pack(string msg) { byte[] dataBytes = Encoding.UTF8.GetBytes(msg); return dataBytes; } }