C#에서 TCP/IP 통신을 위한 코드입니다. 송신부는 비동기로 구현할 필요가 없다고 생각해서 연결부, 수신부만 비동기로 구현했습니다. 프로젝트 진행 중 TCP/IP 구현이 필요해서 샘플코드를 찾아보는데 막상 쓸만한 예제를 찾기가 어렵더군요.
본문의 예제는 직접 작성한 코드라서 완벽하진 않지만 기본적인 송수신 기능에는 문제가 없습니다.
✅ TCP/IP 비동기 통신 클라이언트
Connect
public bool Connect(string host, int port)
{
IPAddress.TryParse(host, out IPAddress? ipAddress);
if (ipAddress == null)
{
return false;
}
_tcpClient = new TcpClient();
_tcpClient.BeginConnect(host, port, new AsyncCallback(ConnectCallback), _tcpClient);
_connEvt.WaitOne(5000);
if (_isConnected)
{
Task.Run(async () => {
while (true)
{
await ReadLinesAsync(_tcpClient);
}
});
return true;
}
return false;
}
public void ConnectCallback(IAsyncResult ar)
{
try
{
TcpClient client = (TcpClient)ar.AsyncState;
if (client == null)
{
return;
}
client.EndConnect(ar);
Console.WriteLine("connected to {0}",
client.Client.RemoteEndPoint?.ToString());
_isConnected = true;
_connEvt.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
IPAddress.TryParse(host, out IPAddress? ipAddress); 에 이은 null 체크는 정상적인 ip 인지 확인하는 코드로 생략이 가능합니다.
TcpClient 객체를 생성하고 Connection 시도 시 ManualResetEvent 로 Wait 상태를 만들고 Connection 후에 Set으로 Wait을 풀어줍니다. Connection 에 대한 Callback으로 ConnectCallback 함수를 사용했습니다.
Connection은 5초 동안 기다리며 5초 내에 성공 시 true, 실패 시 false를 return 합니다.
또한 Connection 성공 시 Receieve 를 바로 시작합니다.
Task.Run( ... ) 에서 데이터 수신을 위한 Thread를 생성합니다.
Send
public void Send(string data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
_tcpClient.Client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), _tcpClient);
}
private void SendCallback(IAsyncResult ar)
{
try
{
TcpClient client = (TcpClient)ar.AsyncState;
int bytesSent = client.Client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
Send 는 전송할 string을 받아서 byte array변환 후 전송합니다.
Send 에 대한 Callback으로 SendCallback 함수를 사용했으며 전송 후처리를 Callback에서 구현하면 됩니다.
Receive
public async Task<string> ReadLinesAsync(TcpClient client)
{
int readResult = await _tcpClient.GetStream().ReadAsync(_recvBuffer, 0, _recvBuffer.Length);
Array.Resize(ref _recvBuffer, readResult);
string recvString = Encoding.ASCII.GetString(_recvBuffer);
Console.Write(recvString);
return recvString;
}
int readResult = await _tcpClient.GetStream().ReadAsync(_recvBuffer, 0, _recvBuffer.Length);
TcpClient 객체의 Stream 에 데이터가 수신되면 위 함수가 동작하며 _recvBuffer에 수신된 데이터, readResult에 데이터의 길이가 채워집니다.
Connect 단계에서 생성된 Thread 가 이 함수를 계속 수행하며 데이터 수신을 감시합니다.
github
github에 VisualStudio 로 작성한 프로젝트를 공유합니다.
도움이 되셨길 바랍니다.
감사합니다.
✅ TCP/IP 비동기 통신 클라이언트 - 끝