当前位置:网站首页>TCP framework___ Unity
TCP framework___ Unity
2022-07-07 15:53:00 【Le_ Sam】
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine;
using System.Text;
namespace Core
{
public class Protocal
{
public const int Connect = -1; // Connect to server
public const int Exception = -2; // Abnormal dropped line
public const int Disconnect = -3; // Normal disconnection
}
enum PACKET_TYPE
{ // Packet format ( Rules set by the server , The client sends strictly according to the format / receive ),PackLen Used to identify the subsequent package length ,Place Is an invalid placeholder ,Type Is the type of package (PACKET_TYPE),Seq The function is unknown. The default is 0,Code Is the error code ,Body For the body of the package
PUSH_TYPE = 0, // PackLen【2byte】,Place【1byte】,Type【1byte】,Body【 Maximum 4096byte】
REQUSET_TYPE, // PackLen【2byte】,Place【1byte】,Type【1byte】,Seq【2byte】,Body【 Maximum 4096byte】
RESPONSE_TYPE, // PackLen【2byte】,Place【1byte】,Type【1byte】,Seq【2byte】,Code( Error code )【2byte】,Body【 Maximum 4096byte】
PING_TYPE, // PackLen【2byte】,Place【1byte】,Type【1byte】,Seq【1byte】PS: Heartbeat sending
PONG_TYPE // PackLen【2byte】,Place【1byte】,Type【1byte】,Seq【1byte】PS: Heartbeat back
};
// Give Way byte[] Press into lua string Not an array userdata
// You can also use LuaByteBufferAttribute To mark byte[]
public struct LuaByteBuffer
{
public LuaByteBuffer(IntPtr source, int len)
: this()
{
buffer = new byte[len];
Length = len;
Marshal.Copy(source, buffer, 0, len);
}
public LuaByteBuffer(byte[] buf)
: this()
{
buffer = buf;
Length = buf.Length;
}
public LuaByteBuffer(byte[] buf, int len)
: this()
{
buffer = buf;
Length = len;
}
public LuaByteBuffer(System.IO.MemoryStream stream)
: this()
{
buffer = stream.GetBuffer();
Length = (int)stream.Length;
}
public static implicit operator LuaByteBuffer(System.IO.MemoryStream stream)
{
return new LuaByteBuffer(stream);
}
public byte[] buffer;
public int Length
{
get;
private set;
}
}
// Byte Data structures , It should be noted that each time data is written in order
public class ByteBuffer
{
MemoryStream stream = null;
BinaryWriter writer = null;
BinaryReader reader = null;
public ByteBuffer()
{
stream = new MemoryStream();
writer = new BinaryWriter(stream);
}
public ByteBuffer(byte[] data)
{
if (data != null)
{
stream = new MemoryStream(data);
reader = new BinaryReader(stream);
}
else
{
stream = new MemoryStream();
writer = new BinaryWriter(stream);
}
}
public void Close()
{
if (writer != null)
{
writer.Close();
}
if (reader != null)
{
reader.Close();
}
stream.Close();
writer = null;
reader = null;
stream = null;
}
public void WriteByte(byte v)
{
writer.Write(v);
}
public void WriteInt(int v)
{
writer.Write((int)v);
}
public void WriteShort(ushort v)
{
writer.Write((ushort)v);
}
public void WriteLong(long v)
{
writer.Write((long)v);
}
public void WriteFloat(float v)
{
byte[] bytes = BitConverter.GetBytes(v);
Array.Reverse(bytes);
writer.Write(BitConverter.ToSingle(bytes, 0));
}
public void WriteDouble(double v)
{
byte[] bytes = BitConverter.GetBytes(v);
Array.Reverse(bytes);
writer.Write(BitConverter.ToDouble(bytes, 0));
}
public void WriteString(string v)
{
byte[] bytes = Encoding.UTF8.GetBytes(v);
writer.Write((ushort)bytes.Length);
writer.Write(bytes);
}
public void WriteBytes(byte[] v)
{
writer.Write((int)v.Length);
writer.Write(v);
}
public void WriteBytesNoLen(byte[] v)
{
writer.Write(v);
}
public void WriteBuffer(LuaByteBuffer strBuffer)
{
WriteBytes(strBuffer.buffer);
}
public byte ReadByte()
{
return reader.ReadByte();
}
public int ReadInt()
{
return (int)reader.ReadInt32();
}
public ushort ReadShort()
{
return (ushort)reader.ReadInt16();
}
public long ReadLong()
{
return (long)reader.ReadInt64();
}
public float ReadFloat()
{
byte[] bytes = BitConverter.GetBytes(reader.ReadSingle());
Array.Reverse(bytes);
return BitConverter.ToSingle(bytes, 0);
}
public double ReadDouble()
{
byte[] bytes = BitConverter.GetBytes(reader.ReadDouble());
Array.Reverse(bytes);
return BitConverter.ToDouble(bytes, 0);
}
public string ReadString()
{
ushort len = ReadShort();
byte[] buffer = new byte[len];
buffer = reader.ReadBytes(len);
return Encoding.UTF8.GetString(buffer);
}
public byte[] ReadBytes()
{
int len = ReadInt();
return reader.ReadBytes(len);
}
public LuaByteBuffer ReadBuffer()
{
byte[] bytes = ReadBytes();
return new LuaByteBuffer(bytes);
}
public byte[] ToBytes()
{
writer.Flush();
return stream.ToArray();
}
public void Flush()
{
writer.Flush();
}
}
public class SocketClient
{
private TcpClient client = null;
private NetworkStream outStream = null; // Network flow used to send data to the server
private MemoryStream memStream; // Used to process the memory stream that receives data from the server ,
private BinaryReader reader;
private const int HEAD_BASE_LEN = 2;
private const int MAX_READ = 8192;
private byte[] byteBuffer = new byte[MAX_READ];
private int iSocketPort = 0; //Socket Server port
private string iSocketAddress = string.Empty; //Socket Server address
private IAsyncResult onReadAsyncResult;
private static SocketClient _SocketClient;
private int ConnectionStatus = -1;
private readonly static byte[] mConnLock = new byte[0]; // Link lock
public static SocketClient GetSocketClient()
{
return _SocketClient;
}
public static void SetSocketClient(SocketClient socketClient)
{
_SocketClient = socketClient;
}
public SocketClient()
{
memStream = new MemoryStream();
reader = new BinaryReader(memStream);
SocketClient.SetSocketClient(this);
}
~SocketClient()
{
Close();
reader.Close();
memStream.Close();
}
// Connect
public void Connect(string addr, int port)
{
iSocketAddress = addr;
iSocketPort = port;
ReConnect();
}
// Reconnection
private void ReConnect()
{
try
{
IPAddress ipAddress;
if (!ParseIpFromHost(iSocketAddress, out ipAddress))
{
OnDisconnected(Protocal.Exception, string.Format("Parse ip from {0} failed", iSocketAddress));
return;
}
client = new TcpClient(ipAddress.AddressFamily)
{
SendTimeout = 10000,
ReceiveTimeout = 10000,
NoDelay = true
};
// Initiate a link
ConnectionStatus = -1;
client.BeginConnect(iSocketAddress, iSocketPort, new AsyncCallback(OnConnect), null);
// Connection timeout
Thread timeout = new Thread(CheckConnectTimeout);
timeout.IsBackground = true;
timeout.Start();
}
catch (Exception e)
{
Debug.Log("Socket ReConnect");
OnDisconnected(Protocal.Exception, e);
}
}
// Link timeout detection
private void CheckConnectTimeout()
{
lock (mConnLock)
{
Monitor.Wait(mConnLock, 10000);
if (!client.Connected && ConnectionStatus < 0)
{
OnDisconnected(Protocal.Exception, new TimeoutException("Socket Connect Timeout."));
}
}
}
// Exception handling
private void OnDisconnected(int protocal, Exception e)
{
Close();
PostMessage(protocal);
if (e is SocketException)
{
Debug.Log(e.ToString() + " SocketErrorCode: " + ((SocketException)(e)).ErrorCode);
}
else
{
Debug.Log(e.ToString());
}
}
// Exception handling
private void OnDisconnected(int protocal, string msg)
{
Close();
PostMessage(protocal);
Debug.Log("SocketErrorCode: " + msg);
}
private static bool ParseIpFromHost(string host, out IPAddress address)
{
address = null;
try
{
if (!IPAddress.TryParse(host, out address))
{
var entries = Dns.GetHostEntry(host);
var addressLst = entries.AddressList.ToList();
address = addressLst.FirstOrDefault(x => x.AddressFamily == AddressFamily.InterNetworkV6) ?? addressLst.First();
}
return true;
}
catch (Exception e)
{
Debug.Log(e);
return false;
}
}
private void OnConnect(IAsyncResult asr)
{
memStream.SetLength(0);
try
{
lock (mConnLock)
{
// If CheckConnectTimeout It's overtime , This will turn client It's empty , Don't go down
if (client == null)
{
return;
}
// Connection status
ConnectionStatus = client.Connected ? 1 : 0;
// The connection fails
if (ConnectionStatus == 0)
{
PostMessage(Protocal.Exception); // PostMessage towards Lua End send message
return;
}
// Successful connection
outStream = client.GetStream();
onReadAsyncResult = client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
PostMessage(Protocal.Connect);
Monitor.PulseAll(mConnLock);
}
}
catch (Exception e)
{
OnDisconnected(Protocal.Exception, e);
}
}
private void OnRead(IAsyncResult asr)
{
if (client == null || !client.Connected)
{
return;
}
int bytesRead = 0;
try
{
lock (client.GetStream())
{ // Read byte stream to buffer
bytesRead = client.GetStream().EndRead(asr);
}
if (bytesRead < 1)
{ // There is a problem with the size of the bag , Disconnection treatment
OnDisconnected(Protocal.Disconnect, "bytesRead < 1");
return;
}
// Analyze packet content , Throw it to the logic layer
OnReceive(byteBuffer, bytesRead);
// Analysis finished , Listen again for new messages from the server
lock (client.GetStream())
{ // Empty array
Array.Clear(byteBuffer, 0, byteBuffer.Length);
onReadAsyncResult = client.GetStream().BeginRead(byteBuffer, 0, MAX_READ, new AsyncCallback(OnRead), null);
}
}
catch (Exception e)
{
OnDisconnected(Protocal.Exception, e);
}
}
// Send data to the server
private void WriteMessage(byte[] message)
{
if (client == null || !client.Connected)
{
return;
}
try
{
outStream.BeginWrite(message, 0, message.Length, new AsyncCallback(OnWrite), null);
}
catch (Exception e)
{
OnDisconnected(Protocal.Exception, e);
}
}
private void OnWrite(IAsyncResult asr)
{
if (client == null || !client.Connected)
{
return;
}
try
{
outStream.EndWrite(asr);
}
catch (Exception e)
{
OnDisconnected(Protocal.Exception, e);
}
}
// send out json Format data . Different types of packages , The data format is different , According to demand , Details refer to PACKET_TYPE
public void Send(int type, int seq, string msg)
{
//Debug.Log("Send type: " + type.ToString() + " seq: " + seq.ToString() + " msg: " + msg);
switch (type)
{
case (int)PACKET_TYPE.REQUSET_TYPE:
SendRequset(type, seq, msg);
break;
case (int)PACKET_TYPE.PING_TYPE:
SendPing(type, seq);
break;
default:
Debug.Log("SocketClientEx ==> The type is not supported " + msg);
return;
}
}
private void SendRequset(int type, int seq, string msg)
{
ByteBuffer buf = new ByteBuffer();
byte[] msgByte = Encoding.UTF8.GetBytes(msg);
buf.WriteShort((ushort)(msgByte.Length + 4)); // Place+Type+Seq = 4
buf.WriteByte(0); // Place Invalid placeholder
buf.WriteByte((byte)type); //1
buf.WriteShort((ushort)seq); //0
buf.WriteBytesNoLen(msgByte);
//Debug.Log(" Total length " + buf.ToBytes().Length + " msg length " + msgByte.Length);
WriteMessage(buf.ToBytes());
}
private void SendPing(int type, int seq)
{
ByteBuffer buf = new ByteBuffer();
buf.WriteShort(3); // Place+Type+Seq = 3
buf.WriteByte(0); // Place Invalid placeholder
buf.WriteByte((byte)type); //3
buf.WriteByte((byte)seq); //0
WriteMessage(buf.ToBytes());
}
// Data analysis
private void OnReceive(byte[] bytes, int length)
{
// Write the read bytes at the end of the stream
memStream.Seek(0, SeekOrigin.End);
memStream.Write(bytes, 0, length);
// The flow pointer is reset to the head
memStream.Seek(0, SeekOrigin.Begin);
// Judge whether the current stream length is greater than the packet length ( Bag length 2 byte )
while (RemainingBytes() >= 2)
{
// front 2 Byte is the header , Indicate the subsequent package length
int messageLen = (int)reader.ReadUInt16();
long curover = RemainingBytes();
//Debug.Log(" Now read the length " + curover + ", The length of the packet " + messageLen);
// When the received data is larger than the packet length , Indicates that the current inclusion data has been received
if (curover >= messageLen)
{
// Temporary memory stream , from reader Extract the required bytes
MemoryStream ms = new MemoryStream();
BinaryWriter writer = new BinaryWriter(ms);
// Only get the data of the current packet length
writer.Write(reader.ReadBytes(messageLen));
ms.Seek(0, SeekOrigin.Begin);
OnReceivedMessage(ms);
}
else
{
// When the received data is incomplete , Ignore this execution , And back out the pointer , Wait for the next callback
memStream.Position = memStream.Position - 2;
break;
}
}
int leftovers = (int)RemainingBytes();
//Debug.Log(" End of analysis , The remaining bytes " + leftovers);
// Take out the remaining bytes , And reset the memory stream , To write
byte[] leftover = reader.ReadBytes(leftovers);
memStream.SetLength(0); //Clear
memStream.Write(leftover, 0, leftover.Length);
}
// The difference between the query stream length and the current stream pointer , It is used to judge whether the current flow meets the needs
private long RemainingBytes()
{
return memStream.Length - memStream.Position;
}
// Parse the packet contents ( Except package length 2 Contents other than bytes )
private void OnReceivedMessage(MemoryStream ms)
{
if (ms.Length >= HEAD_BASE_LEN)
{
BinaryReader r = new BinaryReader(ms);
int place = r.ReadByte(); // Place【1byte】
int type = r.ReadByte(); // Type【1byte】
int seq = 0;
int code = 0;
// response type , Need to parse again 4 Bytes are the body
if (type == (int)PACKET_TYPE.RESPONSE_TYPE)
{
seq = r.ReadUInt16(); // Seq【2byte】
code = r.ReadUInt16(); // Code【2byte】
}
// pong type , Heartbeat back
else if (type == (int)PACKET_TYPE.PONG_TYPE)
{
seq = r.ReadByte(); // Seq【1byte】
}
if (ms.Length - ms.Position > 0)
{
byte[] body = r.ReadBytes((int)(ms.Length - ms.Position));
LuaByteBuffer buffer = new LuaByteBuffer(body);
// The body of the package sent by the server is json, Convert directly to string, It depends on the demand
Debug.Log("Received Msg " + Encoding.UTF8.GetString(buffer.buffer));
PostMessage(0, buffer);
}
}
}
// Callback message to client , undetermined ,cmd Is the command word ,buffer Is the actual data
protected void PostMessage(int cmd, object buffer = null)
{
// This interface is owned by the original project , Used to direct to lua End send message , hold proto2 Antisequential formation lua surface
// MessageCenter.Post(MessageNames.Socket, this, cmd, buffer);
}
public void Close()
{
if (onReadAsyncResult != null)
{
onReadAsyncResult.AsyncWaitHandle.Close();
onReadAsyncResult = null;
}
if (client != null)
{
if (client.Connected)
{
if (client.GetStream() != null)
{
client.GetStream().Dispose();
}
if (client.Client.Connected)
{
client.Client.Shutdown(SocketShutdown.Both);
}
client.Close();
}
client = null;
}
}
}
}
边栏推荐
- [quick start of Digital IC Verification] 23. AHB sramc of SystemVerilog project practice (3) (basic points of AHB protocol)
- 过度依赖补助,大客户收款难,冲刺“国产数据库第一股”的达梦后劲有多足?
- 神经网络c语言中的指针是怎么回事
- How to deploy the super signature distribution platform system?
- Align individual elements to the right under flex layout
- 【数字IC验证快速入门】18、SystemVerilog学习之基本语法5(并发线程...内含实践练习)
- Three. JS introductory learning notes 19: how to import FBX static model
- unnamed prototyped parameters not allowed when body is present
- The "go to definition" in VS2010 does not respond or prompts the solution of "symbol not found"
- 【數字IC驗證快速入門】20、SystemVerilog學習之基本語法7(覆蓋率驅動...內含實踐練習)
猜你喜欢

强化实时数据管理,英方软件助力医保平台安全建设
![[quick start of Digital IC Verification] 26. Ahb-sramc of SystemVerilog project practice (6) (basic points of APB protocol)](/img/7e/188e57ee026200478a6f61eb507c92.png)
[quick start of Digital IC Verification] 26. Ahb-sramc of SystemVerilog project practice (6) (basic points of APB protocol)

The difference between full-time graduate students and part-time graduate students!

10 schemes to ensure interface data security

numpy--疫情数据分析案例

HPDC smart base Talent Development Summit essay

Use of SVN

Create lib Library in keil and use lib Library

Streaming end, server end, player end

Spin animation of Cocos performance optimization
随机推荐
AE learning 01: AE complete project summary
Monthly observation of internet medical field in May 2022
Create lib Library in keil and use lib Library
保证接口数据安全的10种方案
[quickstart to Digital IC Validation] 20. Basic syntax for system verilog Learning 7 (Coverage Driven... Including practical exercises)
It's different for rich people to buy a house
Function: JS Click to copy content function
Ue4/ue5 multi thread development attachment plug-in download address
Align individual elements to the right under flex layout
Jacobo code coverage
When opening the system window under UE4 shipping, the problem of crash is attached with the plug-in download address
一大波开源小抄来袭
Use moviepy Editor clips videos and intercepts video clips in batches
【花雕体验】15 尝试搭建Beetle ESP32 C3之Arduino开发环境
Cocos creator collision and collision callback do not take effect
Points for attention in porting gd32 F4 series programs to gd32 F3 series
Annexb and avcc are two methods of data segmentation in decoding
Summary of knowledge points of xlua hot update solution
UE4 exports the picture + text combination diagram through ucanvasrendertarget2d
numpy--数据清洗