• addr: địa chỉ cấu trúc dùng để chứa thông tin socket phía kết nối đến.. • addr: địa chỉ cấu trúc dùng để chứa thông tin socket phía kết nối đến.. _ Trường hợp lấy thông tin phía kết nố
Trang 1_ Xác định bởi những bit nhận dạng (Class ID):
– Sự tương quan giữa lớp và kích thước mạng:
a) Lớp Internet (Internet Layer)
_ Giao thức Internet (IP – Internet Protocol)
_ Giao thức Kiềm soát Thông điệp Internet (Internet Control Message Protocol – ICMP)
_ Giao thức Nhóm Thông điệp Internet (Internet Group Message Protocol – IGMP)
_ Giao thức Phân giải Địa chỉ (Address Resolution Protocol – ARP), giao thức Chuyển đổi Địa chỉ (Address Reverse Protocol – ARP): chuyển đổi địa chỉ vật lý, luận lý
Trang 2b) Lớp Giao vận (Transport Layer)
_ Cung cấp dịch vụ truyền thông giữa các tiến trình
_ Thông tin xác định tiến trình:
_ Giao thức Kiểm soát Truyền thông (Transmission Control Protocol – TCP):
• Có thiết lập cầu nối: full duplex
• Tin cậy: đúng trình tự, không thất thoát, không trùng lấp
• Byte stream: đệm dữ liệu (nơi lưu trữ dữ liệu trước khi gửi; ví dụ: nếu đệm là 1 KB, gói dữ liệu
là 2 KB thì chỉ có 1KB được chuyển phải gửi lại thêm 1 KB nữa)
_ Giao thức Dữ liệu Người dùng (User Datagram Protocol – UDP):
• Không thiết lập cầu nối
• Không tin cậy
• Dạng truyền thông (broadcast)
• Dữ liệu Người dùng (datagram)
c) Lớp Ứng dụng (Application Layer)
_ Cung cấp việc vận chuyển dữ liệu trong suốt giữa các hệ thống đầu cuối (end systems)
II Ứng dụng mạng
_ Truyền tải tập tin (File Transfer)
_ Trình duyệt web / server (Web Browser / Server)
_ Thư điện tử (Electric Mail)
_ Truyền tải giọng nói (Voice over IP)
_ Xem phim, nghe nhạc trực tuyến (Audio / Video Online)
_ Hội họp từ xa (Remote Conferencing)
_ Trò chơi trực tuyến (Game Online)
_ …
III Mô hình ứng dụng
_ Mô hình 2 tầng (2-tiers): Client / Server
_ Mô hình đa tầng (N-tiers)
_ Mô hình hàng ngang (Peer to Peer)
IV Giao diện lập trình socket
1 Window Socket API
_ Khái quát:
• Phát triển theo đặc tả giao diện Phân phối Phần mềm Berkeley (Berkeley Soft ware Distribution – BSD Socket)
• Bổ sung các tính năng hoạt động của môi trường Windows
• Hiện thực ở dạng thư viện liên kết động: wsock32.dll (winsock.h), ws2_32.del (winsock.h)
• Thư viện lập trình giao tiếp với giao thức mạng
_ Dữ liệu: socket, địa chỉ IP, thông tin máy
_ Các hàm: liên kết thư viện truy xuất thông tin, chuyển đổi dữ liệu, làm việc với socket
2 Tiếp cận hướng đối tượng
a) MFC
_ Thư viện hỗ trợ của Microsoft:
• Che giấu chi tiết sử dụng các hàm Winsock API
• Hỗ trợ xây dựng ứng dụng Internet
_ Windows Sockets: CasyncSocket, Csocket, CsocketFile
_ Mở rộng: Win32 Internet Extensions Winlnet:
• ElnternetSession
• ElnternetConnection: CftpConnection, CgopherConection, ChttConnection
• CgopherLocation
Trang 4Chương 2: CĂN BẢN LẬP TRÌNH WINSOCK
I Socket
1 Khái niệm
_ Cơ chế trừu tượng dùng cho quá trình truyền thông giữa các tiến trình
_ Tương ứng với cấu trúc chứa các thông tin cần cho quá trình truyền thông giữa các tiến trình (IP, port)
2 Quản lý socket
_ Cấu trúc dữ liệu do hệ điều hành quản lý
_ Ứng dụng sử dụng thông qua handle
3 Phân loại
_ Stream Socket: TCP Socket
_ Datagram Socket: UDP Socket
_ Raw Socket
II Phân nhóm hàm thư viện
_ Liên kết thư viện, kết thúc
_ Truy xuất thông tin
_ Chuyển đổi dạng dữ liệu
_ Các hàm thao tác trên socket:
• Tạo socket, đóng socket
• Thiết lập cầu nối
• Gửi, nhận dữ liệu
III Liên kết thư viện
_ Liên kết thư viện: int WSAStartup (WORD wVersionRequested, LPWSADATA lpwaData); _ Kết thúc: int WSACleanup();
_ Truy xuất mã lỗi sai: int WSAGetLastError();
IV Truy xuất thông tin
1 Thông tin máy
_ Các phương thức:
• int gethost name (char FAR* name, int len);
• PHOSTENT gethostbyname (const char FAR* hostname);
• PHOSTENT gethostbyaddr (const char FAR* addr, int len, int af);
_ Ví dụ:
char sethostName [MAX_LEN];
if (gethostname (sethostName, MAX_LEN) != SOCKET_ERROR)
{ //… } else { //… }
_ Cấu trúc thông tin máy:
• struct hostent
{
Trang 5char FAR* h_name;
char FAR* FAR* h_aliases;
short h_addtype;
short h_lenght;
char FAR* FAR* h_addr_list;
#define h_addr h_addr_list[0];
PSERVENT getservbyname (constchar char FAR* name, const FAR* proto);
V Chuyển đổi thông tin dữ liệu
1 Chuyển đổi trật tự byte
_ Trật tự byte:
• Lưu trữ số nguyên trên máy tính:
Host Byte Order Little-Endian Big-Endian
• Quy ước lưu trữ số nguyên trên mạng (Network Byte Order): Big-Endian
_ Các hàm chuyển đổi:
• u_short ntohs (u_short);
• u_long ntohl (u_long);
• u_short htons (u_short);
• u_long htonl (u_long);
2 Chuyển đổi dạng địa chỉ
_ Dạng biểu diễn địa chỉ IPv4:
• Số nguyên 4 byte
• Chuỗi dấu chấm thập phân (Dotted Decimal)
_ Các hàm chuyển đổi:
• unsigned long inet_addr (const char FAR* CD);
• char FAR* inet_ntoa (struct in_addr in);
_ Cấu trúc địa chỉ:
struct in_addr
{
union {
struct { u_char s_b1, s_b2, s_b3, s_b4; } S_un_b;
struct { u_short s_w1,s_w2; } S_un_w;
u_long S_addr;
} S_un;
#define s_addr S_un.S_addr // can be used for most tcp & ip code
#define s_host S_un.S_un_b.s_b2 // host on imp
#define s_net S_un.S_un_b.s_b1 // network
#define s_imp S_un.S_un_w.s_w2 // imp
#define s_impno S_un.S_un_b.s_b4 // imp #
#define s_lh S_un.S_un_b.s_b3 // logical host
Trang 6}
memcpy (&inAddr, pHost->h_addr, 4);
VI Các hàm socket
1 Quy trình sử dụng
a) Có thiết lập cầu nối
b) Không thiết lập cầu nối
Trang 72 Chi tiết sử dụng
a) Tạo socket
_ Cú pháp: SOCKET socket (int af, int type, int protocol);
_ Thông số:
• af: họ địa chỉ AF_INET
• type: loại địa chỉ – SOCK_STREAM (có thiết lập cầu nối – TCP), SOCK_DGRAM (không thiết lập cầu nối – UDP)
• protocol: loại giao thức – 0
_ Kết quả trả về:
• Thành công: handle của socket vừa tạo
• Thất bại: INVALID_SOCKET
_ Ví dụ:
SOCKET s; // socket descriptor
char lpszMessage[100]; // informational message
s = socket(AF_INET, SOCK_STREAM, 0);
if (s == INVALID_SOCKET)
wsprintf (lpszMessage, “socket() generated error %d”, WSAGetLastError());
else lstrcpy(lpszMessage, “socket() succeeded”);
MessageBox(NULL, lpszMessage, “Info”, MB_OK);
b) Đóng socket
_ Cú pháp: int closesocket(SOCKET s);
_ Thông số: s: handle máy muốn đóng
_ Kết quả trả về: Thất bại: SOCKET_ERROR
c) Gán thông tin socket
_ Cú pháp: int bind (SOCKET s, const struct sockaddr FAR* addr, int addrlen); _ Thông số:
• s: handle của socket chờ gán thông tin
• addr: địa chỉ cấu trúc dùng để chứa thông tin socket phía kết nối đến
• addrlen: địa chỉ biến chứa kích thước cấu trúc bởi addr
_ Cấu trúc thông tin socket:
struct sockaddr
{
u_short sa_family; // address family char sa_data[14]; // up to 14 bytes of direct address };
struct sockaddr_in
{
short sin_family; // address family u_short sin_port; // service port struct in_addr sin_addr; // Internet address char sin_zero[8]; // filler
Trang 8};
_ Ví dụ:
SOCKET s; // socket descriptor
char lpszMessage[100]; // informational message
SOCKADDR_IN addr; // Internet address
// create a stream socket
// bind the socket to its address
if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR) {
wsprintf(lpszMessage, “ bind() generated error %d”, WSAGetLastError());
MessageBox(NULL, lpszMessage, “Info”, MB_OK);
} else { // } }
• Trường hợp không chỉ định port: sin_port = 0;
• Lấy thông tin socket: int getsockname (SOCKET s, struct sockAddr* addr, int* addrlen);
d) Lắng nghe
_ Cú pháp: int listen (SOCKET s, int backlog);
_ Thông số:
• s: handle máy muốn đóng
• backlog: kích thước hàng đợi kết nối
_ Kết quả trả về: Thất bại: SOCKET_ERROR
_ Ví dụ:
SOCKET s; // socket descriptor
char lpszMessage[100]; // informational message
SOCKADDR_IN addr; // Internet address
// create a stream socket
// bind the socket to its address
if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) != SOCKET_ERROR) {
// listen for connections (queueing up to three)
if (listen(s, 3) == SOCKET_ERROR) {
wsprintf(lpszMessage, “listen() generated error %d”, WSAGetLastError());
MessageBox(lpszMessage, “Info”);
} else { // } }
}
e) Tiếp nhận
_ Cú pháp: SOCKET socket (SOCKET s, struct sockAddr FAR* addr, int FAR* addrlen);
Trang 9_ Thông số:
• s: handle của socket chờ tiếp nhận “nói” (“lắng nghe”)
• addr: địa chỉ cấu trúc dùng để chứa thông tin socket phía kết nối đến
• addrlen: địa chỉ biến chứa kích thước cấu trúc bởi addr
_ Kết quả trả về:
• Thành công: handle của socket giao tiếp với phía kết nối đến
• Thất bại: INVALID_SOCKET
_ Ví dụ:
SOCKET s; // socket descriptor
SOCKET clientS; // client socket descriptor
char lpszMessage[100]; // informational message
SOCKADDR_IN addr; // Internet address
SOCKADDR_IN clientAddr; // Internet address
IN_ADDR clientIn; // IP address
// bind the socket to its address
if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) != SOCKET_ERROR) {
// listen for connections (queueing up to three)
if (listen(s, 3) != SOCKET_ERROR) {
// set the size of the client address structure nClientAddrLen = sizeof(clientAddr);
// accept a connection clientS = accept(s, (LPSOCKADDR)&clientAddr,
&nClientAddrLen);
if (clientS == INVALID_SOCKET) {
wsprintf(lpszMessage, “ accept() generated error
%d”, WSAGetLastError());
MessageBox(lpszMessage, “Info”);
} else {
// copy the four byte IP address into an IP address structure
memcpy(&clientIn, &clientAddr.sin_addr.s_addr, 4); // print an informational message
wsprintf(lpszMessage,
“accept() ok: client IP address is %s, port is
%d”, inet_ntoa(clientIn), ntohs(clientAddr.sin_port));
MessageBox(lpszMessage, “Info”);
} }
} }
Trang 10_ Trường hợp lấy thông tin phía kết nối sau khi tiếp nhận kết nối: int getpeername (SOCKET s, struct sockAddr* addr, int* addrlen);
wsprintf(lpszMessage, “getpeername() generated error %d”, WSAGetLastError());
MessageBox(lpszMessage, “Info”);
} else {
// copy the four byte IP address into an IP address structure
• s: handle của socket thực hiện kết nối
• addr: địa chỉ cấu trúc dùng để chứa thông tin socket phía chờ kết nối
• addrlen: địa chỉ biến chứa kích thước cấu trúc bởi addr
_ Kết quả trả về: Thất bại: SOCKET_ERROR
_ Ví dụ:
bool ConnectToServer (const Cstring &sServerAddress, short nServerPort) {
bool bSuccess = true;
m_hSocket = socket (AP_INET, SOCK_STREAM, 0);
if (m_hSocket == INVALID_SOCKET) bSuccess = false;
else {
bSuccess = false;
closesock(m_hSocket);
Trang 11} return bSuccess;
} }
g) Gửi nhận
_ Có thiết lập cầu nối:
• Cú pháp:
int send (SOCKET s, const char FAR* buf, int len, int flags);
int recv (SOCKET s, const char FAR* buf, int len, int flags);
• Thông số:
s: handle của socket bên gửi
buf: địa chỉ vùng đệm chứa dữ liệu cần gửi
len: kích thước dữ liệu gửi (tính theo byte)
flags: 0, MSG_DONTROUTR, MSG, OOB
int nError; // error status // create, bind, and connect socket s
lstrcpy(pszBuf, “Hello, World!”);
nBufLen = lstrlen(pszBuf);
nBytesSent = send(s, pszBuf, nBufLen, 0);
if (nBytesSent == SOCKET_ERROR) r = WSAGetLastError();
else { // }
Nhận:
SOCKET s; // socket to communicate over
#define BUFSIZE (100) // receive buffer size char pszBuf[BUFSIZE]; // buffer to receive data int nBytesRecv; // number of bytes received int nError; // error status
// create, bind, and connect socket s
nBytesRecv = recv(s, pszBuf, BUFSIZE, 0);
if (nBytesRecv == SOCKET_ERROR) nError = WSAGetLastError(); else { // }
_ Không thiết lập cầu nối:
s: handle của socket bên gửi
buf: địa chỉ vùng đệm chứa dữ liệu cần gửi
len: kích thước dữ liệu gửi (tính theo byte)
flags: 0, MSG_DONTROUTR, MSG, OOB
Trang 12if (nBytesSent == SOCKET_ERROR) { // } else { // }
closesocket(s);
}
Nhận:
char pszMessage[100]; // informational message
SOCKET s; // socket to receive data on
SOCKADDR_IN addr; // address of the socket
#define BUFSIZE (100) // receive buffer size
char pszBuf[BUFSIZE]; // receive buffer
int nBytesRecv; // number of bytes received
int nError; // error code
SOCKADDR_IN addrFrom; // address of sender
int nAddrFromLen = sizeof(addrFrom); // lengh of sender structure
IN_ADDR inFrom; // IP address of sender
// bind the name to the socket
if (bind(s, (LPSOCKADDR)&addr, sizeof(addr)) == SOCKET_ERROR)
{
nError = WSAGetLastError();
//
} else
Trang 13{
nBytesRecv = recvfrom(s, pszBuf, 100, 0, (LPSOCKADDR)&addrFrom, &nAddrFromLen);
if (nBytesRecv == SOCKET_ERROR) {
nError = WSAGetLastError();
//
} else {
// got some data
// copy the four byte IP address into an IP address structure
memcpy(&inFrom, &addrFrom.sin_addr.s_addr, 4);
// print an informational message wsprintf(pszMessage,
“server received %d bytes from %s, port is
%d”,
nBytesRecv, inet_ntoa(inFrom), ntohs(addrFrom.sin_port));
} closesocket(s);
} }
3 Hai chế độ hoạt động của socket
a) Blocking
_ Các hàm thực hiện hoạt động nhập / xuất trên socket chỉ trả về khi tác vụ hoàn tất → Tiến trình bị chặn nếu tác vụ chưa hoàn tất (sự kiện mong đợi chưa xảy ra)
b) Non-blocking
_ Các hàm thực hiện hoạt động nhập / xuất trên socket trở vền gay sau khi được gởi
_ Phát sinh lỗi WSAEWOULDBLOCK nếu tác vụ yêu cầu chưa hoàn tất → Tiến trình không bị chặn
4 Mô hình xử lý
a) Blocking
_ Sử dụng các hàm socket theo chế độ hoạt động mặc định (blocking)
_ Thường sử dụng giải pháp xử lý đa luồng (multithread)
b) WSAAsyncSelect
_ Mô hình xử lý bất đồng bộ:
• Ứng dụng đăng ký sự kiện mong đợi xảy ra trên socket
• Hệ thống giám sát và gửi thông điệp báo hiệu đến ứng dụng khi sự kiện xảy ra
• Ứng dụng xử lý khi nhận được thông điệp
_ Giải pháp phù hợp với mô hình hoạt động hướng thông điệp của Windows
WSAAsyncSelect (s, hWnd, USER_MESSAGE, FD_READ | FD_CLOSE);
• Sai: Thông điệp báo hiệu do người lập trình định nghĩa
#define <USER_MESSAGE> (WM_USERtn) const UINT <USER_MESSAGE> = WM_USERtn;
Trang 14c) Tạo trình xử lý thông điệp (MFC)
_ Hàm thành phần của lớp cửa sổ nhận thông điệp:
• Khai báo:
LRESULT <tên trình xử lý> (WPARAM wParam, LPARAM lParam);
trong đó:
wParam: handle socket xảy ra sự kiện mong đợi
lParam: mã sự kiện xảy ra và lỗi sai
• Định nghĩa:
LRESULT <tên lớp>::<tên trình xử lý>(WPARAM wParam, LPARAM lParam)
{
if (WSAGETSELECTERROR (lParam == 0) {
switch (WSAGETSELECTEVENT (lParam)) {
case FD_ACCEPT: // ; break;
case FD_READ: // ; break;
case FD_CLOSE: // ; break;
//
} }
else { // } return LRESULT();
}
• Ví dụ:
const UINT MSG_ASYNC = WM_USER + 1;
bool <tên lớp>::ConnectToServer (const Cstring &sIpAddr, short
nServerPort) {
bool bSuccess = true;
m_hSocket = ;
if (m_hSocket != INVALID_SOCKET) {
SOCKADD_IN sockAddr;
if (connect (m_hSocket, , ) == SOCKET_ERROR || WSAAsynSelect (m_hSocket, m_h Wnd, MSG_ASYNC, FD_READ | FD_CLOSE) == SOCKET_ERROR)
{
closesocket (m_hSocket);
bSuccess = false;
} }
else bSuccess = false;
switch (WSAGETSELECTEVENT) {
case FD_READ: ReceiveData(); break;
case FD_CLOSE: closesocket (m_hSocket); break; }
} else { // } return 0L;
} _ Đăng ký trình xử lý:
Trang 15BEGIN_MESSAGE_MAP(<tên lớp >, <tên lớp cơ sở>)
//
ON_MESSAGE (<thông điệp>, <tên trình xử lý thông điệp>)
END_MESSAGE_MAP
trong đó:
• MSG_ASYNC: thông điệm do người lập trình định nghĩa
• OnAsyncSelect tên trình xử lý thông điệp
Giao tiếp với người dùng
Cho phép đăng nhập theo nhóm
Cho phép “trò chuyện” trong nhóm
_ Giao thức ứng dụng:
• Server port: 2013: có thiết lập cầu nối
• Tập lệnh (Client Server):
GLIST: yêu cầu danh sách nhóm :
LOGIN <khoảng trắng (SP)> <tên nhóm>, <tên người dùng>
ULIST: yêu cầu danh sách người dùng trong nhóm:
Gửi nội dung trò chuyện:
TALKS <khoảng trắng (SP)><thông điệp>
LGOUT: đăng xuất
Ký hiệu đặc biệt để ngăn cắt: CRLF
• Dạng hồi đáp (Server Client):
Khi thiết lập cầu nối: xuất lời chào
Lệnh GLIST (trường hợp thành công):
message = <tên nhóm 1>, …, <tên nhóm N>
Lệnh ULIST (trường hợp thành công):
message = <tên người dùng 1>, …, <tên người dùng N>
Lệnh LOGIN, LGOUT, TALKS (hoặc trường hợp thất bại):
message = <nội dung diễn giải>
Trang 16c) Cài đặt
_ Ứng dụng dạng hộp thoại
_ Lớp hộp thoại ứng dụng:
• Dữ liệu:
socket handle: SOCKET m_hSocket
Trạng thái hiện tại:
enum FSTATE {FS_BEGIN, FS_CONNECT, FS_GLIST, FS_LOGIN, FS_ULIST, FS_TALKS, FS_LOGOUT};
FSTATE m_fState
Tên đăng nhập: Cstring m_sUserName
Thành phần liên kết với điều khiển:
CString m_sMessage CListBox m_lbGroups CListBox m_lbUsers CListBox m_lbContent
• Thao tác:
Trình xử lý sự kiện:
Tác động trên các nút:
Kết nối (Connect):
Kiểm tra trạng thái chưa kết nối
Mở hộp thoại kết nối (Connect Dialog)
Thực hiện kết nối – gọi thao tác phụ trợ (ConnectToServer) Đặt trạng thái: đang kết nối
Hoạt động bất đồng bộ:
Lấy Danh sách Nhóm (Get Groups):
Kiểm tra trạng thái kết nối
Gởi lệnh GLIST
Đặt trạng thái: đang lấy danh sách nhóm
Đăng nhập (Login):
Kiểm tra trạng thái đã kết nối và chưa đăng nhập
Mở hộp thoại đăng nhập (Login Dialog)
Gởi lệnh LOGIN
Đặt trạng thái: đang đăng nhập
Lấy Danh sách Người dùng (Get Users):
Kiểm tra trạng thái đã đăng nhập
Đặt trạng thái: đang trao đổi
Đăng xuất (Logout):
Kiểm tra trạng thái đã đăng nhập
Gởi lệnh LGOUT
Đặt trạng thái: đang thoát ra khỏi nhóm
Hoạt động bất đồng bộ:
Kiểm tra mã báo lỗi
Thực hiện / gọi tác vụ xử lý sự kiện tương ứng:
FD_CONNECT: báo kết nối thành công
FD_READ: nhận và xử lý hồi đáp từ server
FD_CLOSE: đóng socket mfState = FS_BEGIN Thông báo
Trang 17 Đặt trạng thái: đã kết nối
Lấy Danh sách Nhóm (Get Groups):
Kiểm tra mã hồi đáp: nếu thành công thì hiển thị danh sách nhóm
tách các tên nhóm và đưa vào listbox; nếu thất bại thì hiển thị thông điệp báo lỗi nhận từ server
Hiển thị thông báo nhận từ server
Đăng nhập (Login):
Kiểm tra mã hồi đáp: nếu thành công thì đặt trạng thái đã đăng nhập (sẵn sàng đón nhận thông điệp); nếu thất bại thì đặt trạng thái:
đã kết nối (chưa đăng nhập)
Hiển thị thông báo nhận từ server
Lấy Danh sách Người dùng (Get Users):
Kiểm tra mã hồi đáp: nếu thành công thì hiển thị danh sách người dùng; nếu thất bại thì hiển thị thông điệp báo lỗi nhận từ server
Đặt trạng thái: sẵn sàng nhận thông điệp
Tạo cầu nối đến server (ConnectToServer):
Thông số: [vào] Địa chỉ server (dạng chuỗi), [vào] số hiệu cổng
Kết quả trả về: nếu thành công là true; nếu thất bại là false
Thực hiện: Kết nối (hoạt động theo chế độ blocking), chọn chế độ hoạt động bất đồng bộ: FD_READ | FD_CLOSE
Nhận dữ liệu (ReceiveData):
Xử lý nhận dữ liệu: nội dung hồi đáp từ server
Gọi thao tác xử lý hồi đáp tương ứng, tùy thuộc trạng thái hiện tại của client
Gởi dữ liệu (SendData)
socket handle: SOCKET m_hSocket
Tên đăng nhập: CString m_sName
Địa chỉ, cổng phía kết nối:
Trang 18 Thao tác:
Thêm người dùng
Lấy người dùng ra khỏi nhóm
Tìm người dùng
Truy xuất tên nhóm
Lấy danh sách tên nhóm
Theo socket handle
Tìm nhóm và người dùng: theo socket handle
Lấy danh sách tên nhóm
_ Lớp hộp thoại ứng dụng:
• Dữ liệu:
socket handle – “lắng nghe”
Danh sách nhóm: CGroupList m_groupList
Danh sách người dùng mới kết nối: CUserList m_groupNewUsers
Thành phần liên kết với các điều khiển
• Thao tác:
Khởi tạo:
Thông số: port lắng nghe
Kết quả trả về: nếu thành công là socket handle; nếu thất bại là INVALID_SOCKET
Dữ liệu nhóm: gồm tập tin dữ liệu hoặc cơ sở dữ liệu
Socket “lắng nghe” – InitListenSocket:
Socket() Bind() Listen() WSAAsyncSelect() - FD_ACCEPT
Kiểm tra người dùng chưa đăng nhập
Kiểm tra thông tin đăng nhập:
Tên nhóm có thật:
Tên người dùng không trùng lắp
Chuyển người dùng sang nhóm đăng nhập (trường hợp thành công):
Xóa khỏi danh sách người dùng mới kết nối
Thêm vào danh sách người dùng của nhóm đăng nhập
Trang 19 Tạo nội dung hồi đáp theo quy định (sử dụng thao tác lấy danh sách tên người dùng của CUserGroup)
Xóa khỏi danh sách người dùng mới của nhóm
Thêm vào danh sách người dùng mới kết nối
Tạo hồi đáp theo quy định
SOCKETADD_IN sockAddr;
sockAddr.sin_family = … sockAddr.sin_port = htons (nServerPort);
if (isalpha (sServerAddress[0]) {
PHOSTENT pHost = gethostbyname (sServerAddress);
if (pHost) memcpy (&sockAddr.sin_addr, pHost->h_addr, 4); }
else sockAddr.sin_addr = inet_addr (sServerAddress);
if (connect (m_hSocket, (LPSOCKADDR) & sockAddr, sizeof(sockAddr)) == SOCKET_ERROR || WSAAsyncSelect, FDREAD
| FDCLOSE) == SOCKET_ERROR) {
closesocket (m_hSocket);
bSuccess = false;
} else bSuccess = false;
return bSuccess;
} }
Trang 20if (ConnectToServer (dlg.m_nServerAddress) == dlg.m_nServerPort)
{
mlbContent.AddString (_T(“Đã kết nối”));
m_fState = FS_CONNECT;
} else mlbContent.AddString (_T(“Kết nối thất bại”)); }
} }
_ Trình xử lý cho hoạt động xử lý bất đồng bộ:
• Hàm thành phần của C…Dlg (lớp hộp thoại chính của ứng dụng)
LRESULT C…Dlg::OnAsyncSelect (WPARAM wParam, LPARAM lParam) {
if (WSAGETSELECTERROR (lParam) == 0) {
switch (WSAGETSELECT (lParam)) {
case FD_READ: ReceiveData(); break;
char szBuffer[BUF_LEN + 1];
int nRecvBytes = recv (m_hSocket, szBuffer, BUF_LEN , 0);
if (nRecvBytes > 0) {