본문 바로가기
개발 이야기/C# 이야기

C# TcpListener와 TcpClient를 이용한 TCP소켓구현

by 런던살자 2019. 7. 2.

안녕하세요 마블랑입니다. 

 

C#에서 TCP 소켓통신을 구현할때 Socket 클래스를 이용했었습니다.

 

처음 소켓통신을 배울때 리눅스에서 배웠기 때문에 socket 생성 - bind - listen - accept 단계에 익숙해져서 그런가 이 방법만 사용하게 되더라고요 ^^

 

그래서 다른 프로그래밍 언어로 소켓 프로세스를 구현할때 Socket클래스 사용을 많이 했었는데요

 

이번에 TcpListener와 TcpClient 클래스로 각각 서버와 클라이언트를 구현하니 정말 간편하고 코드도 보기가 훨씬 쉬워졌습니다.

 

객체를 생성할때 매개변수로 IP와 Port만 입력을 해주면 내부적으로 알아서 설정을 해주고 소켓을 사용할수 있도록 해줍니다.

 

데이터를 주고받는것도 Stream을 통해서 주고받기 때문에 read나 write 함수를 불러오지 않아도 됩니다. 

 

 

그럼 예제 코드를 보겠습니다.

 

그전에 예제 프로그램에 대해 먼저 설명을 드리면 서버에 클라이언트가 접속한뒤 클라이언트가 보낸 메시지를 서버쪽에서 표시하고 서버는 해당 메시지를 다시 클라이언트에게 다시 전달합니다. 일명 echo서버라고 하죠.

 

그리고 클라이언트가 'exit'를 입력을 하면 서버와 클라이언트 모두 종료가 됩니다.

 

1. Server

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

namespace Console_Tcp_Server
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string strMsg;

                TcpListener sockServer = new TcpListener(IPAddress.Parse("127.0.0.1"), 9090); //IP, Port
                sockServer.Start();
                Console.WriteLine("Server 시작! Client 연결 대기중...");

                TcpClient client = sockServer.AcceptTcpClient();//Accept
                Console.WriteLine("Client 접속성공!");

                NetworkStream ns = client.GetStream();
                StreamReader sr = new StreamReader(ns);
                StreamWriter sw = new StreamWriter(ns);

                string welcome = "Server Connnect Success!";
                sw.WriteLine(welcome);
                sw.Flush();

                while (true)
                {
                    strMsg = sr.ReadLine();
                    if (strMsg == "exit")  //exit 메시지 수신시 종료하기
                        break;

                    Console.WriteLine(strMsg);
                    sw.WriteLine(strMsg);
                    sw.Flush();
                }

                sw.Close();
                sr.Close();
                ns.Close();
                sockServer.Stop();

                Console.WriteLine("Client 연결 종료!");
            }
            catch (SocketException e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}

 

TcpListener를 이용하여 구현한 서버코드입니다. 조금씩 주석을 달아놓아서 어렵지 않게 사용할수 있을듯합니다.

 

전체적인 흐름은 기존의 TCP Socket 통신의 흐름과 비슷하다고 보면 됩니다. (단지 중간에 자잘한 과정들이 감춰졌다고 생각하세요 ^^)  

 

 

2. Client 

using System;
using System.IO;
using System.Net.Sockets;

namespace Console_Tcp_Client
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                string strRecvMsg;
                string strSendMsg;

                TcpClient sockClient = new TcpClient("127.0.0.1", 9090); //소켓생성,커넥트
                NetworkStream ns = sockClient.GetStream();
                StreamReader sr = new StreamReader(ns);
                StreamWriter sw = new StreamWriter(ns);

                strRecvMsg = sr.ReadLine();         //서버로부터 접속 성공 메시지 수신
                Console.WriteLine(strRecvMsg);  

                while (true)
                {
                    strSendMsg = Console.ReadLine();

                    sw.WriteLine(strSendMsg);
                    sw.Flush();
                    if (strSendMsg == "exit")
                    {
                        break;
                    }
                    strRecvMsg = sr.ReadLine();
                    Console.WriteLine(strRecvMsg);
                }
                sr.Close();
                sw.Close();
                ns.Close();
                sockClient.Close();

                Console.WriteLine("접속 종료!");
            }
            catch (SocketException e)
            {
                Console.WriteLine(e.ToString());
            }
        }
    }
}

 

TcpClient 클래스를 이용하여 구현한 클라이언트쪽 코드입니다. 

 

역시 서버와 동일하게 기존 Socket통신과 비슷한 구조로 되어있습니다.

 

 

실행화면을 보겠습니다.

 

왼쪽이 서버화면, 오른쪽이 클라이언트 화면입니다. 

 

클라이언트에 두번씩 표시되는 이유는 입력을 한 메시지와 서버에서 보내준 메시지를 둘다 표시하기 때문입니다.

 

화면 구성을 하는것이 귀찮아서 Winform 이 아니라 Console 기반으로 예제를 작성하였습니다.

 

아마 Winform으로 구현할 경우에는 데이터를 받는 부분을 Thread로 구현해야 하지 않을까 싶습니다. 

(그렇지 않으면 메시지를 수신할동안 메인폼은 계속 대기중인 상태로 있을 것으로 예상합니다. )

 

 

기본적인 TCP 소켓통신이지만 잘 활용하시기 바랍니다.

 

이상 마블랑이었습니다.

 

읽어주셔서 고맙습니다.

 

댓글