Thực hành Lập trình hệ thống chat đơn giản bằng WinSock trong môi trường lập trình Visual C++
.1Giới thiệu môi trường lập trình Visual
C++ 6.0
4.2 Lập trình Winsock trong VC++
4.3 Thit kng dng mng MiniChat
4.4 Hiện thực chương trình MiniChatServer
4.5 Hin thc chương trình MiniChatClient
i
các phần tử giao diện Listbox, Edit box,
Static Text
• Đặt các biến dùng cho lập trình socket
• Viết mã lệnh trình tự các hàm như đã trình
bày ở chương 3
Lập trình Winsock trong VC++
• Hàm được gọi đầu tiên khi ứng dụng khởi
tạo là OnInitDialog(): chúng ta có thể viết
hàm khởi tạo socket, bind, listen, accept
trong hàm này
• Có thể tạo các button để xử lý gọi các
hàm nêu trên.
• Nên tạo các hàm để xử lý sự kiện và các
lệnh tương ứng
Lập trình Winsock trong VC++
• Tạo hàm
WindowProc để xử
lý các sự kiện mạng:
– Cửa sổ
ClassWinzard, chọn
ID là C*Dlg,
Messages là
WindowProc và click
button Add Function
– Click button Edit code
để viết mã
Lập trình Winsock trong VC++
• Một số messages cần quan tâm khi lập
trình mạng trong VC++
– WM_CLOSE: xảy ra khi người sử dụng đóng
chương trình
– WM_KEYUP: xảy ra khi người sử dụng nhả
một phím, có thể dùng để detect phím Enter
• Việc sử lý các messages này cũng cần
phải tạo hàm xử lý tương ứng như slide
trước
Thit k ng dng mng
MiniChat
• Ứng dụng MiniChat có hai chương trình
MiniChatServer và MiniChatClient
• Trong hệ thống, chỉ có một chương trình
server và nhiều chương trình client đang
chạy.
• Chương trình client gởi dữ liệu đến cho
chương trình server để yêu cầu thông tin
hoặc gởi thông tin => Định nghĩa các loại
dữ liệu gởi
Định nghĩa các loại dữ liệu gởi
• Dữ liệu gởi của client cho server:
– Tham gia vào chat room: LOGIN:nickname*
• nickname là tên của người sử dụng dùng để chat,
không được trùng với các nickname khác
– Gởi message cho toàn bộ chat room:
PUBLIC: nicknamesender:message*
– Gởi message cho riêng một user:
PRIVATE:nicknamesender:nicknamereciever:
message*
– Thoát khỏi chat room: QUIT*
Định nghĩa các loại dữ liệu gởi
• Dữ liệu gởi từ server cho client:
– Danh sách các user (nickname) có trong
chatroom: LIST[:nickname]+*
• Ví dụ: LIST:cuc:mai:lan:dao*
– Message cho toàn bộ user:
PUBLIC:nicknamesender:message*
– Message cho riêng một user:
PRIVATE:nicknamesender:message*
Định nghĩa các loại dữ liệu gởi
• Dữ liệu gởi từ server cho client:
– Một user login vào: USERL:nickname*
– Đã xử lý yêu cầu đúng: +OK
– Các lỗi:
• -100: Unknown command
• -101: Not login
• -102: Nickname existed
• -103: Nickname not exist
• -104: Cannot send the message
• -105: Not accept null nickname
-106: Login already
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatServer
• Chương trình server mở socket và lắng
nghe kết nối từ các client. Khi có dữ liệu
đến, server phân tích dữ liệu thuộc dạng
nào và xử lý tương ứng:
– Nếu không thuộc các định dạng trên thì gởi
lện –100: Bad request cho client
Dữ liệu đến
LOGIN* PRIVATE*PUBLIC* QUIT*
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatServer
• Với mỗi loại dữ liệu sẽ xử lý tương ứng:
– LOGIN*
Phân tích lấy
nickname
Dữ liệu đúng
định dạng
Nickname đã
có trong danh
sách?
Thêm nickname và địa chỉ
socket vào danh sách.
Gởi lệnh LIST:* cho client
này. Gởi thông tin cho tât
cả các user lệnh
USERL:nickname*
Gởi thông báo lỗi
–100: Bad request
cho client
Gởi thông báo lỗi
–102: Nickname existed
cho client
S
Đ
Đ
S
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatServer
• Xử lý dữ liệu PUBLIC*:
Phân tích lấy
dữ liệu
Dữ liệu đúng
định dạng
Lấy thông tin
nicknamesender
. Đã có trong
danh sách?
Gởi thông báo lỗi
–100: Bad request
cho client
Gởi thông tin +OK cho
client đã gởi tin.
Gởi thông tin cho tât cả
các địa chỉ socket trong
danh sách các user
S
Đ
S Gởi thông báo lỗi –101: Not login
cho client
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatServer
• Xử lý dữ liệu PRIVATE*:
Phân tích lấy
dữ liệu
Dữ liệu đúng
định dạng
Lấy thông tin
nicknamesender
. Đã có trong
danh sách?
Gởi thông báo lỗi
–100: Bad request
cho client Tìm địa chỉ socket của user trong danh
sách và gởi thông tin
PRIVATE:nicknamesender:message*
cho client này. Gởi thông tin +OK cho
client đã gởi tin
S
Đ
S
Đ
Gởi thông báo lỗi
–101: Not login
cho client
Lấy thông
tin
nicknamere
ciever. Đã
có trong
danh sách?
Gởi thông báo lỗi
–103: Nickname not exist
cho client
Đ
S
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatServer
• Xử lý dữ liệu QUIT*:
Phân tích lấy
dữ liệu
Dữ liệu đúng
định dạng
Tìm địa chỉ
socket này có
trong danh sách
các user?
Gởi thông báo lỗi
–100: Bad request
cho client
Gởi thông tin +OK cho client
này. Xoá thông tin user khỏi
danh sách user. Gởi lệnh
LIST[:nickname]* cho tất cả
client có trong danh sách user.
S
Đ
S Gởi thông báo lỗi
–101: Not login
cho client
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatClient
• Chương trình client tạo socket, lấy các thông tin
từ giao diện của người sử dụng để kết nối đến
server.
• Nếu kết nối thành công, lấy thông tin nickname
để gởi dữ liệu LOGIN:nickname* đến server và
chờ nhận dữ liệu về. Dữ liệu về có hai dạng:
– nếu bắt đầu bằng ký hiệu ‘-’ có nghĩa là bị lỗi, phân
tích lỗi tương ứng để thông báo cho user
– Nếu là LIST* có nghĩa là đăng nhập thành công, phân
tích danh sách các nickname để hiển thị cho user
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatClient
• User gởi message vào chat room, có hai
dạng:
– Chỉ gởi cho một user: tạo lệnh PRIVATE* và
gởi cho server. Chờ nhận dữ liệu về:
• +OK: tiếp tục các quá trình khác
• -xxx: lỗi giao thức, phân tích lỗi và thông báo
– Gởi cho toàn bộ chat room: tạo lệnh PUBLIC*
và gởi cho server. Chờ nhận dữ liệu về:
• +OK: tiếp tục quá trình khác
• -xxx: lỗi giao thức, phân tích lỗi và thông báo
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatClient
• User thoát khỏi chat room hoặc tắt chương trình
– Gởi lệnh QUIT* cho server và chờ nhận dữ liệu về:
• +OK: tiếp tục các quá trình khác
• -xxx: lỗi giao thức, phân tích lỗi và thông báo
• Nhận dữ liệu bất kỳ từ server: phân tích dữ liệu
thuộc một trong các dạng: USERL*, USERQ*,
PRIVATE*, PUBLIC*, nếu không thuộc các dạng
này thì thông báo lỗi. Đối với mỗi dạng dữ liệu
sẽ được sử lý như slide kế
Thiết kế sơ đồ chức năng của
ứng dụng MiniChatClient
• Nếu là lệnh USERL*:
– Phân tích lấy nickname
– Thêm nickname vào danh sách các user
• Nếu là lệnh USERQ*:
– Phân tích lấy nickname
– Xoá nickname khỏi danh sách các user, nếu
có lỗi thì báo lỗi cho user
• Nếu là lệnh PRIVATE* hoặc PUBLIC*
– Hiển thị thông tin này cho user
Hiện thực chương trình
MiniChatServer
Thiết kế giao
diện như hình
bên và đặt các
biến tương
ứng cho các
phần tử giao
diện
Edit box,
ID=IDD_EDIT_MESSAGE,
Multiline, scroll, biến tương
ứng: CString m_message;
Listbox,
ID=IDD_LIST_USER,
Multiline, scroll, biến
tương ứng:
CListBox m_users;
Editbox,
ID=IDD_EDIT_PORT,
biến tương ứng:
int m_port;
StaticText,
ID=IDD_STATIC_STATUS
, caption =‘’, biến tương
ứng CString m_status;
Hiện thực chương trình
MiniChatServer
• Định nghĩa kiểu dữ liệu record để lưu
danh sách các user (đầu file C*Dlg.h):
typedef struct T_UserRecord {
char name[20];
SOCKET socket;
int state;
struct T_UserRecord* next;
} T_UserRecord;
• Khai báo các biến: (dùng chức năng Add Member Variable)
SOCKET ServerSocket; char temp_message[128];
T_UserRecord *UserRecordList; T_UserRecord *tempUserRecord;
Hiện thực chương trình
MiniChatServer
• Khai báo các hằng số (file Resource.h)
– #define MSG_LENGTH 256
– #define WSA_ACCEPT 1006
– #define WSA_RDCLOSE 1007
– #define CONNECTED 2000
– #define LOGIN 2001
– #define CHAT 2002
• Lập trình theo các bước sau:
– Tạo hàm xử lý sự kiện khi người dùng click chuột vào
Button Listen, hàm OnButtonListen(): lần lượt gọi các
lệnh socket, bind, listen, và WSASyncSelect
Hiện thực chương trình
MiniChatServer
• Trình tự:
– Tạo hàm WindowProc() và viết mã lệnh:
• Tùy theo loại message sẽ gọi hàm tương ứng để xử lý (hai
loại message định nghĩa là WSA_ACCEPT,
WSA_RDCLOSE).
– Định nghĩa và viết mã lệnh hàm OnAccept(…): xử lý
sự kiện FD_ACCEPT, message WSA_ACCEPT khi
có yêu cầu kết nối
– Định nghĩa và viết mã lệnh hàm Process(…): xử lý sự
kiện FD_READ, message WSA_RDCLOSE khi có dữ
liệu gởi đến từ client
Hiện thực chương trình
MiniChatServer
• Trình tự:
– Trong hàm Process(): phân tích định dạng
của dữ liệu đến xử lý tương ứng:
• LOGIN*: hàm Login(…)
• PUBLIC*: hàm SendPublic(…)
• PRIVATE*: hàm SendPrivate(…)
• QUIT*: hàm Logout(…)
– Định nghĩa và viết mã lệnh cho lần lượt các
hàm trên theo sơ đồ khối đã thiết kế
Hiện thực chương trình
MiniChatClient
Thiết kế giao diện
của chương trình
client như hình vẽ
Editbox,
CString m_message
Editbox,
CString m_data
Listbox,
CListBox
m_list_members
Static Text,
CString
m_status
Editbox,
CString m_host
Editbox,
CString m_nickname
Editbox,
int port
Editbox,
CString user
Hiện thực chương trình
MiniChatClient
• Khai báo các biến: (dùng chức năng Add Member Variable)
SOCKET ClientSocket;
char temp_message[128];
int chat_status;
CString data;
• Khai báo các hằng số (file Resource.h)
– #define NOTLOGIN 2000
– #define LOGIN 2001
– #define QUIT 2002
– #define CHAT 2003
– #define WSA_RDREAD 3000
Hiện thực chương trình
MiniChatClient
• Lập trình theo các bước sau:
– Tạo hàm xử lý sự kiện khi người dùng click
chuột vào Button Login, hàm
OnButtonLogin(): lần lượt gọi các lệnh socket,
connect, và WSASyncSelect để chờ nhận sự
kiện mạng
– Tạo hàm WindowProc() và viết mã lệnh:
• Chương trình client chỉ có một message (WSA_RDREAD)
cho hai sự kiện FR_READ và FD_CLOSE, với mỗi sự kiện ta
thực hiện lệnh gọi hàm tương ứng
– Định nghĩa và viết mã lệnh hàm Process(…): xử lý sự
kiện FD_READ, message WSA_RDREAD khi có dữ
liệu từ server gởi đến
Hiện thực chương trình
MiniChatClient
• Trình tự:
– Định nghĩa và viết mã lệnh lần lượt các hàm
Login, ResponseLogin, Send, Communicate,
DisplayUserList
–Tạo hàm xử lý sự kiện
:OnSelchangeListMember, OnButtonSend,
OnButtonLogout
File đính kèm:
Thực hành Lập trình hệ thống chat đơn giản bằng WinSock trong môi trường lập trình Visual C++.pdf

