본문 바로가기

네트워크/채팅 프로그램

[TCP/IP 소켓 프로그래밍] Winform 을 이용한 채팅 프로그램 - 1

Winform 채팅 프로그램 컨셉

 

간단한 클라이언트 - 서버 구조를 살펴보았다. 클라이언트에서 사용자 입력을 받아 NetworkStream 을 이용해서 서버로 보내고 서버에서는 마찬가지로 스트림을 이용해서 메시지를 받아온다. 이번에는 좀 더 멋스럽게 Winform 을 이용해서 아주 간단한 양방향 채팅 프로그램 하나를 만들어보자. 

 

기능자체는 아주 간단한 채팅 시스템을 만들어볼 생각이고 컨셉은 다음과 같다.

 

1. 서버와 클라이언트가 채팅을 하는것은 약간 이상하니까, 클라이언트 - 클라이언트 로 채팅을 하게끔 구현해보자. 그러면, 클라이언트는 서버로 메시지를 보내고 서버는 받아온 메시지를 다시 다른 클라이언트에게 전달해야한다. 

 

2. 채팅 프로그램을 실행하면 서버에 접속한다. 

 

3. 채팅 가능 시점은 두 클라이언트가 모두 서버에 접속했을 때이다. 

 

일단 이번에는 이런 방식의 채팅프로그램을 만들고, 추후에 다른 PC 에서 동작하게 한다거나, 사진을 보내는 등의 기능을 추가해볼 생각이다. 일단은 Winform 을 이용해서 투박한 채팅 UI 하나를 만들어준 뒤, 2개의 클라이언트를 하나의 서버에 접속을 하는 기능부터 만들어봐야겠다. 

 

UI 야 아래처럼 아주 간단하게 만들 생각이다. Winform 을 이용해서 입력창, 버튼, 상대방이 보낸 메시지와 내가 보낸 메시지를 보여줄 수 있는 TextBox 하나를 놓았다. 

 

투박한 UI

 

 

UI 도 완성시켰으니 이제 클라이언트 2개를 서버에 접속시켜보자. 원래 하나의 서버와 하나의 클라이언트를 연결하는 경우라면, 서버가 별도의 스레드 환경이 아니더라도 연결하는것은 아무 문제가 없다. 다만, 2개 이상의 클라이언트를 서버에 연결하고자 할 때라면, 서버는 스레드를 돌려서 모든 클라이언트의 Connect 요청을 받아들여야 한다. 그리고 각 클라이언트에서 보내지는 메시지들을 처리할 수도 있어야 한다. 그러기 위해서는 Thread 환경이 필요하며, 이를 구현해볼 예정이다. 

 

Winform 채팅 서버

다음은 서버 프로그램의 코드이다. 

 

public class Program
{
    private static TcpListener Listener_First;
    private static TcpListener Listener_Second;
    private static TcpClient Client;


    static void Main(string[] args)
    {
        Listener_First = new TcpListener(IPAddress.Any, 7000);
        Listener_First.Start();

        Listener_Second = new TcpListener(IPAddress.Any, 7001);
        Listener_Second.Start();

        Thread Accept_FirstClientThread = new Thread(new ThreadStart(Accept_FirstClient));
        Accept_FirstClientThread.Start();

        Thread Accept_SecondClientThread = new Thread(new ThreadStart(Accept_SecondClient));
        Accept_SecondClientThread.Start();
    }

    public static void Accept_FirstClient()
    {
        NetworkStream Stream;

        Console.WriteLine("첫번째 Client 연결 대기중 . . .");
        Client = Listener_First.AcceptTcpClient();

        Console.WriteLine("Client 연결 완료 !");
        Stream = Client.GetStream();

        Receive_Client(Stream);
    }

    public static void Accept_SecondClient()
    {
        NetworkStream Stream;

        Console.WriteLine("두번째 Client 연결 대기중 . . .");
        Client = Listener_Second.AcceptTcpClient();

        Console.WriteLine("Client 연결 완료 !");
        Stream = Client.GetStream();

        Receive_Client(Stream);
    }


    public static void Receive_Client(NetworkStream Stream)
    {
        byte[] Buff = new byte[1024];
        int Nbytes;
        string ReceiveData = "";

        while ((Nbytes = Stream.Read(Buff, 0, Buff.Length)) > 0)
        {
            ReceiveData = Encoding.Unicode.GetString(Buff, 0, Nbytes);
            Console.WriteLine("데이터 받는중 : " + ReceiveData + "   남은 데이터 개수 : " + Nbytes);
            //Stream.Write(Buff, 0, Nbytes);
        }

        Console.WriteLine("받아온 데이터 : " + ReceiveData);

        Stream.Close();
        Client.Close();

        Process.GetCurrentProcess().Kill(); 
    }
}

 

간단하게 하나의 클래스 파일로 구현해봤다. 만일 간단한 프레임워크 작업이 필요하다면 추후에 하나씩 추가해볼 생각이다. 서버단에서는 Client 의 Listener 만 설정해두고, Thread 를 이용해서 각 Client 의 접속을 대기 및 연결하도록 해두었다. 그리고 각 Client 의 연결이 완료되면 무한 루프문을 이용해서 Client 가 보내는 메시지를 받아 볼 수 있도록 설정해두었다.

 

이제 서버는 마련해두었으니 Client 가 서버에 접속할 수 있도록 해보자.