You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
7.3 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net.Sockets;
namespace ILRuntime.Runtime.Debugger
{
public class DebugSocket
{
private Socket _socket = null;
private bool _ready = false;
private const int MAX_BUFF_SIZE = 256 * 1024;
private const int HEAD_SIZE = 8;
private byte[] _headBuffer = new byte[HEAD_SIZE];
private byte[] _sendBuffer = new byte[64 * 1024];
//private MemoryPoolSafe<Package> _packagePool = new MemoryPoolSafe<Package>();
//private Package _currPackage = null;
private System.IO.MemoryStream _sendStream = null;
BinaryWriter bw;
const int RECV_BUFFER_SIZE = 1024;
private MemoryStream recvBuffer = new MemoryStream();
private int lastMsgLength = -1;
private byte[] socketAsyncBuffer = new byte[RECV_BUFFER_SIZE];
private SocketAsyncEventArgs saeArgs;
private object socketLockObj = new object();
private byte[] _sendHeaderBuffer = new byte[HEAD_SIZE];
public bool Disconnected { get { return _socket == null || !_socket.Connected; } }
public Action OnConnect { get; set; }
public Action OnConnectFailed { get; set; }
public Action OnClose { get; set; }
public Action<DebugMessageType, byte[]> OnReciveMessage { get; set; }
public DebugSocket()
{
_sendStream = new System.IO.MemoryStream(_sendBuffer);
bw = new BinaryWriter(_sendStream);
}
public DebugSocket(Socket _socket)
: this()
{
this._socket = _socket;
BeginReceive();
_ready = true;
}
public void Connect(string ip, int port)
{
Close();
Socket socket;
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.BeginConnect(ip, port, new AsyncCallback(onConnected), this);
_socket = socket;
_ready = false;
}
private void AsyncRecv_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
{
try
{
ReceivePayload(e.Buffer, e.BytesTransferred);
}
catch (Exception)
{
Close();
return;
}
}
else
{
Close();
return;
}
try
{
//继续接受数据
if (!_socket.ReceiveAsync(saeArgs))
{
AsyncRecv_Completed(null, saeArgs);
}
}
catch (Exception ex)
{
Close();
throw ex;
}
}
private void ReceivePayload(byte[] data, int length)
{
if (_socket == null)
return;
if (!_socket.Connected)
{
Close();
return;
}
//接受数据并拼接成message
byte[] msgBuff;
//写入缓存
recvBuffer.Position = recvBuffer.Length;
recvBuffer.Write(data, 0, length);
//如果长度有错,返回
if (lastMsgLength < 0 && recvBuffer.Length < 4)
{
msgBuff = null;
return;
}
recvBuffer.Position = 0;
BinaryReader br = new BinaryReader(recvBuffer);
//读取消息长度
if (lastMsgLength < 0)
{
lastMsgLength = br.ReadInt32() - 4;
if (lastMsgLength > MAX_BUFF_SIZE)
{
Close();
throw new Exception("Too long package length!");
}
}
int remaining = (int)(recvBuffer.Length - recvBuffer.Position);
//消息已经完整
while (remaining >= lastMsgLength && lastMsgLength > 0)
{
//读取一条消息
int type = br.ReadInt32();
msgBuff = br.ReadBytes(lastMsgLength - 4);
try
{
if (OnReciveMessage != null)
OnReciveMessage((DebugMessageType)type, msgBuff);
}
catch(Exception ex)
{
Console.WriteLine(ex.ToString());
}
lastMsgLength = -1;
remaining = (int)(recvBuffer.Length - recvBuffer.Position);
//保留剩余数据
if (remaining >= 4)
{
lastMsgLength = br.ReadInt32() - 4;
remaining -= 4;
if (lastMsgLength > MAX_BUFF_SIZE)
{
Close();
throw new Exception("Too long package length!");
}
}
}
remaining = (int)(recvBuffer.Length - recvBuffer.Position);
if (remaining > 0)
{
byte[] buffer = recvBuffer.GetBuffer();
Array.Copy(buffer, recvBuffer.Position, buffer, 0, remaining);
}
recvBuffer.Position = 0;
recvBuffer.SetLength(remaining);
}
private void onConnected(IAsyncResult result)
{
if (_socket.Connected)
{
_socket.EndConnect(result);
BeginReceive();
if (OnConnect != null)
OnConnect();
//ReceiveOnce();
}
else
{
if (OnConnectFailed != null)
OnConnectFailed();
}
}
void BeginReceive()
{
saeArgs = new SocketAsyncEventArgs();
saeArgs.Completed += AsyncRecv_Completed;
saeArgs.SetBuffer(socketAsyncBuffer, 0, socketAsyncBuffer.Length);
_socket.ReceiveAsync(saeArgs);
_ready = true;
}
//len type msg
public void Send(DebugMessageType type, byte[] buffer, int len)
{
if (!_ready)
return;
//timeStamp = UnityEngine.Time.realtimeSinceStartup;
_sendStream.Position = 0;
bw.Write(len + HEAD_SIZE);
bw.Write((int)type);
bw.Write(buffer, 0, len);
int totalLen = (int)_sendStream.Position;
RawSend(_socket, _sendBuffer, totalLen);
//_socket.Send(_sendBuffer, len, SocketFlags.None);
}
private void RawSend(Socket sock, byte[] buf, int end)
{
if (sock == null)
return;
if (end < 0)
end = buf.Length;
sock.Send(buf, end, SocketFlags.None);
}
public void Close()
{
if (_socket == null || !_ready)
return;
if (saeArgs != null)
saeArgs.Dispose();
_socket.Close();
_socket = null;
_ready = false;
if (OnClose != null)
{
OnClose();
}
}
}
}