C#網絡編程學習(3)---使用Tcp和Unity建立本地聊天室的小案例

使用Tcp協議實現最簡單的本地局域網聊天

一、思路

服務器html

  1. 先用C#網絡編程學習(1)---Socket之Tcp協議的簡單使用中方法寫可接收多個客戶端的鏈接代碼。
  2. 另外寫一個類Client專門處理鏈接的客戶端clientSocket。
  3. 在主類中用List<Client>存放全部鏈接的客戶端。。
  4. 在Client中給出接收信息(線程),發送信息,是否處於鏈接狀態方法。
  5. 在主類中寫廣播方法(向全部客戶端發送信息)

Unity客戶端UI 編程

Unity客戶端代碼c#

  1. Unity空物體ChatManager中綁定腳本ChatManager
  2. 遊戲開始時鏈接服務器
  3. 點擊按鈕事件觸發Send()發送數據方法
  4. 接收廣播消息的方法(線程).

二、服務器端

/// <summary>
/// 主類中寫服務器信息
/// </summary>
class Program
{
    //建立一個集合記錄全部鏈接的客戶端,當廣播消息時,向鏈接的全體客戶端發送消息
    private static List<Client> clientList = new List<Client>();

    static void Main(string[] args)
    {
        Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        tcpServer.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 7788));
        tcpServer.Listen(100);
        Console.WriteLine("server running");

        while (true) //用while接收多個客戶端鏈接
        {
            Socket tcpClient = tcpServer.Accept();
            Console.WriteLine("a client is connected");

            //由於不只須要while接收多個客戶端,每一個客戶端也能夠一直髮送消息。因此單獨寫個類來控制客戶端比較直觀方便。
            Client client = new Client(tcpClient);
            clientList.Add(client);
        }
    }

    //廣播消息  (就是向全部客戶端發送消息)
    public static void BroadcastMessage(string message)
    {
        List<Client> notConnectedList = new List<Client>(); //得到全部斷開鏈接的客戶端
        //遍歷list集合,向全部客戶端發送消息
        foreach (var client in clientList)
        {
            if (client.Connected)
                client.SendMessage(message);
            else
            {
                notConnectedList.Add(client);
            }
        }

        //把全部斷開鏈接的客戶端移除
        foreach (var temp in notConnectedList)
        {
            clientList.Remove(temp);
        }
    }

}

/// <summary>
/// Client類用來和客戶端作通訊
/// </summary>
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);

            //消息的廣播,要放在Main裏面寫,由於在Main中存着全部鏈接的客戶端
            Program.BroadcastMessage(message);
            Console.WriteLine("收到了消息" + message);
        }
    }

    //向全部客戶端發送消息
    public void SendMessage(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        clientSocket.Send(data);
    }

    //判斷客戶端服務器是否還鏈接,不鏈接將在Main裏面刪去
    public bool Connected
    {
        get { return clientSocket.Connected; }
    }
}

三、客戶端

public class ChatManager : MonoBehaviour
{
    private string ipAddress = "192.168.1.2";
    private int port = 7788;
    private Socket clientSocket;
    public InputField textInput; //用戶輸入框
    
    //接收服務器數據
    private Thread t;
    private byte[] data = new byte[1024];
    private string receiveMessages = "";
    public Text chatText;  //用戶聊天框

    private void Start()
    {
        ConnectedToServer();
    }

    private void Update()
    {
        //時刻檢測當接收到數據時,receiveMessages不爲空,數據加入到聊天框當中
        if (receiveMessages != null && receiveMessages != "")
        {
            chatText.text += "\n" + receiveMessages;
            receiveMessages = "";
        }
    }

    //程序開始時鏈接服務器
    private void ConnectedToServer()
    {
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        //發起鏈接
        clientSocket.Connect(new IPEndPoint(IPAddress.Parse(ipAddress), port));

        //建立一個新的線程用於接收廣播消息,由於消息要一直接收的
        t = new Thread(ReceiveMessage);
        t.Start();
    }

    //發送數據
    private void SendMessage(string message)
    {
        byte[] data = Encoding.UTF8.GetBytes(message);
        clientSocket.Send(data);
    }

    //點擊按鈕觸發
    public void OnSendButtonClick()
    {
        string value = textInput.text;
        SendMessage(value);
        textInput.text = "";
    }

    //這個線程方法用於循環接收廣播消息
    private void ReceiveMessage()
    {
        while (true)
        {
            //與服務器斷開鏈接時,取消線程
            if (clientSocket.Connected == false)
            {
                break;
            }
            int length = clientSocket.Receive(data);
            receiveMessages = Encoding.UTF8.GetString(data, 0, length);
            //由於Unity中線程不容許直接操控UI組件,因此間接改變
        }
    }
}

四、效果

先打開VS中服務器 圖1:爲客戶端鏈接時,服務器彈出鏈接信息,服務器能夠收到客戶端發送的消息 服務器

<br> **圖2**:爲打開兩個客戶端時,一方發送消息,另外一方就能夠收到 ![](https://img2018.cnblogs.com/blog/1355434/201905/1355434-20190508133554525-271203991.gif)網絡

五、百度雲源碼連接

連接:https://pan.baidu.com/s/1dsZNw8UQJ8BjJHejBzaOLg 提取碼:3ufksocket

相關文章
相關標籤/搜索