





Preview text:
HANOI UNIVERSITY OF SCIENCE AND TECHNOLOGY
SCHOOL OF ELECTRICAL AND ELECTRONIC ENGINEERING LẬP TRÌNH NÂNG CAO
BÁO CÁO DỰ ÁN: ỨNG DỤNG CHAT NHÓM WPF
ĐINH QUANG HIỂN NGUYỄN HUY HOÀNG 20224281 20224313
VŨ MINH HIỂN NGUYỄN TRƯỜNG GIANG 20224282 20224271
1. Tổng quan Dự án
Đây là một ứng dụng chat nhóm desktop được xây dựng bằng công nghệ WPF (Windows
Presentation Foundation) và .NET, hoạt động theo mô hình Client-Server. Dự án bao gồm hai phần chính:
● ChatServer: Một ứng dụng Console đóng vai trò là máy chủ, có nhiệm vụ lắng nghe, quản
lý kết nối và chuyển tiếp tin nhắn.
● WpfChatApp: Một ứng dụng WPF với giao diện đồ họa, đóng vai trò là máy khách (client),
cho phép người dùng kết nối, gửi và nhận tin nhắn.
Mục tiêu của dự án là tạo ra một phòng trò chuyện thời gian thực, nơi nhiều người dùng có thể
giao tiếp với nhau một cách liền mạch, hỗ trợ nhiều tính năng hiện đại như gửi tệp tin, trả lời
tin nhắn, và xem danh sách người dùng đang hoạt động.
2. Kiến trúc và Cách thức hoạt động
Dự án được xây dựng dựa trên kiến trúc Client-Server kinh điển, sử dụng System.Net.Sockets
của .NET để giao tiếp mạng.
2.1. Phía Server (Program.cs)
Server là trung tâm điều phối của toàn bộ hệ thống.
● Lắng nghe kết nối: Server sử dụng một đối tượng TcpListener để mở một cổng (mặc định là
8888) và liên tục chờ đợi các kết nối mới từ client. // File: Program.cs
TcpListener server = new TcpListener(IPAddress.Any, 8888); server.Start(); while (true) {
TcpClient client = await server.AcceptTcpClientAsync();
_ = HandleClientAsync(client); // Phân luồng cho mỗi client }
● Quản lý Client: Mỗi khi một client kết nối thành công, Server sẽ tạo một đối tượng
ClientInfo để lưu trữ thông tin của họ (tên, màu sắc, và quan trọng nhất là đối tượng
StreamWriter để gửi dữ liệu). Tất cả được lưu trong một Dictionary. // File: Program.cs
private static readonly Dictionary connectedClients;
// ... trong HandleClientAsync ...
clientInfo = new ClientInfo { Username = username, ColorHex = GetNextColor(), Writer =
writer }; lock (_lock) { connectedClients.Add(client, clientInfo); }
● Phát sóng (Broadcasting): Khi nhận được một tin nhắn từ một client, Server không xử lý
nội dung mà chỉ đơn giản là "phát sóng" tin nhắn đó đến tất cả các client khác đang kết
nối. Đây là cơ chế cốt lõi của một phòng chat nhóm.
2.2. Phía Client (MainWindow.xaml.cs)
Client là nơi người dùng tương tác trực tiếp.
● Kết nối đến Server: Client sử dụng TcpClient để kết nối đến địa chỉ IP và cổng của Server.
● Gửi và Nhận dữ liệu: Mỗi client duy trì hai luồng (stream) chính: ○
StreamWriter: Để gửi tin nhắn (dữ liệu đi).
○ StreamReader: Để liên tục lắng nghe và đọc tin nhắn từ Server (dữ liệu đến) trong một
vòng lặp bất đồng bộ.
● Cập nhật Giao diện (UI): Vì các hoạt động mạng chạy trên luồng nền, mỗi khi nhận được
dữ liệu mới, Client phải sử dụng Application.Current.Dispatcher.Invoke để đảm bảo rằng
việc cập nhật giao diện (thêm tin nhắn, cập nhật danh sách người dùng) được thực hiện
một cách an toàn trên luồng UI chính.
// File: CS.txt (MainWindow.xaml.cs) private void AddMessage(...) {
Application.Current.Dispatcher.Invoke(() => {
Messages.Add(new ChatMessage { ... });
MessagesScrollViewer.ScrollToEnd(); }); }
2.3. Giao thức Truyền tin (Communication Protocol)
Để Server và Client có thể "hiểu" nhau, dự án sử dụng một giao thức truyền tin tự định nghĩa,
dựa trên việc phân tách chuỗi bằng ký tự |. Các loại tín hiệu chính bao gồm: Tiền tố Mục đích
Cấu trúc Client ->
Cấu trúc Server -> Server Client (không có) Nội dung tin nhắn _user_|Tên|Màu|Nội
Tin nhắn văn bản thường dung _file_ Gửi tệp tin _file_|TênFile| _file_|Tên|Màu| NộiDungBase64 TênFile| NộiDungBase64 _reply_ Trả lời tin nhắn _reply_| _reply_|Tên|Màu| NgườiĐượcTrảLời| NgườiĐượcTrảLời| NộiDungCũ| NộiDungCũ| NộiDungMới NộiDungMới _system_ Thông báo hệ thống (Không có) _system_|Nội dung thông báo _userlist_ (Không có) Cập nhật danh sách _userlist_| online Tên1,Tên2,Tên3
3. Phân tích các Chức năng chính
3.1. Giao diện người dùng (UI)
● Giao diện chính (MainWindow.xaml): Được chia làm hai cột rõ ràng. Cột trái dành cho
khung chat chính, cột phải hiển thị danh sách người dùng online.
● Bong bóng chat (DataTemplate): Sử dụng DataTemplate và DataTrigger một cách hiệu quả
để hiển thị các loại tin nhắn khác nhau (của mình, của người khác, tin nhắn hệ thống, tin
nhắn file, tin nhắn trả lời) với giao diện riêng biệt.
3.2. Gán màu và Nhận diện người dùng
● Cơ chế: Server duy trì một danh sách màu cố định. Hàm GetNextColor sẽ gán màu cho
người dùng mới theo thứ tự và tự động lặp lại khi hết danh sách, đảm bảo ứng dụng không
bị lỗi khi có nhiều người tham gia.
// File: Program.txt static string GetNextColor() { lock (userColors) {
string color = userColors[colorIndex];
colorIndex = (colorIndex + 1) % userColors.Count; // Phép chia lấy dư để quay vòng return color; } }
3.3. Gửi File và Xem trước ảnh
● Gửi File: Client đọc toàn bộ nội dung file dưới dạng mảng byte[], sau đó mã hóa nó thành
một chuỗi Base64 để có thể gửi đi như một tin nhắn văn bản thông thường.
● Xem trước ảnh: Khi nhận được một tin nhắn _file_, Client sẽ kiểm tra đuôi file.
○ Nếu là file ảnh (.jpg, .png, v.v.): Client sẽ giải mã chuỗi Base64 trở lại thành byte[], tạo
một BitmapImage từ đó và hiển thị trực tiếp trên giao diện. ○ Nếu là file khác: Giao diện
"Lưu file" tiêu chuẩn sẽ được hiển thị.
// File: CS.txt (MainWindow.xaml.cs)
private void AddFileMessage(...) { // ... if (IsImageFile(fileName)) {
// Giải mã Base64 và tạo ImageSource để xem trước chatMessage.IsImagePreview = true;
chatMessage.PreviewImageSource = bitmapImage; } // ... }
3.4. Trả lời (Reply) và Nhắc tên (Mention)
● Reply: Khi người dùng trả lời, client sẽ lưu lại thông tin của tin nhắn gốc. Lúc gửi đi, nó
đóng gói cả nội dung tin nhắn cũ và mới vào tín hiệu _reply_. Các client khác khi nhận được
sẽ dựa vào đó để tái tạo lại giao diện trích dẫn.
● Mention: Đây là một tính năng thuần túy phía client. Khi người dùng nhấp vào một tên
trong danh sách, ứng dụng sẽ tự động thêm chuỗi @{tên_người_dùng} vào ô nhập liệu,
giúp tăng tốc độ tương tác.
4. Định hướng Phát triển và Mở rộng
Dự án hiện tại là một nền tảng vững chắc, nhưng có rất nhiều hướng để phát triển nó thành
một ứng dụng hoàn thiện và mạnh mẽ hơn.
4.1. Lưu trữ Lịch sử trò chuyện (Persistence)
Đây là nâng cấp quan trọng nhất. Như đã phân tích, có hai hướng chính:
1. Hướng đi đơn giản (Ngắn hạn): Cho phép người dùng xuất (export) cuộc trò chuyện ra file
.txt từ phía client. Cách này dễ thực hiện, không cần sửa server, nhưng trải nghiệm không liền mạch.
2. Hướng đi chuyên nghiệp (Dài hạn): Lưu trữ lịch sử trên Server.
○ Thách thức: Cần phải xây dựng lại Server để làm việc với một cơ sở dữ liệu (ví dụ: SQLite, SQL Server, MongoDB).
○ Lợi ích: Mang lại trải nghiệm đồng bộ trên nhiều thiết bị, người dùng không bao giờ
mất tin nhắn, và là nền tảng cho các tính năng tìm kiếm sau này.
4.2. Mở rộng quy mô (Scalability)
● Mô hình TcpListener hiện tại hoạt động tốt với vài chục hoặc vài trăm người dùng. Tuy
nhiên, để hỗ trợ hàng ngàn người dùng đồng thời, bạn nên cân nhắc chuyển sang các công
nghệ được thiết kế riêng cho ứng dụng thời gian thực như:
○ ASP.NET Core SignalR: Một thư viện của Microsoft giúp đơn giản hóa việc thêm chức
năng web thời gian thực vào ứng dụng. Nó tự động quản lý kết nối và hỗ trợ nhiều
phương thức truyền tin. Đây là lựa chọn tự nhiên nhất cho hệ sinh thái .NET.
○ gRPC: Một framework hiệu năng cao của Google, phù hợp cho việc truyền dữ liệu liên tục (streaming).
4.3. Các tính năng Nâng cao khác
● Nhắn tin riêng (1-v-1 Private Messaging): Yêu cầu Server có khả năng định tuyến tin nhắn
đến một client cụ thể thay vì phát sóng cho tất cả.
● Xác thực người dùng (Authentication): Xây dựng hệ thống đăng nhập/đăng ký để người
dùng có tài khoản cố định.
● Trạng thái tin nhắn (Seen/Read Receipts): Server cần theo dõi xem những ai đã nhận và đọc tin nhắn.
● Hồ sơ người dùng (User Profiles): Cho phép người dùng đặt ảnh đại diện (avatar), tên hiển thị, và trạng thái. 5. Kết luận
Dự án đã đạt được một thành công lớn trong việc xây dựng một ứng dụng chat nhóm đa chức
năng từ đầu. Kiến trúc Client-Server được triển khai một cách rõ ràng, và các tính năng cốt lõi
hoạt động ổn định. Các hướng phát triển được đề xuất ở trên, đặc biệt là việc lưu trữ lịch sử
trên server và chuyển sang SignalR, sẽ là những bước đi hợp lý tiếp theo để đưa dự án lên một tầm cao mới.