Unity 簡易聊天室(基於TCP)(1)
為了準備畢業設計,學習了伺服器與客戶端之間傳輸的一些簡單的知識,並跟著網路上的教程製作了一個簡易的Unity聊天室
伺服器:用C# .Net Framework寫的
結構分為:main(主函式)、Server類(用於伺服器的開啟和接收客戶端連線)、Client類(接收訊息和傳送訊息)、Message類(用於訊息的解析和包裝)
main:
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;
}
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;
}
}