unity3d的網絡套接字SOCKET模塊使用
2019/6/12 點擊:
使用方法簡單:
1、新建一個空物體把NetWork掛載上,2、填上ip和prot,3、調用Connet方法(fǎ);
/*
UNITY3D 網絡組件,它是單例模式。
通過Network開啟和(hé)關閉網絡;
消息訂閱器MsgEvent管理服務端發來的消息(xī)
*/
using UnityEngine;
using Assets.Scripts.Events;
using Assets.Scripts.Util;
using Assets.Scripts.Net;
using System;public enum NetMsgType
{
////// 新消息
///newMsg = -4,
////// 連接服務中斷
///interrupt = -3,
////// 請(qǐng)求錯誤
///error = -2,
////// 連接(jiē)成(chéng)功(gōng)
///complete = -1,
////// 服(fú)務端握手響應
///state = 1
}
public class Network : MonoBehaviour
{
////// 網絡消息廣播,當服務端有消息發來是通過它廣播
///public static readonly EventDispatchMsgEvent = new EventDispatch();
public static bool IsConnet { get; private set; }
public static bool IsActive { get; private set; }
////// 網絡(luò)組(zǔ)件實例
///public static Network Server { get; private set; } private SocketTcp socket;
public string ip = "";
public int prot;
void Awake()
{
Server = this;
}
void Start()
{
}
////// 向服務端發送數據(jù)
//////協議接口類(lèi)型///預(yù)留///要發送的數據public void outCall(ushort type, ushort error, ByteArray data)
{
if (IsConnet)
{
socket.Send(type, error, data);
}
}
public void Connet()
{
if (IsActive == false)
{
IsActive = true;
socket = new SocketTcp(ip, prot);
socket.AddListener(NetEvent.CONNETED, Conneted);
socket.AddListener(NetEvent.CONNET_IOERROT, ConnetIOError);
socket.AddListener(NetEvent.CONNET_ERROT, ConnetError);
socket.AddListener(NetEvent.CONNET_MSG, MsgHandler); socket.Start();
}
}
private void Conneted(EventData data)
{
IsConnet = true;
MsgEvent.Dispatch(NetMsgType.complete);
}
void ConnetIOError(EventData data)
{
IsConnet = false;
IsActive = false;
MsgEvent.Dispatch(NetMsgType.error);
}
void ConnetError(EventData data)
{
IsConnet = false;
IsActive = false;
MsgEvent.Dispatch(NetMsgType.interrupt);
}
void MsgHandler(EventData data)
{
BucketItem msg = (BucketItem)data.data;
msg.ByteArray.Position = 0;
if (msg.Error > 0)
{
Debug.Log("網絡錯誤:" + msg.Error);
return;
}
if (Enum.IsDefined(typeof(NetMsgType), msg.Type))
{
MsgEvent.Dispatch((NetMsgType)msg.Type, msg);
}
else
{
Debug.Log("未定義網絡消息:" + msg.Type);
}
}
public void Disconnect()
{
IsConnet = false;
IsActive = false;
socket.RemoveListener(NetEvent.CONNETED, Conneted);
socket.RemoveListener(NetEvent.CONNET_IOERROT, ConnetIOError);
socket.RemoveListener(NetEvent.CONNET_ERROT, ConnetError);
socket.RemoveListener(NetEvent.CONNET_MSG, MsgHandler);
socket.Destroy();
socket = null;
}
void FixedUpdate()
{ }
void Update()
{
if (socket != null) socket.Updata();
}
//程序退出則關閉連接
void OnApplicationQuit()
{
if (socket != null) socket.Destroy();
}
}
/*
socketTcp封裝了一個輕量通信(xìn)協議,以8個(gè)字節為頭部(整(zhěng)型):無符號4字節長(zhǎng)度(包(bāo)括頭部8字節)、消(xiāo)息類(lèi)型無符號2字節、預留無符號2字節。
使用異步方法兼容hololens的uwp平台。消(xiāo)息類型自定義,協議的數據包格式(shì)在注釋(shì)有說。 */
using Assets.Scripts.Events;
using System;
using System.Collections;
using Assets.Scripts.Util;
using UnityEngine;
using System.Collections.Generic;
#if !UWP
using System.Net;
using System.Net.Sockets;
#else
using Windows.Networking.Sockets;
using Windows.Networking.Connectivity;
using Windows.Networking;
#endif
namespace Assets.Scripts.Net
{
public enum NetEvent{
////// 連接建立
///CONNETED,
////// 請求(qiú)連(lián)接服務器時發生錯誤
///CONNET_IOERROT,
////// 連接中斷
///CONNET_ERROT,
////// 收到消息
///CONNET_MSG
}
public class SocketTcp : EventDispatch{
////// 頭部字節
///public const int head_size = 8;
////// 是(shì)否使用小端
///public const bool IsLittleEndian = true;
bool _activity = false;
////// 是否已啟用
///public bool Activity
{
get { return _activity; }
}
////// 接受的消(xiāo)息,隊列(liè)
///private QueueMsgList;
private QueuecodeMsg;
public int port { get; private set; }
public string ip { get; private set; }
Socket socket;
SocketAsyncEventArgs ReceiveSaea;
SocketAsyncEventArgs sendSaea;
byte[] sendData;
////// 允許單個數據包30720字節
///
///const int RECV_LEN = 30720;
byte[] recv_buf = new byte[RECV_LEN];
Bucket bucket;
bool socketState=false;
public SocketTcp(string ip, int port)
{
this.port = port;
this.ip = ip;
bucket = new Bucket();
codeMsg = new Queue();
MsgList = new Queue();
}
private SocketAsyncEventArgs connetedSaea;
////// 發起鏈接請求
/// 會調度CONNETED或CONNET_IOERROT事件
///public void Start()
{
if (socket==null)
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
connetedSaea = new SocketAsyncEventArgs();
connetedSaea.Completed += new EventHandler(connetedCall);//設置回調(diào)方法
connetedSaea.RemoteEndPoint = new IPEndPoint(ipadsdress.Parse(ip), port); //設置(zhì)遠端連接節點,一般用於接收消息
sendSaea = new SocketAsyncEventArgs();
//連接(jiē)到(dào)服務器
socket.ConnectAsync(connetedSaea);
}
catch (Exception e)
{
Debug.Log(e);
Dispatch(NetEvent.CONNET_IOERROT);
}
}
}
private void connetedCall(object sender, SocketAsyncEventArgs e)
{
_activity = true;
codeMsg.Enqueue(NetEvent.CONNETED);
ReceiveSaea = new SocketAsyncEventArgs();
ReceiveSaea.SetBuffer(recv_buf, 0, recv_buf.Length);//設置緩衝區
ReceiveSaea.Completed += new EventHandler(ReceiveCall);//設置回調(diào)方法
//codeMsg.Enqueue(1);
//連接後開始從服務器讀取網絡消息(xī)
socket.ReceiveAsync(ReceiveSaea);
}
int fragmentLen;
byte[] fragment;
////// 回調讀取網絡數據、檢查是否(fǒu)斷線。
/////////private void ReceiveCall(object sender, SocketAsyncEventArgs e)
{
fragmentLen = e.BytesTransferred;//調用這個函數來結束本次接收並返回接收到的數據長度(dù)。
if (fragmentLen > 0)
{
fragment = new byte[fragmentLen];
Array.Copy(recv_buf, 0, fragment, 0, fragmentLen);
Queuearr = bucket.Infuse(fragment);
while (arr.Count > 0)
{
MsgList.Enqueue(arr.Dequeue());
}
socket.ReceiveAsync(ReceiveSaea);
}
else
{
ReceiveSaea.Dispose();
bucket.Reset();
socket.Shutdown(SocketShutdown.Receive);//這個函數用來關閉客(kè)戶(hù)端連(lián)接
_activity = false;
socketState = true;
Debug.Log("中斷,關閉連接");
return;
}
}
////// 發送字節流(liú)
//////public void Send(ushort type, ushort error, ByteArray data)
{
uint len = (uint)data.Length + head_size;
//清空發送(sòng)緩存
sendData = new byte[len];
ByteHelp.WriteNumber(len, ref sendData, 0, IsLittleEndian);
ByteHelp.WriteNumber(type, ref sendData, 4, IsLittleEndian);
ByteHelp.WriteNumber(error, ref sendData, 6, IsLittleEndian);
if (data.Length > 0)
{
Array.Copy(data.Data, 0, sendData, head_size, data.Length);
}
//sendData.
//數(shù)據(jù)類型轉換
//sendData = Encoding.ASCII.GetBytes(sendStr);
//發送
sendSaea.SetBuffer(sendData, 0, sendData.Length);
socket.SendAsync(sendSaea);
}
////// 主線程每(měi)幀調用以拿(ná)取數據
///public void Updata()
{
while (codeMsg.Count > 0)
{
Dispatch(codeMsg.Dequeue());
}
while (MsgList.Count > 0)
{
Dispatch(NetEvent.CONNET_MSG, MsgList.Dequeue());
}
if (socketState)
{
//Debug.Log("連接丟失,是否要重連");
socketState = false;
Dispatch(NetEvent.CONNET_ERROT);
}
}
public void Destroy()
{
base.Dispose();
//後關(guān)閉服務器
if (socket != null && socket.Connected)
{
//this.socket.Disconnect(true);
//this.socket.Shutdown(SocketShutdown.Both);
//socket.Dispose();
socket.Shutdown(SocketShutdown.Receive);
socket.Shutdown(SocketShutdown.Send);
ReceiveSaea.Dispose();
}
bucket.Reset();
MsgList.Clear();
codeMsg.Clear();
socketState = false;
if (sendSaea != null) connetedSaea = null;
if(sendSaea!=null) sendSaea.Dispose();
sendSaea = null;
if (_activity)
{
_activity = false;
}
}
}
}- 上一篇(piān):UNITY3D使用SHADER給頂點設置顏色 2019/6/12
- 下一篇:Unity3d網絡(luò)通信 - NetWork組件使用 2019/5/28
