Unity的网络通信这块是个坑,还有端口通信。
首先是网络通信,网络通信有Udp协议,Tcp短链接,Tcp长连接等等。搜的话网上一大堆代码。
但是我在使用中遇到了一些问题,发送端没啥好说的,主要是接收端。问题如下:
1.首先是接收端写法,在update里面写和在协程里面写都不行,只有在新开的线程中才可以使用,但是
如果关闭的时候没关闭好线程就会导致程序未响应卡死。
2.udp广播在不同平台上有时候接收不到。
using UnityEngine; using System.Collections; //引入库 using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; public class UdpServer : MonoBehaviour { //接收的字符串 // public string strRecvData;//接收到的消息 public bool IsNewRecv;//是否接收到新的消息,当接收到消息将其改为false //以下默认都是私有的成员 Socket socket; //目标socket EndPoint clientEnd; //客户端 IPEndPoint ipEnd; //侦听端口 string sendStr; //发送的字符串 string recvStr; byte[] recvData = new byte[1024]; //接收的数据,必须为字节 byte[] sendData = new byte[1024]; //发送的数据,必须为字节 int recvLen; //接收的数据长度 Thread connectThread; //连接线程 string strTextData = "Data:"; //初始化 void InitSocket() { //定义侦听端口,侦听任何IP ipEnd = new IPEndPoint(IPAddress.Any,8088); //定义套接字类型,在主线程中定义 socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); //服务端需要绑定ip socket.Bind(ipEnd); //定义客户端 IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0); clientEnd = (EndPoint)sender; print("waiting for UDP dgram"); //开启一个线程连接,必须的,否则主线程卡死 connectThread = new Thread(new ThreadStart(SocketReceive)); connectThread.Start(); // UdpClient cls = new UdpClient(); // cls.Close(); } void SocketSend(string sendStr) { //清空发送缓存 sendData = new byte[1024]; //数据类型转换 sendData = Encoding.ASCII.GetBytes(sendStr); //发送给指定客户端 socket.SendTo(sendData, sendData.Length, SocketFlags.None, clientEnd); } //服务器接收 void SocketReceive() { //进入接收循环 while (true) { //对data清零 recvData = new byte[1024]; //获取客户端,获取客户端数据,用引用给客户端赋值 recvLen = socket.ReceiveFrom(recvData, ref clientEnd); //print("message from: " + clientEnd.ToString()); //打印客户端信息 //输出接收到的数据 recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen); //strTextData += (recvStr+"||"); if (recvStr.Length>1) { IsNewRecv = true; strRecvData = recvStr; } //print(recvStr); //将接收到的数据经过处理再发送出去 //sendStr = "From Server: " + recvStr; // SocketSend(sendStr); } } //连接关闭 void SocketQuit() { //关闭线程 if (connectThread != null) { connectThread.Interrupt(); connectThread.Abort(); } //最后关闭socket if (socket != null) { socket.Close(); } } // Use this for initialization void Start() { InitSocket(); //在这里初始化server } // Update is called once per frame void Update() { } //这里使用OnDestroy进程就会完全关掉。OnDestroy void OnDestroy() { SocketQuit(); } //void OnGUI() //{ // GUILayout.Label(strTextData); //} }端口通信:Unity端口通信是个坑,接收端接收会将接收的内容分两次获取,比如说我发一个“”Unity”让程序接收,她会先收到一个“U”,再收到一个“nity”。
不知道后续版本会不会修复这个bug。我百度搜了下有篇文章也全篇在说明这个问题。我这里的解决办法就是将两次接收判断一下。如果接收到是一个字符,就等下个字符串接收到表示一次接收。但这样有个问题就是三个字符以下的命令接收就有错误。所以避免发送三个字符以下的代码就可以用(- -)。以下是代码
using UnityEngine; using System.Collections; using System.Threading; using System.Text; using System.IO.Ports; using System; using System.Collections.Generic; using UnityEngine.UI; //这里传输的字节数必须大于3才行,不然会出现错误。 public class ComReceive : MonoBehaviour { public Text txtUI; public Text txtPCUI; public GameObject go; public string strtxt = "5"; public string portName = "COM2";//端口号 public int baudRate = 9600;//波特率 public Parity parity = Parity.None;//奇偶校验位 public int dataBits = 8;//数据位值 public StopBits stopBits = StopBits.One;//停止位数 SerialPort sp = null; // Thread connectThread;//主线程 byte[] b = new byte[1024]; string strInfo; void Start() { sp = new SerialPort(portName, baudRate, parity, dataBits, stopBits); sp.Open(); //开启一个线程连接,必须的,否则主线程卡死 connectThread = new Thread(new ThreadStart(ReceiveMethod)); connectThread.Start(); } void Update() { txtUI.text = strtxt; go.transform.position = new Vector3(go.transform.position.x, Convert.ToSingle(strtxt) * 0.1f, go.transform.position.z); //img.rectTransform.anchoredPosition3D = new Vector3(Convert, img.rectTransform.anchoredPosition3D.y, img.rectTransform.anchoredPosition3D.z); } private void ReceiveMethod() { string recvData = ""; while (true) { //打开新的串行端口连接 //丢弃来自串行驱动程序的接收缓冲区的数据 sp.DiscardInBuffer(); //丢弃来自串行驱动程序的传输缓冲去的数据 sp.DiscardOutBuffer(); // int k = sp.Read(b, 0, b.Length); string a = Encoding.ASCII.GetString(b, 0, k); if (k == 1) { recvData = a; } else { recvData += a; strtxt = recvData; // print(recvData); } } } private void ReceiveMethod2() { } //这里也一样使用OnDestroy
//void OnApplicationQuit()OnDestroy void OnDestroy() { sp.Close(); SocketQuit(); } //连接关闭 private void SocketQuit() { //关闭线程 if (connectThread != null) { connectThread.Interrupt(); connectThread.Abort(); } } }