C#网络编程学习(3)---使用Tcp和Unity创建本地聊天室的小案例

使用Tcp协议实现最简单的本地局域网聊天

1、思路

服务器

  1. 先用C#网络编程学习(1)---Socket之Tcp协议的简单使用中方法写可接收多个客户端的连接代码。
  2. 另外写一个类Client专门处理连接的客户端clientSocket。
  3. 在主类中用List存放所有连接的客户端。。
  4. 在Client中给出接收信息(线程),发送信息,是否处于连接状态方法。
  5. 在主类中写广播方法(向所有客户端发送信息)

Unity客户端UI

Unity客户端代码

  1. Unity空物体ChatManager中绑定脚本ChatManager
  2. 游戏开始时连接服务器
  3. 点击按钮事件触发Send()发送数据方法
  4. 接收广播消息的方法(线程).

2、服务器端

/// <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; }
    }
}

3、客户端

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组件,所以间接改变
        }
    }
}

4、效果

先打开VS中服务器
图1:为客户端连接时,服务器弹出连接信息,服务器可以收到客户端发送的消息


**图2**:为打开两个客户端时,一方发送消息,另一方就可以收到 ![](https://img2018.cnblogs.com/blog/1355434/201905/1355434-20190508133554525-271203991.gif)

5、百度云源码链接

链接:https://pan.baidu.com/s/1dsZNw8UQJ8BjJHejBzaOLg
提取码:3ufk

posted @ 2019-05-08 20:08  Fflyqaq  阅读(712)  评论(0编辑  收藏  举报