TCP통신
비동기 Socket Server (1:1)
2021. 12. 23. 20:49
심플해보이지만 잘 작동하는 소스
// Author: CodeReaper
// Last update: 2022/01/01
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace AsyncSocket
{
/// <summary>
/// 핸들링할 객체를 담아둘 Class
/// </summary>
public class StateObject
{
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
// Client socket.
public Socket workSocket = null;
}
/// <summary>
/// 비동기 소켓 서버
/// </summary>
public class Server
{
public int LocalPort { get; set; } = 0;
//연결 event
public event onConnectEventHandler onConnect;
public delegate void onConnectEventHandler(object sender, string remoteIP, string remotePort);
//연결해제 event
public event onDisconnectEventHandler onDisconnect;
public delegate void onDisconnectEventHandler(object sender);
//수신 event
public event onDataArrivalEventHandler onDataArrival;
public delegate void onDataArrivalEventHandler(object sender, byte[] Data, int bytesRead);
//송신 event
public event onSendCompleteEventHandler onSendComplete;
public delegate void onSendCompleteEventHandler(object sender, byte[] Data);
public Server(int ListenPort = 0)
{
LocalPort = ListenPort;
}
protected StateObject _state = null;
Socket listener;
public async void Listen()
{
if (_state != null)
{
return;
}
if (LocalPort < 1)
{
return;
}
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, LocalPort);
// Create a TCP/IP socket.
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
Socket clientSock = await Task.Factory.FromAsync(listener.BeginAccept, listener.EndAccept, null);
onConnect?.Invoke(this, ((IPEndPoint)clientSock.RemoteEndPoint).Address.ToString(), ((IPEndPoint)clientSock.RemoteEndPoint).Port.ToString());
// Create the state object.
_state = new StateObject();
_state.workSocket = clientSock;
clientSock.BeginReceive(_state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), _state);
}
}
catch
{
Stop();
}
finally
{
}
}
private void ReadCallback(IAsyncResult ar)
{
try
{
_state = (StateObject)ar.AsyncState;
Socket handler = _state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
byte[] rcvBuff = new byte[bytesRead];
Array.Copy(_state.buffer, rcvBuff, bytesRead);
if (onDataArrival != null) { onDataArrival(this, rcvBuff, bytesRead); }
handler.BeginReceive(_state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), _state);
}
else
{
Stop();
}
}
catch
{
Stop();
}
}
public void Stop()
{
try
{
_state.workSocket.Shutdown(SocketShutdown.Both);
_state.workSocket.Close();
}
catch
{ }
finally
{
_state = null;
onDisconnect?.Invoke(this);
}
}
public void Send(byte[] data)
{
try
{
if (_state == null || _state.workSocket == null)
{
return;
}
_state.workSocket.Send(data, 0, data.Length, SocketFlags.None);
onSendComplete?.Invoke(this, data);
}
catch
{ }
}
public bool Send(string msg, Encoding enc = null)
{
try
{
if (_state == null || _state.workSocket == null)
{
return false;
}
if (enc == null)
{
enc = Encoding.Default;
}
byte[] bytesEncoded = enc.GetBytes(msg);
_state.workSocket.Send(bytesEncoded, 0, bytesEncoded.Length, SocketFlags.None);
onSendComplete?.Invoke(this, bytesEncoded);
return true;
}
catch (Exception ex)
{
return false;
throw ex;
}
}
}
}
MSDN에서 기본 소스 참조하고, 테스트를 거친 후에 품종 개량한 것입니다.
참고 사이트
https://docs.microsoft.com/ko-kr/dotnet/framework/network-programming/asynchronous-server-socket-example
https://www.csharpstudy.com/net/article/11-%eb%b9%84%eb%8f%99%ea%b8%b0-Socket-%ec%84%9c%eb%b2%84
728x90