Unity/C#要想和其他電腦或者軟件程序通訊,最好的方式是通過網(wǎng)絡(luò)進(jìn)行通訊,下面簡要介紹以下其原理和實現(xiàn):
TCP和UDP
TCP和UDP是傳輸層協(xié)議,使用IP協(xié)議從一個網(wǎng)絡(luò)傳送數(shù)據(jù)包到另一個網(wǎng)絡(luò)。把IP想像成一種高速公路,它允許其它協(xié)議在上面行駛并找到到其它電腦的出口。
兩者的不同是:TCP能提供有保證的數(shù)據(jù)傳輸,而UDP不提供,即UDP的數(shù)據(jù)容易丟失。
Socket 接口是TCP/IP網(wǎng)絡(luò)的API,Socket接口定義了許多函數(shù)或例程,用以開發(fā)TCP/IP網(wǎng)絡(luò)上的應(yīng)用程序。也就是說Socket是TCP/UDP通訊的實現(xiàn)方式。
TCP Unity簡單實現(xiàn)
TCP服務(wù)端
新建U3D項目,創(chuàng)建空場景,添加server腳本到相機:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets; //調(diào)用socket
using System.Text;
using System.Threading; //調(diào)用線程
using UnityEngine;
using System.IO;
public class server : MonoBehaviour
{
//定義變量(與GUI一致)
private string info = "NULL"; //狀態(tài)信息
private string recMes = "NULL"; //接收到的信息
private int recTimes = 0; //接收到的信息次數(shù)
private string inputIp = "127.0.0.1"; //ip地址(本地)
private string inputPort = "8080"; //端口值
private string inputMessage = "NULL"; //用以發(fā)送的信息
private Socket socketWatch; //用以監(jiān)聽的套接字
private Socket socketSend; //用以和客戶端通信的套接字
private bool isSendData = false; //是否點擊發(fā)送數(shù)據(jù)按鈕
private bool clickConnectBtn = false; //是否點擊監(jiān)聽按鈕
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
//建立tcp通信鏈接
private void ClickConnect()
{
try
{
int _port = Convert.ToInt32(inputPort); //獲取端口號(32位,4個字節(jié))
string _ip = inputIp; //獲取ip地址
Debug.Log(" ip 地址是 :" + _ip);
Debug.Log(" 端口號是 :" + _port);
clickConnectBtn = true; //點擊了監(jiān)聽按鈕,更改狀態(tài)
info = "ip地址是 : " + _ip + "端口號是 : " + _port;
//點擊開始監(jiān)聽時 在服務(wù)端創(chuàng)建一個負(fù)責(zé)監(jiān)聽IP和端口號的Socket
socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(_ip);
IPEndPoint point = new IPEndPoint(ip, _port); //創(chuàng)建對象端口
socketWatch.Bind(point); //綁定端口號
Debug.Log("監(jiān)聽成功!");
info = "監(jiān)聽成功";
socketWatch.Listen(10); //設(shè)置監(jiān)聽,最大同時連接10臺
//創(chuàng)建監(jiān)聽線程
Thread thread = new Thread(Listen);
thread.IsBackground = true;
thread.Start(socketWatch);
}
catch { }
}
/// <summary>
/// 等待客戶端的連接 并且創(chuàng)建與之通信的Socket
/// </summary>
void Listen(object o)
{
try
{
Socket socketWatch = o as Socket;
while (true)
{
socketSend = socketWatch.Accept(); //等待接收客戶端連接
Debug.Log(socketSend.RemoteEndPoint.ToString() + ":" + "連接成功!");
info = socketSend.RemoteEndPoint.ToString() + " 連接成功!";
Thread r_thread = new Thread(Received); //開啟一個新線程,執(zhí)行接收消息方法
r_thread.IsBackground = true;
r_thread.Start(socketSend);
Thread s_thread = new Thread(SendMessage); //開啟一個新線程,執(zhí)行發(fā)送消息方法
s_thread.IsBackground = true;
s_thread.Start(socketSend);
}
}
catch { }
}
// 服務(wù)器端不停的接收客戶端發(fā)來的消息
void Received(object o)
{
try
{
Socket socketSend = o as Socket;
while (true)
{
byte[] buffer = new byte[1024 * 6]; //客戶端連接服務(wù)器成功后,服務(wù)器接收客戶端發(fā)送的消息
int len = socketSend.Receive(buffer); //實際接收到的有效字節(jié)數(shù)
if (len == 0)
{
break;
}
string str = Encoding.UTF8.GetString(buffer, 0, len);
Debug.Log("接收到的消息:" + socketSend.RemoteEndPoint + ":" + str);
recMes = str;
recTimes++;
info = "接收到一次數(shù)據(jù),接收次數(shù)為:" + recTimes;
Debug.Log("接收數(shù)據(jù)次數(shù):" + recTimes);
}
}
catch { }
}
// 服務(wù)器端不停的向客戶端發(fā)送消息
void SendMessage(object o)
{
try
{
Socket socketSend = o as Socket;
while (true)
{
if (isSendData)
{
isSendData = false;
byte[] sendByte = Encoding.UTF8.GetBytes(inputMessage);
Debug.Log("發(fā)送的數(shù)據(jù)為 :" + inputMessage);
Debug.Log("發(fā)送的數(shù)據(jù)字節(jié)長度 :" + sendByte.Length);
socketSend.Send(sendByte);
}
}
}
catch { }
}
// 關(guān)閉連接,釋放資源
private void OnDisable()
{
Debug.Log("begin OnDisable()");
if (clickConnectBtn)
{
try
{
socketWatch.Shutdown(SocketShutdown.Both); //禁用Socket的發(fā)送和接收功能
socketWatch.Close(); //關(guān)閉Socket連接并釋放所有相關(guān)資源
socketSend.Shutdown(SocketShutdown.Both); //禁用Socket的發(fā)送和接收功能
socketSend.Close(); //關(guān)閉Socket連接并釋放所有相關(guān)資源
}
catch (Exception e)
{
Debug.Log(e.Message);
}
}
Debug.Log("end OnDisable()");
}
//交互界面(代碼創(chuàng)建)
void OnGUI()
{
GUI.color = Color.black; //字體顏色
GUI.Label(new Rect(65, 10, 80, 20), "狀態(tài)信息");
GUI.Label(new Rect(155, 10, 80, 70), info);
GUI.Label(new Rect(65, 80, 80, 20), "接收到消息:");
GUI.Label(new Rect(155, 80, 80, 20), recMes);
GUI.Label(new Rect(65, 120, 80, 20), "發(fā)送的消息:");
inputMessage = GUI.TextField(new Rect(155, 120, 100, 20), inputMessage, 20);
GUI.Label(new Rect(65, 160, 80, 20), "本機ip地址:");
inputIp = GUI.TextField(new Rect(155, 160, 100, 20), inputIp, 20);
GUI.Label(new Rect(65, 200, 80, 20), "本機端口號:");
inputPort = GUI.TextField(new Rect(155, 200, 100, 20), inputPort, 20);
if (GUI.Button(new Rect(65, 240, 60, 20), "開始監(jiān)聽"))
{
ClickConnect(); //點擊開始
}
if (GUI.Button(new Rect(65, 280, 60, 20), "發(fā)送數(shù)據(jù)"))
{
isSendData = true; //發(fā)送數(shù)據(jù)
}
}
}
測試如下:
TCP客戶端
客戶端與服務(wù)端實現(xiàn)類似,貼上腳本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class client : MonoBehaviour
{
private string staInfo = "NULL"; //狀態(tài)信息
private string inputIp = "127.0.0.1"; //輸入ip地址
private string inputPort = "8080"; //輸入端口號
public string inputMes = "NULL"; //發(fā)送的消息
private int recTimes = 0; //接收到信息的次數(shù)
private string recMes = "NULL"; //接收到的消息
private Socket socketSend; //客戶端套接字,用來鏈接遠(yuǎn)端服務(wù)器
private bool clickSend = false; //是否點擊發(fā)送按鈕
void Start()
{
}
// Update is called once per frame
void Update()
{
}
//建立鏈接
private void ClickConnect()
{
try
{
int _port = Convert.ToInt32(inputPort); //獲取端口號
string _ip = inputIp; //獲取ip地址
//創(chuàng)建客戶端Socket,獲得遠(yuǎn)程ip和端口號
socketSend = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(_ip);
IPEndPoint point = new IPEndPoint(ip, _port);
socketSend.Connect(point);
Debug.Log("連接成功 , " + " ip = " + ip + " port = " + _port);
staInfo = ip + ":" + _port + " 連接成功";
Thread r_thread = new Thread(Received); //開啟新的線程,不停的接收服務(wù)器發(fā)來的消息
r_thread.IsBackground = true;
r_thread.Start();
Thread s_thread = new Thread(SendMessage); //開啟新的線程,不停的給服務(wù)器發(fā)送消息
s_thread.IsBackground = true;
s_thread.Start();
}
catch (Exception)
{
Debug.Log("IP或者端口號錯誤......");
staInfo = "IP或者端口號錯誤......";
}
}
/// <summary>
/// 接收服務(wù)端返回的消息
/// </summary>
void Received()
{
while (true)
{
try
{
byte[] buffer = new byte[1024 * 6];
//實際接收到的有效字節(jié)數(shù)
int len = socketSend.Receive(buffer);
if (len == 0)
{
break;
}
recMes = Encoding.UTF8.GetString(buffer, 0, len);
Debug.Log("客戶端接收到的數(shù)據(jù) : " + recMes);
recTimes ++;
staInfo = "接收到一次數(shù)據(jù),接收次數(shù)為 :" + recTimes;
Debug.Log("接收次數(shù)為:" + recTimes);
}
catch { }
}
}
/// <summary>
/// 向服務(wù)器發(fā)送消息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void SendMessage()
{
try
{
while (true)
{
if (clickSend) //如果點擊了發(fā)送按鈕
{
clickSend = false;
string msg = inputMes;
byte[] buffer = new byte[1024 * 6];
buffer = Encoding.UTF8.GetBytes(msg);
socketSend.Send(buffer);
Debug.Log("發(fā)送的數(shù)據(jù)為:" + msg);
}
}
}
catch { }
}
private void OnDisable()
{
Debug.Log("begin OnDisable()");
if (socketSend.Connected)
{
try
{
socketSend.Shutdown(SocketShutdown.Both); //禁用Socket的發(fā)送和接收功能
socketSend.Close(); //關(guān)閉Socket連接并釋放所有相關(guān)資源
}
catch (Exception e)
{
print(e.Message);
}
}
Debug.Log("end OnDisable()");
}
//用戶界面
void OnGUI()
{
GUI.color = Color.black;
GUI.Label(new Rect(65, 10, 60, 20), "狀態(tài)信息");
GUI.Label(new Rect(135, 10, 80, 60), staInfo);
GUI.Label(new Rect(65, 70, 50, 20), "服務(wù)器ip地址");
inputIp = GUI.TextField(new Rect(125, 70, 100, 20), inputIp, 20);
GUI.Label(new Rect(65, 110, 50, 20), "服務(wù)器端口");
inputPort = GUI.TextField(new Rect(125, 110, 100, 20), inputPort, 20);
GUI.Label(new Rect(65, 150, 80, 20), "接收到消息:");
GUI.Label(new Rect(155, 150, 80, 20), recMes);
GUI.Label(new Rect(65, 190, 80, 20), "發(fā)送的消息:");
inputMes = GUI.TextField(new Rect(155, 190, 100, 20), inputMes, 20);
if (GUI.Button(new Rect(65, 230, 60, 20), "開始連接"))
{
ClickConnect();
}
if (GUI.Button(new Rect(65, 270, 60, 20), "發(fā)送信息"))
{
clickSend = true;
}
}
}
UDP Unity簡單實現(xiàn)
UDP服務(wù)端
同樣,新建U3D項目,創(chuàng)建腳本:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;
public class server : MonoBehaviour
{
private Socket socket; //目標(biāo)socket
private EndPoint clientEnd; //客戶端
private IPEndPoint ipEnd; //偵聽端口
private string recvStr; //接收的字符串
private string sendStr; //發(fā)送的字符串
private byte[] recvData = new byte[1024]; //接收的數(shù)據(jù),必須為字節(jié)
private byte[] sendData = new byte[1024]; //發(fā)送的數(shù)據(jù),必須為字節(jié)
private int recvLen; //接收的數(shù)據(jù)長度
private Thread connectThread; //連接線程
// Start is called before the first frame update
void Start()
{
InitSocket(); //在這里初始化server
}
// Update is called once per frame
void Update()
{
}
//初始化
void InitSocket()
{
//定義偵聽端口,偵聽任何IP
ipEnd = new IPEndPoint(IPAddress.Any, 8999);
Debug.Log(ipEnd);
//定義套接字類型,在主線程中定義
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//服務(wù)端需要綁定ip
socket.Bind(ipEnd);
//定義客戶端
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 9000);
clientEnd = (EndPoint)sender;
Debug.Log(clientEnd);
print("waiting for UDP dgram");
//開啟一個線程連接,必須的,否則主線程卡死
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
//服務(wù)器發(fā)送
void SocketSend(string sendStr)
{
//清空發(fā)送緩存
sendData = new byte[1024];
//數(shù)據(jù)類型轉(zhuǎn)換
sendData = Encoding.ASCII.GetBytes(sendStr);
//發(fā)送給指定客戶端
socket.SendTo(sendData, sendData.Length, SocketFlags.None, clientEnd);
}
//服務(wù)器接收
void SocketReceive()
{
//進(jìn)入接收循環(huán)
while (true)
{
//對data清零
recvData = new byte[1024];
//獲取客戶端,獲取客戶端數(shù)據(jù),用引用給客戶端賦值
recvLen = socket.ReceiveFrom(recvData, ref clientEnd);
print("message from: " + clientEnd.ToString()); //打印客戶端信息
//輸出接收到的數(shù)據(jù)
recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen);
print("我是服務(wù)器,接收到客戶端的數(shù)據(jù)" + recvStr);
//將接收到的數(shù)據(jù)經(jīng)過處理再發(fā)送出去
sendStr = "From Server: " + recvStr;
SocketSend(sendStr);
}
}
//連接關(guān)閉
void SocketQuit()
{
//關(guān)閉線程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后關(guān)閉socket
if (socket != null)
socket.Close();
print("disconnect");
}
void OnApplicationQuit()
{
SocketQuit();
}
}
測試結(jié)果如下:
UDP客戶端
客戶端與服務(wù)端類似,腳本如下:文章來源:http://www.zghlxwxcb.cn/news/detail-795613.html
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine.UI;
public class UdpClient : MonoBehaviour
{
public string editString = “hello wolrd”; //編輯框文字
//以下默認(rèn)都是私有的成員
private Socket socket; //目標(biāo)socket
private EndPoint serverEnd; //服務(wù)端
private IPEndPoint ipEnd; //服務(wù)端端口
private string recvStr; //接收的字符串
private string sendStr; //發(fā)送的字符串
private byte[] recvData = new byte[1024]; //接收的數(shù)據(jù),必須為字節(jié)
private byte[] sendData = new byte[1024]; //發(fā)送的數(shù)據(jù),必須為字節(jié)
private int recvLen; //接收的數(shù)據(jù)長度
private Thread connectThread; //連接線程
//初始化
void InitSocket()
{
//定義連接的服務(wù)器ip和端口,可以是本機ip,局域網(wǎng),互聯(lián)網(wǎng)
ipEnd = new IPEndPoint(IPAddress.Parse("172.168.1.103"), 8999);
//定義套接字類型,在主線程中定義
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//定義服務(wù)端
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
serverEnd = (EndPoint)sender;
print("waiting for sending UDP dgram");
//建立初始連接,這句非常重要,第一次連接初始化了serverEnd后面才能收到消息
SocketSend("hello");
//開啟一個線程連接,必須的,否則主線程卡死
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketSend(string sendStr)
{
//清空發(fā)送緩存
sendData = new byte[1024];
//數(shù)據(jù)類型轉(zhuǎn)換
sendData = Encoding.ASCII.GetBytes(sendStr);
//發(fā)送給指定服務(wù)端
socket.SendTo(sendData, sendData.Length, SocketFlags.None, ipEnd);
}
//服務(wù)器接收
void SocketReceive()
{
//進(jìn)入接收循環(huán)
while (true)
{
//對data清零
recvData = new byte[1024];
//獲取客戶端,獲取服務(wù)端端數(shù)據(jù),用引用給服務(wù)端賦值,實際上服務(wù)端已經(jīng)定義好并不需要賦值
recvLen = socket.ReceiveFrom(recvData, ref serverEnd);
print("message from: " + serverEnd.ToString()); //打印服務(wù)端信息
//輸出接收到的數(shù)據(jù)
recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen);
print("我是客戶端,接收到服務(wù)器的數(shù)據(jù)" + recvStr);
}
}
//連接關(guān)閉
void SocketQuit()
{
//關(guān)閉線程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后關(guān)閉socket
if (socket != null)
socket.Close();
}
// Use this for initialization
void Start()
{
InitSocket(); //在這里初始化
}
void OnGUI()
{
editString = GUI.TextField(new Rect(10, 10, 100, 20), editString);
if (GUI.Button(new Rect(10, 30, 60, 20), "send"))
SocketSend(editString);
}
// Update is called once per frame
void Update()
{
}
void OnApplicationQuit()
{
SocketQuit();
}
以上。文章來源地址http://www.zghlxwxcb.cn/news/detail-795613.html
到了這里,關(guān)于【Unity】網(wǎng)絡(luò)通信(TCP&UDP)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!