본문 바로가기

네트워크/채팅 프로그램

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

Winform 채팅 클라이언트

 

클라이언트 접속하기

UI 까지는 투박하지만 만들어 두었으니, 서버에 접속부터 해보자. 서버에서는 Thread 를 이용해서 모든 클라이언트의 Connect 를 체크해야했지만, 지금 Winform 채팅 프로그램에서 클라이언트에게 서버는 하나이기 때문에 서버에 접속하는것은 그리 어렵지 않다.

 

다음은 클라이언트의 서버 접속 코드다. 

 

 public void ConnectToServer()
{
    // (1) IP 주소와 포트를 지정하고 TCP 연결 
    while (true)
    {
        try
        {
            Console.WriteLine("Client 연결 요청 중 . . .");
            Client = new TcpClient("127.0.0.1", 7000);

            Thread.Sleep(1000);
            break;
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.ToString());
        }
    }
    Console.WriteLine("서버 연결 완료 !! ==============================");
    SendDataToServer();
}

 

TcpClient 클래스를 이용해서 서버에 접속해주었다. 서버 ip 주소는 localhost , 포트번호는 7000번으로 설정해두었기 때문에 TcpClient 의 생성자에 위와 같이 인자로 넘겨주었다. 

 

두번째 클라이언트의 코드도 위와 동일하다. 그렇게 해서 각각 실행을 시켜주면, 다음 그림과 같이 서버에 잘 접속했음을 알 수 있다. 

 

클라이언트의 서버 접속

 

일단은 어떤 클라이언트가 서버에 접속을 했는지, 그리고 각 Winform 이 어떤 클라이언트의 UI 인지 구별해줄 필요는 있겠다. 그건 따로 추가 하는걸로 하자. 자 그럼 서버에 접속까지 마무리했으니 이제 데이터를 보내보자. 간단하게 입력 버튼을 누르면 TextBox 안에 있는 string 데이터를 서버로 보내보는 작업을 해보자. 

 

일단은 한글과 영어를 보내야하기 때문에 Encoding 타입은 Unicode 로 진행해야 할것같고.. 입력을 누르면  데이터를 byte[]  의 형태로 변환시키고 NetworkStream 하나를 TcpClient 클래스를 이용해서 생성해준뒤, 이를 이용해서 데이터를 서버로 넘겨주는 작업을 해보자. 어차피 두 클라이언트에서 해야하는 작업은 동일하기 때문에 한번만 작업해두면 끝이다. 

 

데이터가 서버에 잘 도착했는지도 확인해야 하니, 서버 콘솔에 받아온 데이터를 찍어주는 형태로 확인해보자. 

 

 

클라이언트에서 서버로 데이터 보내기

그러면 일단, 클라이언트쪽에서 버튼 입력 이벤트를 처리해보자. 다음 코드는 버튼 입력 이벤트 코드이다. 

 

private void button_Input_Click(object sender, EventArgs e)
{
    string Msg = textBox_SendMsg.Text;

    if(Msg == "")
    {
        textBox_SendMsg.Focus();
        return;
    }

    byte[] Buff = Encoding.Unicode.GetBytes(Msg);

    Stream = MainManager.Instance().Client.GetStream();

    // 서버로 보내는 데이터
    Stream.Write(Buff, 0, Buff.Length);               
}

 

textBox 에 있는 String 데이터를 Msg 변수에 담아 두자. 만약, 작성된 메시지가 없다면 textBox 에 Focus 만 주고 작업을 종료하고, 메시지가 있다면, 메시지 데이터를 Unicode 타입으로 인코딩해서 byte[] 의 형태로 변환해준다. 그런 뒤에, TcpClient 를 이용해서 NetworkStream 을 생성하고 Write() 함수를 통해 메시지를 서버로 보내준다.

 

단, 주의할 점은 TcpClient 와 NetworkStream 의 생성과 소멸을 잘 제어해야 한다는 점이다. 서버에 접속한 TcpClient 객체를 이용해야지 데이터를 NetworkStream 을 통해 메시지를 보낼 수 있지, 혹여나 Client 객체를 새로 생성한다거나 하면 제대로 동작하지 않는다. 어찌보면 당연하지만, 나는 실수해서 처음에 오류가 와작 뜨는 경험을 했다. 이 리소스들을 해제할때도 마찬가지 인데, 채팅이 모두 종료되고나서 Close() 를 이용해서 리소스를 해제해주어야 한다. 이도 어찌보면 당연한듯.. 어쨋든 이런식으로 클라이언트에서 서버로 데이터를 보낼 수 있다. 

 

 

서버에서 데이터 받아오기

 

이번에는 클라이언트에서 보내온 데이터를 서버쪽에서 받아와보자. 그리 어려울건 없다. NetworkStream 을 이용해서 데이터를 받아와주기만 하면 끝이다. 다만, 약간 기능을 추가해서 어떤 클라이언트에서 데이터가 넘어왔는지 확인하는 코드를 추가해보자. enum 으로 클라이언트의 타입을 설정해주고, 이를 이용해서 어떤 클라이언트에서 넘어온 데이터인지 확인이 가능하다. 다음 코드를 보자. 

 

public static void Accept_FirstClient()
{
    ... 중략 
    
    Receive_Client(Stream, CLIENT_TYPE.FIRST);
}

public static void Accept_SecondClient()
{
    ... 중략
    
    Receive_Client(Stream,CLIENT_TYPE.SECOND);
}

public static void Receive_Client(NetworkStream Stream, CLIENT_TYPE ClientType)
{
    switch(ClientType)
    {
        case CLIENT_TYPE.FIRST:
            RecvMsgFromClient(Stream,CLIENT_TYPE.FIRST);
            break;
        case CLIENT_TYPE.SECOND:
            RecvMsgFromClient(Stream, CLIENT_TYPE.SECOND);
            break;
    }

}

public static void RecvMsgFromClient(NetworkStream Stream, CLIENT_TYPE ClientType)
{
    while (true)
    {
        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);

            if(ClientType == CLIENT_TYPE.FIRST)
            {
                Console.WriteLine("1번 클라이언트 : " + ReceiveData);
            }
            else
            {
                Console.WriteLine("2번 클라이언트 : " + ReceiveData);
            }
        }
    }
}

 

이렇게 하면 클라이언트에서 넘어온 데이터를 서버쪽에서 받아볼 수 있다. 아래는 그 결과다. 

 

 

제법 채팅같은 모습

이제 뭘 추가해야할까.. 

 

일단 딱 보이는건 입력 버튼 눌렀을 때, TextBox 가 초기화가 되야할것같고, 또 엔터를 눌렀을 때 메시지가 보내지면 좋을것같다. 이 부분은 따로 추가해보는걸로 하고 넘어가자. 이제는 뭘 해야할까. 가장 중요한 부분이 남아있다. 

 

서버에 메시지는 잘 도착했으니, 이제 서버에서 각 클라이언트로 다시 메시지를 전달하고 각 클라이언트에서는 서버로 부터 받아온 상대방의 메시지를 본인의 textBox 에 표시해두어야 겠다. 여기까지만 하면 그래도 제법 채팅을 하는 맛이 나지 않을까 싶다.