unity3d的网络套接字SOCKET模块使用
2019/6/12 点击:
使用方法简单:
1、新建一个空物体把NetWork挂载上,2、填上ip和prot,3、调用Connet方法;
/*
UNITY3D 网络组件,它是单例模式。
通过Network开启和关闭网络;
消息订阅器MsgEvent管理服务端发来的消息
*/
using UnityEngine;
using Assets.Scripts.Events;
using Assets.Scripts.Util;
using Assets.Scripts.Net;
using System;
public enum NetMsgType
{
////// 新消息
///newMsg = -4,
////// 连接服务中断
///interrupt = -3,
////// 请求错误
///error = -2,
////// 连接成功
///complete = -1,
////// 服务端握手响应
///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; }
////// 网络组件实例
///public static Network Server { get; private set; }
private SocketTcp socket;
public string ip = "";
public int prot;
void Awake()
{
Server = this;
}
void Start()
{
}
////// 向服务端发送数据
//////协议接口类型///预留///要发送的数据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封装了一个轻量通信协议,以8个字节为头部(整型):无符号4字节长度(包括头部8字节)、消息类型无符号2字节、预留无符号2字节。
使用异步方法兼容hololens的uwp平台。消息类型自定义,协议的数据包格式在注释有说。 */
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,
////// 请求连接服务器时发生错误
///CONNET_IOERROT,
////// 连接中断
///CONNET_ERROT,
////// 收到消息
///CONNET_MSG
}
public class SocketTcp : EventDispatch{
////// 头部字节
///public const int head_size = 8;
////// 是否使用小端
///public const bool IsLittleEndian = true;
bool _activity = false;
////// 是否已启用
///public bool Activity
{
get { return _activity; }
}
////// 接受的消息,队列
///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);//设置回调方法
connetedSaea.RemoteEndPoint = new IPEndPoint(IPAddress.Parse(ip), port); //设置远端连接节点,一般用于接收消息
sendSaea = new SocketAsyncEventArgs();
//连接到服务器
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);//设置回调方法
//codeMsg.Enqueue(1);
//连接后开始从服务器读取网络消息
socket.ReceiveAsync(ReceiveSaea);
}
int fragmentLen;
byte[] fragment;
////// 回调读取网络数据、检查是否断线。
/////////private void ReceiveCall(object sender, SocketAsyncEventArgs e)
{
fragmentLen = e.BytesTransferred;//调用这个函数来结束本次接收并返回接收到的数据长度。
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);//这个函数用来关闭客户端连接
_activity = false;
socketState = true;
Debug.Log("中断,关闭连接");
return;
}
}
////// 发送字节流
//////public void Send(ushort type, ushort error, ByteArray data)
{
uint len = (uint)data.Length + head_size;
//清空发送缓存
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.
//数据类型转换
//sendData = Encoding.ASCII.GetBytes(sendStr);
//发送
sendSaea.SetBuffer(sendData, 0, sendData.Length);
socket.SendAsync(sendSaea);
}
////// 主线程每帧调用以拿取数据
///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();
//后关闭服务器
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;
}
}
}
}
- 上一篇:UNITY3D使用SHADER给顶点设置颜色 2019/6/12
- 下一篇:Unity3d网络通信 - NetWork组件使用 2019/5/28
