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();
}
}
}