using PUtility; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Compression; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading.Tasks; namespace PComm { public class PClient { private readonly int BUFF_SIZE = 8192; public delegate void ClientReceivedHandler(PClient sender, PDataType dataType, byte[] data); public event ClientReceivedHandler OnReceived; public delegate void ClientDisconnectedHandler(PClient sender); public event ClientDisconnectedHandler Disconnected; public string ID { get; set; } public IPEndPoint EndPoint { get; private set; } public bool Connected { get { return socket.Connected; } } public bool DataCompression { get; set; } = false; private Socket socket; public PClient(string ip, int port, string id = null) { if (string.IsNullOrEmpty(id)) id = Guid.NewGuid().ToString(); socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); this.ID = id; this.EndPoint = new IPEndPoint(IPAddress.Parse(ip), port); socket.Connect(this.EndPoint); // send ID this.Send(PDataType.ClientID, Encoding.UTF8.GetBytes(this.ID)); socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, AcceptCallback, null); } public PClient(Socket accepted) { if (string.IsNullOrEmpty(this.ID)) this.ID = Guid.NewGuid().ToString(); socket = accepted; this.EndPoint = (IPEndPoint)socket.RemoteEndPoint; socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, AcceptCallback, null); } public void Reconnect() { if (socket.Connected) return; socket.Connect(this.EndPoint); this.Send(PDataType.ClientID, Encoding.UTF8.GetBytes(this.ID)); socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, AcceptCallback, null); } private int SendData(byte[] data) { byte[] toSendData; // 데이터 크기 100B 이하 또는 50MB 이상 압축하지 않음 (CPU 부하시간 더 큼) // 압축한 경우 1 전송, 아닌경우 0 전송 if (DataCompression == false || data.Length <= 100 || data.Length >= 50000000) { byte[] isCompressed = BitConverter.GetBytes(false); socket.Send(isCompressed, SocketFlags.None); toSendData = data; } else { byte[] isCompressed = BitConverter.GetBytes(true); socket.Send(isCompressed, SocketFlags.None); toSendData = PUtil.CompressBytes(data, CompressionLevel.Optimal); } byte[] length = BitConverter.GetBytes(toSendData.Length); socket.Send(length, 0, 4, SocketFlags.None); return socket.Send(toSendData, SocketFlags.None); } public int Send(string msg) { socket.Send(BitConverter.GetBytes((int)PDataType.SimpleString), 0, 4, 0); byte[] data = Encoding.UTF8.GetBytes(msg); //byte[] length = BitConverter.GetBytes(data.Length); //socket.Send(length, 0, 4, 0); //return socket.Send(data, SocketFlags.None); return SendData(data); } public int Send(PDataType dataType, byte[] data) { socket.Send(BitConverter.GetBytes((int)dataType), 0, 4, 0); //byte[] length = BitConverter.GetBytes(data.Length); //socket.Send(length, 0, 4, 0); //return socket.Send(data, SocketFlags.None); return SendData(data); } private void AcceptCallback(IAsyncResult ar) { try { socket.EndReceive(ar); // get data type byte[] dataTypeBuff = new byte[4]; socket.Receive(dataTypeBuff, dataTypeBuff.Length, SocketFlags.None); PDataType dataType = (PDataType)BitConverter.ToInt32(dataTypeBuff, 0); // check compressed byte[] isCompressedBuff = new byte[1]; socket.Receive(isCompressedBuff, isCompressedBuff.Length, SocketFlags.None); bool isCompressed = BitConverter.ToBoolean(isCompressedBuff, 0); // get data size byte[] sizeBuff = new byte[4]; socket.Receive(sizeBuff, sizeBuff.Length, SocketFlags.None); int dataSize = BitConverter.ToInt32(sizeBuff, 0); using (MemoryStream ms = new MemoryStream()) { while (dataSize > 0) { byte[] buff; if (dataSize < BUFF_SIZE) buff = new byte[dataSize]; else buff = new byte[BUFF_SIZE]; int receiveSize = socket.Receive(buff, buff.Length, SocketFlags.None); ms.Write(buff, 0, buff.Length); dataSize -= receiveSize; } byte[] receivedData = ms.ToArray(); byte[] data; if (isCompressed) data = PUtil.DecompressBytes(receivedData); else data = receivedData; if (OnReceived != null) OnReceived(this, dataType, data); socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, AcceptCallback, null); } } catch (Exception ex) { Debug.WriteLine($"[ERROR] CleintAcceptCallback: {ex.Message}"); PFileManager.Instance.WriteLog($"[ERROR] CleintAcceptCallback: {ex.Message}"); if (CheckSocketConnection(socket)) { socket.BeginReceive(new byte[] { 0 }, 0, 0, 0, AcceptCallback, null); } else { Debug.WriteLine($"[ERROR] Close socket {socket.RemoteEndPoint.ToString()}"); PFileManager.Instance.WriteLog($"[ERROR] Close socket {socket.RemoteEndPoint.ToString()}"); Close(); if (Disconnected != null) Disconnected(this); } } } private bool CheckSocketConnection(Socket socket) { bool availability = socket.Available == 0; bool poll = socket.Poll(1000, SelectMode.SelectRead); if (availability && poll) return false; else return true; } public void Close() { socket.Close(); socket.Dispose(); } } }