diff --git a/NFClientNet.cs b/NFClientNet.cs new file mode 100644 index 0000000..de9963d --- /dev/null +++ b/NFClientNet.cs @@ -0,0 +1,567 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace NFTCPClient +{ + public enum NFTCPClientState + { + Connecting, + Connected, + Disconnected + } + + public enum NFTCPEventType + { + None, + Connected, + Disconnected, + ConnectionRefused, + DataReceived + } + + public class NFSocketPacket + { + public byte[] bytes = null; + public int bytesCount = 0; + + public NFSocketPacket(byte[] bytes, int bytesCount) + { + this.bytes = bytes; + this.bytesCount = bytesCount; + } + + } + + public class NFTCPEventParams + { + public NFClientNet client = null; + public int clientID = 0; + public TcpClient socket = null; + public NFTCPEventType eventType = NFTCPEventType.None; + public string message = ""; + public NFSocketPacket packet = null; + + } + + class StructureTransform + { + static bool bBig = false;//defalut little + public static void Reverse(byte[] msg) + { + if (!bBig) + { + Array.Reverse(msg); + } + } + + public static void Reverse(byte[] msg, int nOffest, int nSize) + { + if (!bBig) + { + Array.Reverse(msg, nOffest, nSize); + } + } + + + public static bool SetEndian(bool bIsBig) + { + bBig = bIsBig; + return bBig; + } + + public static void ByteArrayToStructureEndian(byte[] bytearray, ref object obj, int startoffset) + { + int len = Marshal.SizeOf(obj); + IntPtr i = Marshal.AllocHGlobal(len); + byte[] temparray = (byte[])bytearray.Clone(); + + obj = Marshal.PtrToStructure(i, obj.GetType()); + + object thisBoxed = obj; + Type test = thisBoxed.GetType(); + int reversestartoffset = startoffset; + + foreach (var field in test.GetFields()) + { + object fieldValue = field.GetValue(thisBoxed); // Get value + + TypeCode typeCode = Type.GetTypeCode(fieldValue.GetType()); //Get Type + if (typeCode != TypeCode.Object) //Èç¹ûΪֵÀàÐÍ + { + Reverse(temparray, reversestartoffset, Marshal.SizeOf(fieldValue)); + reversestartoffset += Marshal.SizeOf(fieldValue); + } + else + { + reversestartoffset += ((byte[])fieldValue).Length; + } + } + try + { + Marshal.Copy(temparray, startoffset, i, len); + } + catch (Exception ex) { Console.WriteLine("ByteArrayToStructure FAIL: error " + ex.ToString()); } + obj = Marshal.PtrToStructure(i, obj.GetType()); + Marshal.FreeHGlobal(i); + } + + public static byte[] StructureToByteArrayEndian(object obj) + { + object thisBoxed = obj; + Type test = thisBoxed.GetType(); + + int offset = 0; + byte[] data = new byte[Marshal.SizeOf(thisBoxed)]; + + object fieldValue; + TypeCode typeCode; + byte[] temp; + + foreach (var field in test.GetFields()) + { + fieldValue = field.GetValue(thisBoxed); // Get value + + typeCode = Type.GetTypeCode(fieldValue.GetType()); // get type + + switch (typeCode) + { + case TypeCode.Single: // float + { + temp = BitConverter.GetBytes((Single)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(Single)); + break; + } + case TypeCode.Int32: + { + temp = BitConverter.GetBytes((Int32)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(Int32)); + break; + } + case TypeCode.UInt32: + { + temp = BitConverter.GetBytes((UInt32)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(UInt32)); + break; + } + case TypeCode.Int16: + { + temp = BitConverter.GetBytes((Int16)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(Int16)); + break; + } + case TypeCode.UInt16: + { + temp = BitConverter.GetBytes((UInt16)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(UInt16)); + break; + } + case TypeCode.Int64: + { + temp = BitConverter.GetBytes((Int64)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(Int64)); + break; + } + case TypeCode.UInt64: + { + temp = BitConverter.GetBytes((UInt64)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(UInt64)); + break; + } + case TypeCode.Double: + { + temp = BitConverter.GetBytes((Double)fieldValue); + StructureTransform.Reverse(temp); + Array.Copy(temp, 0, data, offset, sizeof(Double)); + break; + } + case TypeCode.Byte: + { + data[offset] = (Byte)fieldValue; + break; + } + default: + { + //System.Diagnostics.Debug.Fail("No conversion provided for this type : " + typeCode.ToString()); + break; + } + }; // switch + if (typeCode == TypeCode.Object) + { + int length = ((byte[])fieldValue).Length; + Array.Copy(((byte[])fieldValue), 0, data, offset, length); + offset += length; + } + else + { + offset += Marshal.SizeOf(fieldValue); + } + } // foreach + + return data; + } // Swap + }; + + public class NFClientNet + { + public NFNet net = null; + + public NFClientNet(NFNet xnet) + { + net = xnet; + Init(); + } + + void Init() + { + mxState = NFTCPClientState.Disconnected; + mxEvents = new Queue(); + mxMessages = new Queue(); + mxPackets = new Queue(); + } + // MonoBehaviour + private int bufferSize = 65536; + + private NFTCPClientState mxState; + private NetworkStream mxStream; + private StreamWriter mxWriter; + private StreamReader mxReader; + private Thread mxReadThread; + private TcpClient mxClient; + private Queue mxEvents; + private Queue mxMessages; + private Queue mxPackets; + + public bool IsConnected() + { + return mxState == NFTCPClientState.Connected; + } + + public NFTCPClientState GetState() + { + return mxState; + } + + public void Update() + { + + while (mxEvents.Count > 0) + { + lock (mxEvents) + { + NFTCPEventType eventType = mxEvents.Dequeue(); + + NFTCPEventParams eventParams = new NFTCPEventParams(); + eventParams.eventType = eventType; + eventParams.client = this; + eventParams.socket = mxClient; + + if (eventType == NFTCPEventType.Connected) + { + OnClientConnect(eventParams); + } + else if (eventType == NFTCPEventType.Disconnected) + { + OnClientDisconnect(eventParams); + + mxReader.Close(); + mxWriter.Close(); + mxClient.Close(); + + } + else if (eventType == NFTCPEventType.DataReceived) + { + lock (mxPackets) + { + eventParams.packet = mxPackets.Dequeue(); + + OnDataReceived(eventParams); + } + } + else if (eventType == NFTCPEventType.ConnectionRefused) + { + + } + } + } + } + + private void OnApplicationQuit() + { + Disconnect(); + } + + private void ConnectCallback(IAsyncResult ar) + { + try + { + + TcpClient tcpClient = (TcpClient)ar.AsyncState; + tcpClient.EndConnect(ar); + + SetTcpClient(tcpClient); + + } + catch (Exception e) + { + e.ToString(); + lock (mxEvents) + { + mxEvents.Enqueue(NFTCPEventType.ConnectionRefused); + } + + } + + } + + private void ReadData() + { + bool endOfStream = false; + + while (!endOfStream) + { + int bytesRead = 0; + byte[] bytes = new byte[bufferSize]; + try + { + bytesRead = mxStream.Read(bytes, 0, bufferSize); + } + catch (Exception e) + { + e.ToString(); + } + + if (bytesRead == 0) + { + + endOfStream = true; + + } + else + { + lock (mxEvents) + { + + mxEvents.Enqueue(NFTCPEventType.DataReceived); + } + lock (mxPackets) + { + mxPackets.Enqueue(new NFSocketPacket(bytes, bytesRead)); + } + + } + } + + mxState = NFTCPClientState.Disconnected; + + mxClient.Close(); + lock (mxEvents) + { + mxEvents.Enqueue(NFTCPEventType.Disconnected); + } + + } + + // Public + public void Connect(string hostname, int port) + { + if (mxState == NFTCPClientState.Connected) + { + return; + } + + mxState = NFTCPClientState.Connecting; + + mxMessages.Clear(); + mxEvents.Clear(); + + mxClient = new TcpClient(); + + mxClient.BeginConnect(hostname, + port, + new AsyncCallback(ConnectCallback), + mxClient); + + } + + public void Disconnect() + { + + mxState = NFTCPClientState.Disconnected; + + try { if (mxReader != null) mxReader.Close(); } + catch (Exception e) { e.ToString(); } + try { if (mxWriter != null) mxWriter.Close(); } + catch (Exception e) { e.ToString(); } + try { if (mxClient != null) mxClient.Close(); } + catch (Exception e) { e.ToString(); } + + } + + public void SendBytes(byte[] bytes) + { + SendBytes(bytes, 0, bytes.Length); + } + + public void SendBytes(byte[] bytes, int offset, int size) + { + + if (!IsConnected()) + return; + + mxStream.Write(bytes, offset, size); + mxStream.Flush(); + + } + + public void SetTcpClient(TcpClient tcpClient) + { + mxClient = tcpClient; + + if (mxClient.Connected) + { + mxStream = mxClient.GetStream(); + mxReader = new StreamReader(mxStream); + mxWriter = new StreamWriter(mxStream); + + mxState = NFTCPClientState.Connected; + + mxEvents.Enqueue(NFTCPEventType.Connected); + + mxReadThread = new Thread(ReadData); + mxReadThread.IsBackground = true; + mxReadThread.Start(); + } + else + { + mxState = NFTCPClientState.Disconnected; + } + } + + /// + /// ////////////////////////////////////////////////////////////////////////////Listener + /// + private UInt32 mnPacketSize = 0; + private byte[] mPacket = new byte[ConstDefine.MAX_PACKET_LEN]; + + public void OnClientConnect(NFTCPEventParams eventParams) + { + net.OnConnect(); + } + + public void OnClientDisconnect(NFTCPEventParams eventParams) + { + if (IsConnected()) + { + Disconnect(); + } + + net.OnDisConnect(); + + } + + public void OnClientConnectionRefused(NFTCPEventParams eventParams) + { + net.Log("Client refused"); + } + + public void OnDataReceived(NFTCPEventParams eventParams) + { + byte[] bytes = eventParams.packet.bytes; + int bytesCount = eventParams.packet.bytesCount; + + net.Log("OnDataReceived:" + mnPacketSize + "|" + bytesCount); + + if (mnPacketSize + bytesCount < ConstDefine.MAX_PACKET_LEN) + { + Array.Copy(bytes, 0, mPacket, mnPacketSize, bytesCount); + mnPacketSize += (UInt32)bytesCount; + + OnDataReceived(); + } + } + + void OnDataReceived() + { + if (mnPacketSize >= ConstDefine.NF_PACKET_HEAD_SIZE) + { + object structType = new MsgHead(); + byte[] headBytes = new byte[Marshal.SizeOf(structType)]; + + Array.Copy(mPacket, 0, headBytes, 0, Marshal.SizeOf(structType)); + StructureTransform.ByteArrayToStructureEndian(headBytes, ref structType, 0); + MsgHead head = (MsgHead)structType; + + if (head.unDataLen == mnPacketSize) + { + byte[] body_head = new byte[head.unDataLen]; + Array.Copy(mPacket, 0, body_head, 0, head.unDataLen); + mnPacketSize = 0; + + if (false == OnDataReceived(this, body_head, head.unDataLen)) + { + OnClientDisconnect(new NFTCPEventParams()); + } + } + else if (mnPacketSize > head.unDataLen) + { + UInt32 nNewLen = mnPacketSize - head.unDataLen; + byte[] newpacket = new byte[ConstDefine.MAX_PACKET_LEN]; + Array.Copy(mPacket, head.unDataLen, newpacket, 0, nNewLen); + + byte[] body_head = new byte[head.unDataLen]; + Array.Copy(mPacket, 0, body_head, 0, head.unDataLen); + mnPacketSize = nNewLen; + mPacket = newpacket; + + if (false == OnDataReceived(this, body_head, head.unDataLen)) + { + OnClientDisconnect(new NFTCPEventParams()); + } + + OnDataReceived(); + } + } + } + + bool OnDataReceived(NFClientNet client, byte[] bytes, UInt32 bytesCount) + { + if (bytes.Length == bytesCount) + { + object structType = new MsgHead(); + StructureTransform.ByteArrayToStructureEndian(bytes, ref structType, 0); + MsgHead head = (MsgHead)structType; + + Int32 nBodyLen = (Int32)bytesCount - (Int32)ConstDefine.NF_PACKET_HEAD_SIZE; + if (nBodyLen > 0) + { + byte[] body = new byte[nBodyLen]; + Array.Copy(bytes, ConstDefine.NF_PACKET_HEAD_SIZE, body, 0, nBodyLen); + + client.net.OnMessageEvent(head, body); + return true; + } + else + { + } + } + + return false; + } + + } +} \ No newline at end of file diff --git a/NFINet.cs b/NFINet.cs new file mode 100644 index 0000000..0d857da --- /dev/null +++ b/NFINet.cs @@ -0,0 +1,49 @@ +using System.Collections; +using NFTCPClient; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +namespace NFTCPClient +{ + public class ConstDefine + { + public static UInt32 NF_PACKET_HEAD_SIZE = 6; + public static int MAX_PACKET_LEN = 655360; + }; + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public class MsgHead + { + public MsgHead() + { + unMsgID = 0; + unDataLen = 0; + } + public UInt16 unMsgID; + public UInt32 unDataLen; + }; + + public abstract class NFINet + { + public delegate void MsgDelegation(MsgHead head, MemoryStream stream); + public delegate void ResultCodeDelegation(int eGameEventCode); + + public delegate void OnConnectDelegation(); + public delegate void OnDisConnectDelegation(); + + public abstract void StartConnect(string strIP, int nPort); + public abstract void SendMsg(int unMsgID, byte[] bodyByte); + public abstract void Disconnect(); + public abstract bool RegisteredDelegation(int eMsgID, MsgDelegation msgDelegate); + public abstract bool RegisteredResultCodeDelegation(int eCode, ResultCodeDelegation msgDelegate); + public abstract bool RegisteredDisConnectDelegation(OnDisConnectDelegation onDisConnectDelegate); + public abstract bool RegisteredConnectDelegation(OnConnectDelegation onConnectDelegate); + } +} \ No newline at end of file diff --git a/NFNet.cs b/NFNet.cs new file mode 100644 index 0000000..404bc14 --- /dev/null +++ b/NFNet.cs @@ -0,0 +1,166 @@ +using System.Collections; +using NFTCPClient; +using System; +using System.Collections.Generic; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Threading; +using System.Linq; +using System.Text; +using System.Runtime.InteropServices; + +public class NFNet : NFINet +{ + public NFClientNet mxClient = null; + public ArrayList mReciveaMsgList = new ArrayList(); + + private Hashtable mhtMsgDelegation = new Hashtable(); + private Hashtable mhtEventDelegation = new Hashtable(); + + OnConnectDelegation mxOnConnectDelegation; + OnDisConnectDelegation mxOnDisConnectDelegation; + + public NFNet() + { + } + + public override void StartConnect(string strIP, int nPort) + { + mxClient = new NFClientNet(this); + mxClient.Connect(strIP, nPort); + } + + public override void SendMsg(int unMsgID, byte[] bodyByte) + { + MsgHead head = new MsgHead(); + head.unMsgID = (UInt16)unMsgID; + head.unDataLen = (UInt32)bodyByte.Length + (UInt32)ConstDefine.NF_PACKET_HEAD_SIZE; + + byte[] headByte = StructureTransform.StructureToByteArrayEndian(head); + + + byte[] sendBytes = new byte[head.unDataLen]; + headByte.CopyTo(sendBytes, 0); + bodyByte.CopyTo(sendBytes, headByte.Length); + + mxClient.SendBytes(sendBytes); + + string strTime = DateTime.Now.Hour + ":" + DateTime.Now.Minute + ":" + DateTime.Now.Second; + string strData = "S***:" + strTime + " MsgID:" + head.unMsgID + " Len:" + head.unDataLen; + mReciveaMsgList.Add(strData); + } + + public override void Disconnect() + { + if (null != mxClient) + { + mxClient.Disconnect(); + } + } + + public override bool RegisteredDelegation(int eMsgID, MsgDelegation msgDelegate) + { + if (!mhtMsgDelegation.ContainsKey(eMsgID)) + { + MsgDelegation myDelegationHandler = new MsgDelegation(msgDelegate); + mhtMsgDelegation.Add(eMsgID, myDelegationHandler); + } + else + { + MsgDelegation myDelegationHandler = (MsgDelegation)mhtMsgDelegation[eMsgID]; + myDelegationHandler += new MsgDelegation(msgDelegate); + } + + return true; + } + + public override bool RegisteredResultCodeDelegation(int eCode, ResultCodeDelegation msgDelegate) + { + if (!mhtEventDelegation.ContainsKey(eCode)) + { + ResultCodeDelegation myDelegationHandler = new ResultCodeDelegation(msgDelegate); + mhtEventDelegation.Add(eCode, myDelegationHandler); + } + else + { + ResultCodeDelegation myDelegationHandler = (ResultCodeDelegation)mhtMsgDelegation[eCode]; + myDelegationHandler += new ResultCodeDelegation(msgDelegate); + } + + return true; + } + + public override bool RegisteredDisConnectDelegation(OnDisConnectDelegation onDisConnectDelegate) + { + mxOnDisConnectDelegation += onDisConnectDelegate; + return true; + } + + public override bool RegisteredConnectDelegation(OnConnectDelegation onConnectDelegate) + { + mxOnConnectDelegation += onConnectDelegate; + return true; + } + + public void Log(string text) + { + + } + + public bool DoResultCodeDelegation(int eCode) + { + if (mhtEventDelegation.ContainsKey(eCode)) + { + ResultCodeDelegation myDelegationHandler = (ResultCodeDelegation)mhtEventDelegation[eCode]; + myDelegationHandler(eCode); + + return true; + } + + return false; + } + + public bool DoDelegation(int eMsg, MsgHead head, MemoryStream stream) + { + if (mhtMsgDelegation.ContainsKey(eMsg)) + { + MsgDelegation myDelegationHandler = (MsgDelegation)mhtMsgDelegation[eMsg]; + myDelegationHandler(head, stream); + + return true; + } + + return false; + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + public void OnMessageEvent(MsgHead head, byte[] bytes) + { + if (head.unDataLen != bytes.Length + ConstDefine.NF_PACKET_HEAD_SIZE) + { + return; + } + + int eMsg = (int)head.unMsgID; + + string strTime = DateTime.Now.Hour + ":" + DateTime.Now.Minute + ":" + DateTime.Now.Second; + string strData = "R:" + strTime + " MsgID:" + head.unMsgID + " Len:" + head.unDataLen; + mReciveaMsgList.Add(strData); + + + DoDelegation(eMsg, head, new MemoryStream(bytes)); + } + + public void OnDisConnect() + { + mxOnDisConnectDelegation(); + + } + + public void OnConnect() + { + mxOnConnectDelegation(); + + } +} diff --git a/NFNet.csproj b/NFNet.csproj new file mode 100644 index 0000000..931ae3d --- /dev/null +++ b/NFNet.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {E615A80A-B280-4E0A-8D6C-20D63A860886} + Library + Properties + NFNet + NFNet + v4.5 + 512 + + + true + full + false + ..\_Out\Lib\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + ..\_Out\Lib\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/NFNet.sln b/NFNet.sln new file mode 100644 index 0000000..325ea30 --- /dev/null +++ b/NFNet.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.23107.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NFNet", "NFNet.csproj", "{E615A80A-B280-4E0A-8D6C-20D63A860886}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E615A80A-B280-4E0A-8D6C-20D63A860886}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E615A80A-B280-4E0A-8D6C-20D63A860886}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E615A80A-B280-4E0A-8D6C-20D63A860886}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E615A80A-B280-4E0A-8D6C-20D63A860886}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2958b3f --- /dev/null +++ b/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的常规信息通过以下 +// 特性集控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("NFNet")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("Microsoft")] +[assembly: AssemblyProduct("NFNet")] +[assembly: AssemblyCopyright("Copyright © Microsoft 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 使此程序集中的类型 +// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型, +// 则将该类型上的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("b8c4006d-6376-4423-8a95-a7397ed86778")] + +// 程序集的版本信息由下面四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值, +// 方法是按如下所示使用“*”: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")]