TCP 서버
TcpListener 클래스
.NET Framework에서 TCP 서버 프로그램을 개발하기 위해서는 System.Net.Sockets.TcpListener 클래스를 사용한다.
TcpListener 클래스는 내부적으로 System.Net.Sockets.Socket 클래스 기능들을 사용하여 TCP Port Listening 기능을 구현하고 있다.
TCP 서버는 TcpListener 클래스를 통해 포트를 열고 TcpListener.AcceptTcpClient() 메서드를 통해 클라이언트 접속을 대기하고 있다가
접속 요청이 오면 이를 받아들여 TcpClient 객체를 생성하여 리턴한다.
이후 서버의 TcpClient 객체가 클라이언트와 직접 네트워크 스트림을 통해 통신하게 된다.
(참고로 AcceptTcpClient() 대신 AcceptSocket()을 사용할 수 있는데 이를 통해 TcpClient 객체 대신 Low Level의 Socket 객체를 사용할 수 있다)
TcpListener 사용법
TcpListener 클래스를 통해 어떻게 TCP 서버를 사용하는지 살펴보기 위해 아래 단순화 예제를 살펴보자.
아래 예제는 TCP 클라이언트로부터 수신한 메시지를 그대로 돌려보내는 간단한 Echo 서버이다.
(주: 이 예제는 이전 TcpClient 아티클의 첫번째 예제와 함께 사용할 수 있다.)
using System.Net.Sockets;
using System.Net;
namespace TcpSrv
{
class Program
{
static void Main(string[] args)
{
// (1) 로컬 포트 7000 을 Listen
TcpListener listener = new TcpListener(IPAddress.Any, 7000);
listener.Start();
byte[] buff = new byte[1024];
while (true)
{
// (2) TcpClient Connection 요청을 받아들여
// 서버에서 새 TcpClient 객체를 생성하여 리턴
TcpClient tc = listener.AcceptTcpClient();
// (3) TcpClient 객체에서 NetworkStream을 얻어옴
NetworkStream stream = tc.GetStream();
// (4) 클라이언트가 연결을 끊을 때까지 데이타 수신
int nbytes;
while ((nbytes = stream.Read(buff, 0, buff.Length)) > 0)
{
// (5) 데이타 그대로 송신
stream.Write(buff, 0, nbytes);
}
// (6) 스트림과 TcpClient 객체
stream.Close();
tc.Close();
// (7) 계속 반복
}
}
}
}
위 예제를 각 스텝별로 살펴보면,
- TCP 서버에서 포트를 열고 Listening 하기 위해 TcpListener 생성자에 IPAddress 와 포트번호를 지정한다.
여기서 IPAddress.Any는 0.0.0.0 을 가리키는 것으로 로컬 머신의 모든 IP IPAddress에 대해 Listening 할 경우 사용한다.
TcpListener 객체 생성 후 실제 Listening을 시작하기 위해 Start() 메서드를 호출한다.
-
Listening을 시작한 후, 일반적으로 무한 루프를 만들어 서버가 계속 클라이언트 연결 요청을 처리하도록 한다.
루프 안에서 TcpListener 객체의 AcceptTcpClient() 메서드를 사용하면 TcpClient Connection 요청이 올 때까지 대기했다가 요청이 들어오면
요청을 수용하고 서버에서 새 TcpClient 객체를 생성하여 리턴한다. 이렇게 생성된 TcpClient 객체를 통해 클라이언트와 통신하게 된다.
위 예제는 동기적으로 클라이언트 요청을 하나씩 처리하는 예이다.
- TcpClient 객체의 GetStream() 메서드는 TCP 네트워크 스트림을 리턴한다.
이 네트워크 스트림을 이용해서 네트워크으로 데이타 송수신하게 된다.
-
NetworkStream의 Read() 메서드를 사용하여 클라이언트 데이타를 읽어온다.
여기서의 Echo 서버 예제는 클라이언트가 Connection을 끊을 때까지 서버는 계속 읽는다는 프로토콜을 구현한 것이다.
-
NetworkStream의 Write() 메서드를 사용하여 데이타를 클라이언트에 보낸다.
-
마지막으로 NetworkStream을 닫고 TcpClient 객체를 닫는다.