在Unity3d项目中利用Udp进行局域网内通信
实现一个用于存储通信息的Quene
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System;
public class CQuene {
int packetnum;
int packetsize;
int size;
int first;
int tail;
byte[] packet;
byte[] zeroBuff;
Mutex hMutex;
public CQuene(int npacket, int sizepacket, string mutexName)
{
size = 0;
first = 0;
tail = 0;
packetnum = npacket;
packetsize = sizepacket;
packet = new byte[npacket * sizepacket];
zeroBuff = new byte[sizepacket];
hMutex = new Mutex(false, mutexName);
}
//void getempty()
//{
//}
public byte[] getvalid()
{
hMutex.WaitOne();
byte[] datas;
if( size > 0 )
{
datas = new byte[packetsize];
Array.Copy(packet, packetsize * tail, datas, 0, packetsize);
tail = (tail + 1) % packetnum;
size--;
}
else
{
datas = null;
}
hMutex.ReleaseMutex();
return datas;
}
public void flush()
{
hMutex.WaitOne();
first = 0;
tail = 0;
size = 0;
hMutex.ReleaseMutex();
}
public int getsize()
{
int ret = 0;
hMutex.WaitOne();
ret = size;
hMutex.ReleaseMutex();
return ret;
}
//void move()
//{
//}
public void push( byte[] data, int len)
{
hMutex.WaitOne();
Array.Copy(zeroBuff, 0, packet, packetsize * first, packetsize);
Array.Copy(data, 0, packet, packetsize * first, packetsize >= len ? len : packetsize);
first = (first + 1) % packetnum;
if (size == packetnum)
{
tail = (tail + 1) % packetnum;
}
else
{
size++;
}
hMutex.ReleaseMutex();
}
public int GetPacketSize()
{
return packetsize;
}
}
实现Udpclient端,注意,接收SocketReceive中必须用try catch来处理可能发生的异常,否则会导致跳出循环。如在没打开远端的情况下,发送send
using UnityEngine;
using System.Collections;
//引入库
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System;
/*
*
*
*
* /
/**/
public class UdpClient : MonoBehaviour
{
string editString = "hello world"; //编辑框文字
//以下默认都是私有的成员
Socket socket; //目标socket
EndPoint serverEnd; //服务端
IPEndPoint ipEnd; //服务端端口
IPEndPoint ipLocal; //本地端口
string recvStr; //接收的字符串
string sendStr; //发送的字符串
byte[] recvData = new byte[1024]; //接收的数据,必须为字节
byte[] sendData = new byte[1024]; //发送的数据,必须为字节
int recvLen; //接收的数据长度
Thread connectThread; //连接线程
CQuene mQuene;
//初始化
void InitSocket(string remoteIp, int remotePort, string localIp, int localPort)
{
mQuene = new CQuene(10, 2048, "UdpClientMutex");
//定义连接的服务器ip和端口,可以是本机ip,局域网,互联网
ipEnd = new IPEndPoint(IPAddress.Parse(remoteIp), remotePort);
//定义套接字类型,在主线程中定义
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
ipLocal = new IPEndPoint(IPAddress.Parse(localIp), localPort);
socket.Bind(ipLocal);
//socket.Blocking = false;
/////////////////////////////////////////////////////////////////////////////////////////////////
int val = -6;
byte[] retArr = UsefulFunc.IntToBytes(val);
int retVal = UsefulFunc.BytesToInt(retArr);
retArr = UsefulFunc.IntToBytes(310);
retVal = UsefulFunc.BytesToInt(retArr);
/////////////////////////////////////////////////////////////////////////////////////////////////
//定义服务端
IPEndPoint sender = new IPEndPoint(IPAddress.Parse(remoteIp), remotePort);
serverEnd = (EndPoint)sender;
print("waiting for sending UDP dgram");
//建立初始连接,这句非常重要,第一次连接初始化了serverEnd后面才能收到消息
//SocketSend("hello");
//开启一个线程连接,必须的,否则主线程卡死
connectThread = new Thread(new ThreadStart(SocketReceive));
connectThread.Start();
}
void SocketSend(string sendStr)
{
//清空发送缓存
sendData = new byte[1024];
//数据类型转换
sendData = Encoding.ASCII.GetBytes(sendStr);
//发送给指定服务端
int len = socket.SendTo(sendData, sendData.Length, SocketFlags.None, ipEnd);
bool connected = socket.Connected;
Debug.Log("socket send len:" + len+" connected:"+connected);
}
//服务器接收
void SocketReceive()
{
//进入接收循环
while (true)
{
try
{
//对data清零
recvData = new byte[1024];
//获取客户端,获取服务端端数据,用引用给服务端赋值,实际上服务端已经定义好并不需要赋值
recvLen = socket.ReceiveFrom(recvData, ref serverEnd);
if (recvLen > 0)
{
//print("message from: " + serverEnd.ToString()); //打印服务端信息
PushRecv(recvData, recvLen);
//byte[] strByte = Bit
//输出接收到的数据
//recvStr = Encoding.ASCII.GetString(recvData, 0, recvLen);
//print(recvStr);
}
}
catch(Exception ex)
{
Debug.Log("recv:"+ex.Message);
}
}
}
//连接关闭
void SocketQuit()
{
//关闭线程
if (connectThread != null)
{
connectThread.Interrupt();
connectThread.Abort();
}
//最后关闭socket
if (socket != null)
socket.Close();
}
// Use this for initialization
void Start()
{
string remoteIp = "127.0.0.1";
string localIp = "127.0.0.1";
int remotePort = 8002;
int localPort = 8001;
InitSocket(remoteIp, remotePort, localIp, localPort); //在这里初始化
}
void OnGUI()
{
GUIStyle stype = new GUIStyle();
stype.fontSize = 40;
editString = GUI.TextField(new Rect(300, 350, 100, 40), editString, stype);
if (GUI.Button(new Rect(300, 390, 100, 40), "send"))
SocketSend(editString);
}
// Update is called once per frame
void Update()
{
byte[] recv = PopRecv();
if( recv != null )
{
//输出接收到的数据
recvStr = Encoding.ASCII.GetString(recv, 0, recv.Length);
Debug.Log(recvStr);
}
}
void OnApplicationQuit()
{
SocketQuit();
}
void PushRecv(byte[] datas, int len)
{
if(len+4> mQuene.GetPacketSize())
{
Debug.Log("PushRecv数据溢出!!");
return;
}
byte[] retBuff = new byte[len + 4];
UsefulFunc.IntToBytes(ref retBuff, len, 0);
Array.Copy(datas, 0, retBuff, 4, len);
mQuene.push(retBuff, len + 4);
}
byte[] PopRecv()
{
byte[] recvBuff = mQuene.getvalid();
if( recvBuff==null )
{
return null;
}
int iVal = UsefulFunc.BytesToInt(recvBuff);
if( iVal <= 0 || iVal >= mQuene.GetPacketSize())
{
return null;
}
byte[] retBuff = new byte[iVal];
Array.Copy(recvBuff, 4, retBuff, 0, iVal);
Debug.Log("PopRecv:" + iVal);
return retBuff;
}
}
注:UsefulFunc类主要用于定义一些公共的实现
class UsefulFunc
{
static bool is_hh_ll = true;
public static int ByteToInt(byte[] buff, int offset = 0)
{
uint uVal = 0;
int i = offset;
if (is_hh_ll)
{
uVal = (uint)(buff[i]) + (uint)(buff[i + 1] << 8) + (uint)(buff[i + 2] << 16) + (uint)(buff[i + 3] << 24);
}
else
{
uVal = (uint)(buff[i + 3]) + (uint)(buff[i + 2] << 8) + (uint)(buff[i + 1] << 16) + (uint)(buff[i] << 24);
}
return (int)uVal;
}
public static bool IntToBytes(ref byte[] buff, int val, int offset)
{
if (buff.Length < offset + 4)
{
return false;
}
uint uVal = (uint)val;
int i = offset;
if (is_hh_ll)
{
buff[i + 0] = (byte)(val & 0xFF);
buff[i + 1] = (byte)((val & 0xFF00) >> 8);
buff[i + 2] = (byte)((val & 0xFF0000) >> 16);
buff[i + 3] = (byte)((val & 0xFF000000) >> 24);
}
else
{
buff[i + 3] = (byte)(val & 0xFF);
buff[i + 2] = (byte)((val & 0xFF00) >> 8);
buff[i + 1] = (byte)((val & 0xFF0000) >> 16);
buff[i + 0] = (byte)((val & 0xFF000000) >> 24);
}
return true;
}
}