Socket编程之TcpClient、TcpListener在Unity3D中的应用

经过一段时间的学习,对于TCP/IP协议有了一定的认识,大概知道了TCP协议通信的原理,接下来主要实现用TcpClient、TcpListener两个封装类和stream来实现一个小的demo:用vs建一个工程作为服务器,然后用Unity引擎作为客户端,实现客户端和服务器,客户端和客户端之间的通信。

由于入坑试验多次,这里强调一下通信时候的数据转换,当在客户端发送信息的时候,会将用户输入的字符串转为byte型数组(要通过NetworkStream stream这个对象写入)

代码块一:

 void SendMessage(string myWrite) {
        byte[] data = Encoding.UTF8.GetBytes(myWrite);
        stream.Write(data, 0, data.Length);
  }

服务器端通过流stream来读取数据,并且将数据重新转换为字符串:

代码块二:

byte[] data = new byte[1024];

int length = stream.Read(data, 0, data.Length);

string message = Encoding.UTF8.GetString(data, 0, length);

转换为字符串后就可以在服务器端打印输出了,然后需要再次将字符串数据转为byte[]数组,重新传回客户端

代码块三:(注意!!!在服务器端一定要将客户端读取的byte数组数据先转为字符串,再将字符串重新转为byte[]数组写入到客户端,至于原因,前面踩过坑,发现,如果直接将客户端读取的byte数组写入到客户端,在Unity的UGUI的文本框显示会出现问题,UGUI只会显示用户输入的第一条数据。总之,这一过程必不可少

public void SendMessage(string message) {
            byte[] data = Encoding.UTF8.GetBytes(message);
            stream.Write(data, 0, data.Length);
 }

然后在客户端读取服务器写入过来的数据,将其用byte数组存放,并转为string字符串

代码块四:

byte[] data = new byte[1024];
int length = stream.Read(data, 0, data.Length);
message = Encoding.UTF8.GetString(data, 0, length);

最后将字符串通过Unity引擎的UGUI和基本代码显示到Unity场景中

 

完整代码如下

服务器端(用vs创建一个工程)由一个主方法和自定义类组成:

额外添加命名空间:using System.Net;   using System.Net.Sockets;  using System.Threading;

主方法如下:

 class Program
    {
        public static List ls = new List();
        public static void BroadcastMessage(string message)
        {
            List nols = new List();
            foreach (var client in ls)
            {
                if (client.client.Connected)
                {
                    client.SendMessage(message);
                }
                else
                {
                    nols.Add(client);
                }
            }
            foreach (var i in nols)
            {
                ls.Remove(i);
            }
        }

        static void Main(string[] args)
        {
            //1.创建一个TCPListener对象,实例化绑定了IP和端口号
            TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Parse("192.168.1.101"), 7788));
            //2.开始侦听
            listener.Start();
            Console.WriteLine("已开启服务器...");

            TcpClient client;
            NetworkStream stream;

            byte[] data = new byte[1024]; //data作为一个容器用来接收
            //读取流里面的数据,存放到data的0索引位置,每次最大读取1024个字节
            while (true)
            {
                //3.等待客户端连接
                client = listener.AcceptTcpClient();
                Console.WriteLine("一个客户端已连接");
                //4.取得客户端发送过来的数据
                stream = client.GetStream();

                ClientStream clientStream = new ClientStream(stream, client);
                ls.Add(clientStream);
            }

            stream.Close();
            client.Close();
            listener.Stop();
            Console.ReadKey();
        }
    }

自定义类如下:

 class ClientStream
    {
        private Thread t;
        private NetworkStream stream;
        public TcpClient client;

        public ClientStream(NetworkStream stream, TcpClient client) {
            this.stream = stream;
            this.client = client;
            t = new Thread(ReceiveMessage);
            t.Start();
        }

        private void ReceiveMessage() {
            while (true)
            {
                if (client.Connected == false)
                {
                    Console.WriteLine("客户端断开连接");
                    stream.Close();
                    break; //跳出循环,终止线程的执行
                }
                byte[] data = new byte[1024];
                int length = stream.Read(data, 0, data.Length);
                string message = Encoding.UTF8.GetString(data, 0, length);
                Console.WriteLine("收到了消息:" + message);

                Program.BroadcastMessage(message);
            }
        }

        public void SendMessage(string message) {
            byte[] data = Encoding.UTF8.GetBytes(message);
            stream.Write(data, 0, data.Length);
        }
    }

客户端脚本(创建一个Unity项目,需额外添加命名空间using System.Net;  using System.Net.Sockets;  using System.Text;
using System.Threading;):

public class ClientTest : MonoBehaviour {

    public Text textContainer;
    public InputField text;

    private string address = "192.168.1.101";
    private int port = 7788;
    private TcpClient client;
    private NetworkStream stream;
    private Thread t;

    private string message;

    // Use this for initialization
    void Start () {
        ConnectToServer();
    }
    
    // Update is called once per frame
    void Update () {
        if (Input.GetKeyDown(KeyCode.Return))
        {
            OnSendButtonClick();
        }
        if (message != "" && message != null)
        {
            textContainer.text += "\n" + message;
            Debug.Log("message2:" + message);
            Debug.Log("文本框2:" + textContainer.text);
            message = "";
        }
    }

    //客户端的连接
    void ConnectToServer() {
        client = new TcpClient(address, port);
        Debug.Log("client.Available:" + client.Available);
        //if (client.Available == 0)
        //    Debug.Log("服务器不存在");
        stream = client.GetStream();
        Debug.Log("客户端连接");

        t = new Thread(ReceiveMessage);
        t.Start();
    }

    //客户端发送消息
    void SendMessage(string myWrite) {
        byte[] data = Encoding.UTF8.GetBytes(myWrite);
        stream.Write(data, 0, data.Length);
    }

    //客户端接收消息
    void ReceiveMessage() {
        while (true)
        {
            if (client.Connected == false)
            {
                break;
            }
            byte[] data = new byte[1024];
            int length = stream.Read(data, 0, data.Length);
            message = Encoding.UTF8.GetString(data, 0, length);
            Debug.Log("从服务器受到了:"+message);
        }
    }

    //按钮侦听函数
    public void OnSendButtonClick() {
        if (text.text != null && text.text != "" && client.Connected) {
            string myWrite= text.text;
            SendMessage(myWrite);
            text.text = "";
        }
    }

    void OnDestroy() {
        stream.Close();
        client.Close();
    }
}

最后先编译vs这边的程序,即启动服务器,

Socket编程之TcpClient、TcpListener在Unity3D中的应用_第1张图片

 

 

 

然后运行Unity,即启动客户端,

Socket编程之TcpClient、TcpListener在Unity3D中的应用_第2张图片也可以将Unity项目打包发布PC端,这样就可以有多个客户端了

Socket编程之TcpClient、TcpListener在Unity3D中的应用_第3张图片

 

 

 

 

 以上只是一个小的demo,望各位大佬不吝赐教!!!

你可能感兴趣的:(Unity聊天室,Socket编程)