Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class NetworkClient : IDisposable //Every connection is a NetworkClient. This class makes use of of predefined message classes, all derived from "GenericMessage". "RequestMessage" and "ResponseMessage" are also derived from "GenericMessage". The way I implemented this system creates the possibility to have an request-response system making syncronization relative easy.
- {
- public TcpClient TcpSocket;
- public NetworkStream Stream;
- private List<int> RequestIDs = new List<int>();
- private List<ResponseMessage> Responses = new List<ResponseMessage>();
- public UdpClient UdpListener;
- public int TcpPing
- {
- get;
- private set;
- }
- public int UdpPing
- {
- get;
- private set;
- }
- public long RealPing
- {
- get
- {
- System.Net.NetworkInformation.Ping P = new System.Net.NetworkInformation.Ping();
- System.Net.NetworkInformation.PingReply Reply = P.Send(IP, 3000);
- return Reply.RoundtripTime;
- }
- }
- public IPAddress IP
- {
- get
- {
- return ((IPEndPoint)TcpSocket.Client.RemoteEndPoint).Address;
- }
- }
- public NetworkClient()
- {
- }
- public NetworkClient(TcpClient Socket) //Needs a connected tcp socket
- {
- this.TcpSocket = Socket;
- Socket.NoDelay = true;
- Stream = Socket.GetStream();
- UdpListener = new UdpClient(AddressFamily.InterNetwork);
- UdpListener.ExclusiveAddressUse = false;
- UdpListener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
- UdpListener.Client.Bind(new IPEndPoint(IP, Connection.CurrentPort - 1));
- UdpListener.Connect(IP, Connection.CurrentPort);
- }
- public NetworkClient(TcpClient Socket, NetworkStream Stream)
- {
- this.TcpSocket = Socket;
- Socket.NoDelay = true;
- this.Stream = Stream;
- UdpListener = new UdpClient(AddressFamily.InterNetwork);
- UdpListener.ExclusiveAddressUse = false;
- UdpListener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
- UdpListener.Client.Bind(new IPEndPoint(IP, Connection.CurrentPort - 1));
- UdpListener.Connect(IP, Connection.CurrentPort);
- }
- public NetworkClient(NetworkClient OriginalClient)
- {
- this.TcpSocket = OriginalClient.TcpSocket;
- this.Stream = OriginalClient.Stream;
- UdpListener = new UdpClient(AddressFamily.InterNetwork);
- UdpListener.ExclusiveAddressUse = false;
- UdpListener.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
- UdpListener.Client.Bind(new IPEndPoint(IP, Connection.CurrentPort - 1));
- UdpListener.Connect(IP, Connection.CurrentPort);
- }
- public void SendTcp(GenericMessage Message)
- {
- try
- {
- Message.SendTime = DateTime.UtcNow;
- List<byte> Bytes = ClassToBytes(Message).ToList();
- Bytes.InsertRange(0, (BitConverter.GetBytes((int)Bytes.Count)));
- Stream.Write(Bytes.ToArray(), 0, Bytes.Count);
- }
- catch (IOException e)
- {
- Main_Form.MainForm.ConsoleWriter(e);
- }
- }
- public ResponseMessage SendTcp(RequestMessage Message, bool WaitForResponse)
- {
- for (int i = 1; i < int.MaxValue; i++)
- {
- if (!RequestIDs.Contains(i))
- {
- RequestIDs.Add(i);
- Message.ID = i;
- break;
- }
- }
- SendTcp((GenericMessage)Message);
- if (WaitForResponse)
- {
- DateTime EndTime = DateTime.UtcNow.Add(new TimeSpan(0, 0, 5));
- while (EndTime > DateTime.UtcNow)
- {
- foreach (ResponseMessage BufferedResponse in Responses)
- {
- if (BufferedResponse.ID == Message.ID)
- {
- RequestIDs.Remove(Message.ID);
- ResponseMessage Response = BufferedResponse;
- Responses.Remove(Response);
- return Response;
- }
- }
- Thread.Sleep(5);
- }
- throw new TimeoutException("An expected response was never received.");
- }
- else
- {
- return null;
- }
- }
- public void SendUdp(GenericMessage Message)
- {
- Message.SendTime = DateTime.UtcNow;
- List<byte> Bytes = ClassToBytes(Message).ToList();
- Bytes.InsertRange(0, (BitConverter.GetBytes((int)Bytes.Count)));
- UdpListener.Send(Bytes.ToArray(), Bytes.Count);
- }
- public ResponseMessage SendUdp(RequestMessage Message, bool WaitForResponse)
- {
- for (int i = 1; i < int.MaxValue; i++)
- {
- if (!RequestIDs.Contains(i))
- {
- RequestIDs.Add(i);
- Message.ID = i;
- break;
- }
- }
- SendUdp((GenericMessage)Message);
- if (WaitForResponse)
- {
- DateTime EndTime = DateTime.UtcNow.Add(new TimeSpan(0, 0, 5));
- while (EndTime > DateTime.UtcNow)
- {
- foreach (ResponseMessage BufferedResponse in Responses)
- {
- if (BufferedResponse.ID == Message.ID)
- {
- RequestIDs.Remove(Message.ID);
- ResponseMessage Response = BufferedResponse;
- Responses.Remove(Response);
- return Response;
- }
- }
- Thread.Sleep(5);
- }
- throw new TimeoutException("An expected response was never received.");
- }
- else
- {
- return null;
- }
- }
- public GenericMessage TcpReceive()
- {
- if (Stream.DataAvailable)
- {
- byte[] Buffer = new byte[sizeof(int)];
- Stream.Read(Buffer, 0, sizeof(int));
- int MessageLenght = BitConverter.ToInt32(Buffer, 0);
- byte[] Message = new byte[MessageLenght];
- int BytesRead = 0;
- while (BytesRead < MessageLenght)
- {
- BytesRead += Stream.Read(Message, BytesRead, MessageLenght - BytesRead);
- Thread.Sleep(0);
- }
- GenericMessage ReceivedMessage = BytesToClass(Message);
- ReceivedMessage.ReceiveTime = DateTime.UtcNow;
- TcpPing = (int)(DateTime.UtcNow - ReceivedMessage.SendTime).Milliseconds * 2; //Times two because a normal ping indicates a round-trip time and mine is base on a single trip
- if (ReceivedMessage is ResponseMessage)
- {
- if (RequestIDs.Contains(((ResponseMessage)ReceivedMessage).ID))
- {
- Responses.Add((ResponseMessage)ReceivedMessage);
- }
- return null;
- }
- else
- {
- return ReceivedMessage;
- }
- }
- else
- {
- return null;
- }
- }
- public GenericMessage UdpReceive()
- {
- if (UdpListener.Available > 0)
- {
- IPEndPoint IpEnd = new IPEndPoint(IPAddress.Any, 0);
- List<byte> Message = UdpListener.Receive(ref IpEnd).ToList();
- Message.RemoveRange(0, sizeof(int));
- GenericMessage ReceivedMessage = BytesToClass(Message.ToArray());
- if (!IpEnd.Address.Equals(IP))
- {
- return null;
- }
- ReceivedMessage.ReceiveTime = DateTime.UtcNow;
- UdpPing = (int)(DateTime.UtcNow - ReceivedMessage.SendTime).Milliseconds * 2; //Times two because a normal ping indicates a round-trip time and mine is base on a single trip
- if (ReceivedMessage is ResponseMessage)
- {
- if (RequestIDs.Contains(((ResponseMessage)ReceivedMessage).ID))
- {
- Responses.Add((ResponseMessage)ReceivedMessage);
- }
- return null;
- }
- else
- {
- return ReceivedMessage;
- }
- }
- else
- {
- return null;
- }
- }
- public void CloseConnection()
- {
- UdpListener.Close();
- Stream.Close();
- TcpSocket.Close();
- }
- public static byte[] ClassToBytes(GenericMessage Data)
- {
- BinaryFormatter Formatter = new BinaryFormatter();
- Formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
- MemoryStream Stream = new MemoryStream();
- Formatter.Serialize(Stream, Data);
- return Stream.ToArray();
- }
- public static GenericMessage BytesToClass(byte[] Data)
- {
- BinaryFormatter Formatter = new BinaryFormatter();
- Formatter.AssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple;
- Formatter.Binder = new FormatterBinder();
- MemoryStream Stream = new MemoryStream(Data);
- return (GenericMessage)Formatter.Deserialize(Stream);
- }
- bool Disposed;
- public void Dispose()
- {
- Dispose(true);
- }
- protected virtual void Dispose(bool Disposing)
- {
- if (Disposed)
- {
- return;
- }
- if (Disposing)
- {
- Disposed = true;
- CloseConnection();
- }
- }
- /// <summary>
- /// This makes sure that the formatted binaries won't whine about the different assemblies
- /// </summary>
- private sealed class FormatterBinder : SerializationBinder
- {
- public override Type BindToType(string assemblyName, string typeName)
- {
- Type typeToDeserialize = null;
- // For each assemblyName/typeName that you want to deserialize to
- // a different type, set typeToDeserialize to the desired type.
- String exeAssembly = Assembly.GetExecutingAssembly().FullName;
- // The following line of code returns the type.
- typeToDeserialize = Type.GetType(String.Format("{0}, {1}", typeName, exeAssembly));
- return typeToDeserialize;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement