Unity3D——制作聊天室

本小白刚接触到socket编程这一块,模仿着写了一个多人在线聊天室,也算是对这个模块有了初步认识吧,写这篇博客一来是在日后能够再温习一下,二来是想给更多小白一个参考学习的详细案例,三来也是对自己学习过程的一个笔记总结吧!好了,话不多说,直接上成果!

演示视频

unity制作聊天室成果展示视频

工具

  1. Visual Studio 2017
  2. Unity 2017
  3. NGUI插件

1.服务器端

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace TCP_Unity_Server
{
     
    class Program
    {
     
        //用于存储接收到的每一个 与客户端交互对象
        static List<Client> clientList = new List<Client>();

        //将一个客户端发出到服务器的消息,发送给所有的客户端(包括他自己)
        public static void BroadcastMessage(string message)//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)
        {
     
            //1.创建sicket
            Socket tcpServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            //2.绑定ip跟端口号 192.168.0.103(本机的ip地址,端口号设置一个四位数的即可)
            //提供internet协议的ip地址
            IPAddress ipaddress = new IPAddress(new byte[] {
      192, 168, 0, 103 });
            //IPEndPoint是对ip+端口做了一层封装的类
            EndPoint point = new IPEndPoint(ipaddress, 7788);
            //向操作系统申请一个可用的ip跟端口号 用来做通信(判断上面写ip、端口的是否用)
            tcpServer.Bind(point);
            //3.开始监听(等待客户端连接)
            //参数是最大连接数,表示该服务器能连接多少台用户端,我设置的为5
            tcpServer.Listen(5);
            //这里是在控制台提示,服务器是否在运行
            Console.WriteLine("server running...");

            //这里做了一个死循环,因为客户端不止一个,一直要接收客户端的连接请求
            while (true)
            {
     
                //使用返回的socket(clientSocket)跟客户端做通讯 (后面将其称为 与客户端交互对象)
                Socket clientSocket = tcpServer.Accept();
                //这段程序时暂停当前线程,直到有一个客户端连接过来,再进行下面的脚本操作

                //这里是在控制台提示,服务器是否在运行,表示有客户端连接进来了
                Console.WriteLine("a client is connected!");
                //把接收到的客户端对象 放到Client类(用来跟看客户端进行通讯)里面处理
                Client client = new Client(clientSocket);//一个client 就表示一个 与客户端交互对象

                //将客户端对象添加进集合中
                clientList.Add(client);
                
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace TCP_Unity_Server
{
     
    //用来跟客户端做通信 (与客户端交互对象)
    class Client
    {
     
        private Socket clientSocket;//与客户端交互对象
        private Thread t;//线程
        private byte[] data = new byte[1024];//数据容器
        public Client(Socket s)
        {
     
            //clientSocket就是 与客户端交互对象
            clientSocket = s;
            //启动一个线程 处理客户端的数据接收
            t = new Thread(ReceiveMessage);//创建一个线程用于处理ReceiveMessage
            //开始执行
            t.Start();
        }

        private void ReceiveMessage()
        {
     
            while (true)//设置为死循环,是因为这个线程:服务器一直会与客户端进行通讯
            {
     

                //在接收前,判断一下socket连接是否断开(与客户端交互对象 的状态是否处于连接)
                //if (clientSocket.Connected==false)
                if (clientSocket.Poll(10,SelectMode.SelectRead))//10毫秒的判断时间是否断开连接了
                {
     
                    clientSocket.Close();//如果断开了连接,那么就要关闭与客户端的通讯(与客户端交互对象),也就是与这台客户端的通讯线程完成了
                    break;//跳出循环,终止线程执行
                }

                //返回值表示接收了多少字节的数据, 
                //clientSocket.Receive(data)用于接收客户端发送过来的数据,数据需要接收
                //用一个1024字节大小的容器data接收
                int length = clientSocket.Receive(data);//与客户端交互对象 接收到的数据
                //将接受到的data数据,只把从索引0开始的length个字节转化string
                string message = Encoding.UTF8.GetString(data,0,length);
                //TODO:接收到数据的时候 要把这个数据分发到客户端
                //广播这个消息
                Program.BroadcastMessage(message);
                //在控制台输出服务器接收到的消息
                Console.WriteLine("收到了消息:"+message);
            }
        }

        public void SendMessage(string message)
        {
     
            //将将需要发送的message数据,转化为byte字节形式存入byte数组中
            byte[] data = Encoding.UTF8.GetBytes(message);
            clientSocket.Send(data);//与客户端交互对象 将这个消息message 发送给这个客户端
        }

        public bool Connected//判断 与客户端交互对象 是否处于连接状态
        {
     
            get {
      return clientSocket.Connected; }
        }
    }
}

2.客户端(Uinty)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;

public class chatMessage : MonoBehaviour {
     

    public string ipaddress = "192.168.0.103";//与服务器ip保持一样
    public int port = 7788;//端口号
    public UIInput textInput;//输入框(用的NGUI构造)
    public UILabel chatLable;//Lable(用的NGUI构造)

    private Socket clientSocket;//socket,定义为全局,作用于所有方法
    private Thread t;//线程,定义为全局,作用于所有方法
    private byte[] data = new byte[1024];//数据容器,定义为全局,作用于所有方法
    private string message = "";//用来接收服务器放松过来的消息 消息容器 ,定义为全局,作用于所有方法
                                // Use this for initialization
    void Start () {
     
        ConnectToServer();//一运行程序,就会去连接服务器
	}
	
	// Update is called once per frame
	void Update () {
     
        if (message!=null && message!="")
        {
     
            chatLable.text += "\n" + message;
            message = "";
        }
	}

    void ConnectToServer()//连接服务器
    {
     
        //创建socket对象
        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);
            //将接受到的data数据,只把从索引0开始的length个字节转化为string
            message = Encoding.UTF8.GetString(data, 0, length);
        }
    }

    //用于向服务器发送消息
    void SendMessage(string message)
    {
     
        //将将需要发送的message数据,转化为byte字节形式存入byte数组中
        byte[] data = Encoding.UTF8.GetBytes(message);
        clientSocket.Send(data);//向服务器发送消息
    }

    public void OnSendButtonClick()//这个是为按钮做的方法(在unity中,为button添加on click事件)
    {
     
        string value = textInput.value;//获取输入框里信息
        SendMessage(value);//向服务器发送消息
        textInput.value = "";//发送后清空输入框
    }

    //void OnDestory()
    //{
     
    //    clientSocket.Shutdown(SocketShutdown.Both)//既不接受也不发送
    //    clientSocket.Close();//关闭socket
    //}
}

源码、插件、聊天室应用程序分享

链接:https://pan.baidu.com/s/1Ufqgl1jKcSds6sWDjyDHIw
提取码:miuu

你可能感兴趣的:(unity学习,unity3d)