上面咱們建立了tcp的客戶端和服務端,可是隻能進行消息的一次收發。此次咱們作一個unity的簡易聊天室,使用了線程,能夠使用多個客戶端鏈接服務器,而且一個客戶端給服務器發消息後,服務器會將消息羣發給全部客戶端。服務器
服務器端分爲Program和Client,在Program中進行Ip和端口的綁定並與客戶端創建鏈接,消息的接收和發送放在Client中、socket
服務端之Program:tcp
using System; using System.Collections.Generic; using System.Linq; using System.Net; using System.Net.Sockets; using System.Net.WebSockets; using System.Text; using System.Threading.Tasks; namespace _022_聊天室_socket_tcp服務器端 { class Program { static List<Client> clientList = new List<Client>(); // 廣播消息 public static void BroadcastMessage(string message) { var notConnectedList = new List<Client>(); foreach (var client in clientList) { if (client.Connected) client.SendMessage(message); else { notConnectedList.Add(client); } } foreach (var temp in notConnectedList) { clientList.Remove(temp); } } static void Main(string[] args) { Socket tcpServer = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.101"),7788)); tcpServer.Listen(100); Console.WriteLine("server running..."); while (true) { Socket clientSocket = tcpServer.Accept(); Console.WriteLine("a client is connected !"); Client client = new Client(clientSocket);//把與每一個客戶端通訊的邏輯(收發消息)放到client類裏面進行處理 clientList.Add(client); } } } }
服務端之Client:spa
using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; namespace _022_聊天室_socket_tcp服務器端 { // 用來跟客戶端作通訊 class Client { private Socket clientSocket; private Thread t; private byte[] data = new byte[1024];//這個是一個數據容器 public Client(Socket s) { clientSocket = s; //啓動一個線程 處理客戶端的數據接收 t = new Thread(ReceiveMessage); t.Start(); } // 接收數據 private void ReceiveMessage() { //一直接收客戶端的數據 while (true) { //在接收數據以前 判斷一下socket鏈接是否斷開 if (clientSocket.Poll(10, SelectMode.SelectRead)) { clientSocket.Close(); break;//跳出循環 終止線程的執行 } int length = clientSocket.Receive(data); string message = Encoding.UTF8.GetString(data, 0, length); //接收到數據的時候 要把這個數據 分發到客戶端 //廣播這個消息 Program.BroadcastMessage(message); Console.WriteLine("收到了消息:"+message); } } // 發送消息 public void SendMessage(string message) { byte[] data = Encoding.UTF8.GetBytes(message); clientSocket.Send(data); } // 判斷是否鏈接 public bool Connected { get { return clientSocket.Connected; } } } }
客戶端:由於是基於unity的聊天室,因此首先建立簡單的UI界面線程
代碼:code
using UnityEngine; using System.Collections; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class ChatManager : MonoBehaviour { public string ipaddress = "192.168.1.101"; public int port = 7788; public UIInput textInput; public UILabel chatLabel; private Socket clientSocket; private Thread t; private byte[] data = new byte[1024];//數據容器 private string message = "";//消息容器 void Start () { ConnectToServer(); } void Update () { if (message != null && message != "") { chatLabel.text += "\n" + message; message = "";//清空消息 } } void ConnectToServer() { clientSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp); //跟服務器端創建鏈接 clientSocket.Connect( new IPEndPoint(IPAddress.Parse(ipaddress),port) ); //建立一個新的線程 用來接收消息 t = new Thread(ReceiveMessage); t.Start(); } // 這個線程方法 用來循環接收消息 void ReceiveMessage() { while (true) { if (clientSocket.Connected == false) break; int length = clientSocket.Receive(data); message = Encoding.UTF8.GetString(data, 0, length); //chatLabel.text += "\n" + message; } } // 發送消息 void SendMessage(string message) { byte[] data = Encoding.UTF8.GetBytes(message); clientSocket.Send(data); } // 發送按鈕點擊 public void OnSendButtonClick() { string value = textInput.value; SendMessage(value); textInput.value = ""; } void OnDestroy() { clientSocket.Shutdown(SocketShutdown.Both); clientSocket.Close();//關閉鏈接 } }