|
|
|
|
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; } }
|
|
|
|
|
|
|
|
|
|
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 (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();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|