본문 바로가기
Study/C#

C# Windows Forms 강의 73편: SignalR 클라이언트를 활용한 실시간 채팅 애플리케이션 제작

by wawManager 2025. 4. 17.

 

1. 강의 개요

이번 강의에서는 SignalR을 활용하여 실시간 채팅 애플리케이션을 제작합니다.
SignalR은 웹 소켓 기반의 실시간 양방향 통신 프레임워크로,
서버와 클라이언트 간 메시지를 손쉽게 주고받을 수 있도록 지원합니다.
이 강의에서는 SignalR 서버와 연결하여 메시지를 송수신하는 클라이언트를 만들어봅니다.


2. 학습 목표

  • SignalR 클라이언트를 사용해 실시간 채팅 구현
  • 서버에서 전송된 메시지를 실시간으로 수신하여 UI에 표시
  • 클라이언트가 입력한 메시지를 서버로 전송
  • 실시간 통신 환경에서 안정적인 데이터 처리를 학습

3. 기능 요구사항

필수 기능

1️⃣ SignalR 서버 연결:

  • 서버와의 연결 상태 관리

2️⃣ 메시지 송수신:

  • 사용자가 입력한 메시지를 서버에 전송
  • 서버에서 전송된 메시지를 실시간으로 수신

3️⃣ UI 표시:

  • 수신된 메시지를 ListBox에 표시

4️⃣ 다중 클라이언트 지원:

  • 여러 클라이언트 간 실시간 메시지 공유

4. 실습: SignalR 채팅 애플리케이션 제작

1️⃣ 사전 준비

  1. SignalR 서버:
    • 서버는 미리 구축된 SignalR 서버를 사용하거나 ASP.NET Core SignalR을 참고하여 구현할 수 있습니다.
    • 예제 URL: http://localhost:5000/chatHub
  2. NuGet 패키지 설치:
    • Visual Studio에서 NuGet 패키지 관리로 이동하여 Microsoft.AspNet.SignalR.Client 패키지를 설치합니다.

2️⃣ 폼 구성

  • 폼(Form) 이름: Form1
  • 컨트롤 배치

컨트롤 타입 이름 위치 크기

TextBox txtServerUrl 폼 상단 왼쪽 (300 x 30)
Button btnConnect 폼 상단 오른쪽 (100 x 30)
ListBox lstMessages 폼 중앙 (400 x 300)
TextBox txtMessage 폼 하단 왼쪽 (300 x 30)
Button btnSend 폼 하단 오른쪽 (100 x 30)

📌 폼 디자인 예시:

--------------------------------------------------
| [Server URL: TextBox]        [Connect 버튼]    |
--------------------------------------------------
|               [ListBox - 메시지 표시]           |
--------------------------------------------------
| [Message: TextBox]             [Send 버튼]     |
--------------------------------------------------

3️⃣ 코드 작성

(1) SignalR 클라이언트 구현

using System;
using System.Threading.Tasks;
using System.Windows.Forms;
using Microsoft.AspNet.SignalR.Client;

namespace WindowsFormsApp_SignalRChat
{
    public partial class Form1 : Form
    {
        private HubConnection _hubConnection;
        private IHubProxy _chatHub;

        public Form1()
        {
            InitializeComponent();
        }

        // SignalR 서버 연결
        private async void btnConnect_Click(object sender, EventArgs e)
        {
            string serverUrl = txtServerUrl.Text.Trim();

            if (string.IsNullOrEmpty(serverUrl))
            {
                MessageBox.Show("서버 URL을 입력하세요.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                _hubConnection = new HubConnection(serverUrl);
                _chatHub = _hubConnection.CreateHubProxy("ChatHub");

                // 메시지 수신 이벤트 등록
                _chatHub.On<string, string>("ReceiveMessage", (user, message) =>
                {
                    string formattedMessage = $"{user}: {message}";
                    lstMessages.Invoke(new Action(() => lstMessages.Items.Add(formattedMessage)));
                });

                await _hubConnection.Start(); // 서버 연결
                lstMessages.Items.Add("SignalR 서버에 연결되었습니다.");
            }
            catch (Exception ex)
            {
                MessageBox.Show($"연결 실패: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
    }
}

(2) 메시지 송신 구현

        // SignalR 메시지 송신
        private async void btnSend_Click(object sender, EventArgs e)
        {
            string message = txtMessage.Text.Trim();
            string user = Environment.UserName; // 사용자 이름

            if (string.IsNullOrEmpty(message))
            {
                MessageBox.Show("보낼 메시지를 입력하세요.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            if (_hubConnection == null || _hubConnection.State != ConnectionState.Connected)
            {
                MessageBox.Show("SignalR 서버와 연결되지 않았습니다.", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            try
            {
                await _chatHub.Invoke("SendMessage", user, message); // 서버로 메시지 전송
                lstMessages.Items.Add($"나: {message}");
                txtMessage.Clear();
            }
            catch (Exception ex)
            {
                MessageBox.Show($"메시지 전송 실패: {ex.Message}", "오류", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

(3) Designer 코드

        private void InitializeComponent()
        {
            this.txtServerUrl = new TextBox();
            this.btnConnect = new Button();
            this.lstMessages = new ListBox();
            this.txtMessage = new TextBox();
            this.btnSend = new Button();

            // Server URL TextBox 설정
            this.txtServerUrl.Location = new System.Drawing.Point(10, 10);
            this.txtServerUrl.Size = new System.Drawing.Size(300, 30);

            // Connect Button 설정
            this.btnConnect.Location = new System.Drawing.Point(320, 10);
            this.btnConnect.Size = new System.Drawing.Size(100, 30);
            this.btnConnect.Text = "Connect";
            this.btnConnect.Click += new EventHandler(this.btnConnect_Click);

            // ListBox 설정
            this.lstMessages.Location = new System.Drawing.Point(10, 50);
            this.lstMessages.Size = new System.Drawing.Size(400, 300);

            // Message TextBox 설정
            this.txtMessage.Location = new System.Drawing.Point(10, 360);
            this.txtMessage.Size = new System.Drawing.Size(300, 30);

            // Send Button 설정
            this.btnSend.Location = new System.Drawing.Point(320, 360);
            this.btnSend.Size = new System.Drawing.Size(100, 30);
            this.btnSend.Text = "Send";
            this.btnSend.Click += new EventHandler(this.btnSend_Click);

            // Form 설정
            this.ClientSize = new System.Drawing.Size(450, 400);
            this.Controls.Add(this.txtServerUrl);
            this.Controls.Add(this.btnConnect);
            this.Controls.Add(this.lstMessages);
            this.Controls.Add(this.txtMessage);
            this.Controls.Add(this.btnSend);
            this.Text = "SignalR 채팅 클라이언트";
        }

4️⃣ 실행 결과

1️⃣ 서버 연결

  • 서버 URL 입력 후 "Connect" 버튼 클릭 → SignalR 서버와 연결 성공

2️⃣ 메시지 송신

  • 텍스트 입력 후 "Send" 버튼 클릭 → 메시지가 서버로 전송

3️⃣ 메시지 수신

  • 다른 클라이언트가 전송한 메시지가 ListBox에 실시간 표시

5. 주요 개념 요약

  • HubConnection: SignalR 서버와 클라이언트 간 연결을 관리
  • IHubProxy: 클라이언트에서 호출할 수 있는 서버의 메서드 정의
  • Invoke: 클라이언트에서 서버 메서드 호출
  • On: 서버에서 전송된 데이터를 클라이언트에서 처리

📌 #CSharp #WindowsForms #SignalR #실시간통신 #양방향통신 #채팅클라이언트