Tải bản đầy đủ (.pdf) (40 trang)

Bài giảng môn Lập trình Mạng

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.24 MB, 40 trang )

Chương 1:

TỔNG QUAN VỀ LẬP TRÌNH MẠNG

I. Họ giao thức TCP/IP
1. Mục tiêu
_ Cung cấp dịch vụ truyền thông liên mạng, che dấu chi tiết kiến trúc liên mạng, che dấu chi tiết phần
cứng.
_ Kiến trúc phân lớp.

2. Địa chỉ IP
a) Khái niệm
_ Địa chỉ luận lý (địa chỉ cấp phát động hoặc tĩnh): xác định duy nhất một máy trên mạng, khác với địa
chỉ card mạng.
_ Địa chỉ vật lý (địa chỉ card mạng): do nhà sản xuất cấp phát.
_ Phiên bản:
• Ipv4: 32 bit, dạng biểu diễn số chấm thập phân (ví dụ: 192.168.10.1).
• Ipv6: 128 bit.

b) Phân lớp địa chỉ
_ 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:

_ Các địa chỉ IP đặc biệt:

_ Các vùng địa chỉ IP dành riêng (Private Network):
• 10.0.0.0 – 10.255.255.255.255
• 172.16.0.0 – 172.31.255.255
• 192.168.0.0 – 192.168.255.255


3. Một số giao thức
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ý.

CuuDuongThanCong.com

/>

b) 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:
• Địa chỉ IP.
• Cổng (16 bit):
 0 – 1023: well-know port, IANA (Internet Assigned Numbers Authority).
 1024 – 49151: registered port.
 49152 – 65535: dynamic port.
_ 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.

CuuDuongThanCong.com

/>

• ElnternetFile.
• EfileFmd.

b) .NET
_ System.Net:
• DNS.
• IPAddress.
• EndPoint.
• IPHostEntry.
• Socket Address.
• WebRequest, WebResponse.
• WebClient.
•…
_ System.Net.Socket:
• Socket.

• SocketException.
• TcpClient, TcpListener.
• UdpClient.
•…
_ System.Net.Mail:
• Enet.
•…

c) Java
_ Java.Net:
• InetAddress.
• Socket, ServerSocket.
• SocketException.
• URI+, URL.
_ Javamail.

CuuDuongThanCong.com

/>

Chươ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();
_ Lưu ý:
• File StdAfx.h: #include <afxsock.h>
• Lớp ứng dụng:
bool CDDemoApp :: InitInstance()
{
...
if (!AfxSocketInit())
{
AfxMessageBox(IDP_SOCKETS_INIT_FAILED);

return false;
}
...
return false;
}

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
{

CuuDuongThanCong.com

/>

char 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];
};
• PHOSTENT pHostEnt = gethostbyname (set);
if (pHostEnt != NULL) { //… }

2. Thông tin dịch vụ
_ Cú pháp:
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
short
12AB
AB12
12AB
long
12AB34CD
CS34AB12
12AB34CD
• 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
#define
#define
#define
#define
#define

s_addr S_un.S_addr // can be used for most tcp & ip code
s_host S_un.S_un_b.s_b2 // host on imp
s_net S_un.S_un_b.s_b1 // network
s_imp S_un.S_un_w.s_w2 // imp
s_impno S_un.S_un_b.s_b4 // imp #

s_lh S_un.S_un_b.s_b3 // logical host

CuuDuongThanCong.com

/>

};

_ Ví dụ:
//…
PHOSTENT pHost = gethostbyname (“…”);
if (pHost != NULL)
{
IN_ADDR inAddr;
memcpy (&inAddr, pHost->h_addr, 4);
// inAddr.s_addr = pHost->h_addr;
Cstring sAddress = inet_ntoa (inAddr);
//…
}

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

CuuDuongThanCong.com


/>

2. 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

CuuDuongThanCong.com

/>

};

_ Ví dụ:
SOCKET s; // socket descriptor
char lpszMessage[100]; // informational message
SOCKADDR_IN addr; // Internet address
// create a stream socket
s = socket(AF_INET, SOCK_STREAM, 0);
if (s != INVALID_SOCKET)

{
// fill out the socket’s address information
addr.sin_family = AF_INET;
addr.sin_port = htons(1050);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 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
s = socket(AF_INET, SOCK_STREAM, 0);

if (s != INVALID_SOCKET)
{
// fill out the socket’s address information
addr.sin_family = AF_INET;
addr.sin_port = htons(1050);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 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);

CuuDuongThanCong.com

/>

_ 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
int nClientAddrLen;
// create a stream socket
s = socket(AF_INET, SOCK_STREAM, 0);
if (s != INVALID_SOCKET)
{
// fill out the socket’s address information
addr.sin_family = AF_INET;
addr.sin_port = htons(1050);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 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));
114 Part II n Basics of WinSock Programming
MessageBox(lpszMessage, “Info”);
...
}
}
}
}


CuuDuongThanCong.com

/>

_ 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);

_ Ví dụ:
// accept a connection
clientS = accept(s, NULL, NULL);
if (clientS == INVALID_SOCKET)
{
wsprintf(lpszMessage, “accept() generated error %d”,
WSAGetLastError());
MessageBox(lpszMessage, “Info”);
}
else
{
if (getpeername(clientS,
(LPSOCKADDR)&clientAddr, &nClientAddrLen)) == SOCKET_ERROR)
{
wsprintf(lpszMessage, “getpeername() 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,
“client IP address is %s, port is %d”,
inet_ntoa(clientIn), ntohs(clientAddr.sin_port));
MessageBox(lpszMessage, “Info”);
//...
}
}

f) Kết nối
_ Cú pháp: int connect

(SOCKET

s,

const

struct

sockAddr

FAR*

addr,

int

addrlen);


_ Thông số:
• 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
{
SOCKADD_IN sockAddr;
addrServer.sin_family = AF_INET;
addrServer.sin_port = htons(nServerPort);
addrServer.sin_addr.s_addr = inet_addr(sServerAddress);
if (connect(s, (LPSOCKADDR) &addrServer, sizeof(addrServer))
== SOCKET_ERROR)
{
bSuccess = false;
closesock(m_hSocket);

CuuDuongThanCong.com

/>

}
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.
• Kết quả trả về:
 Thành công: số byte dữ liệu đã gửi.
 Thất bại: SOCKET_ERROR.
• Ví dụ:
 Gửi:
SOCKET s; // socket to communicate over
char pszBuf[100]; // buffer to send
int nBufLen; // number of bytes in buffer to send
int nBytesSent; // bytes sent
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:
• Cú pháp:
int sendto (SOCKET s, const char * buf, int size, int flags, const
struct sockAddr FAR* addrTo);
int recvfrom (SOCKET s, char* buf, int size, int flags, struct
sockAddr FAR* addrFrom);

• 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.
• Kết quả trả về:
 Thành công: số byte dữ liệu đã gửi.
 Thất bại: SOCKET_ERROR.
• Ví dụ:
 Gửi:
SOCKET s;


CuuDuongThanCong.com

/>

SOCKADDR_IN addr;
#define BUFSIZE (100)
char pszBuf[BUFSIZE];
int nBufLen;
int nBytesSent;
int nError;
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == INVALID_SOCKET)
{
nError = WSAGetLastError();
// ...
}
else
{
// fill out the address of the recipient
addr.sin_family = AF_INET;
addr.sin_port = htons(2050);
addr.sin_addr.s_addr = inet_addr(“166.78.16.150”);
// assign some data to send
lstrcpy(pszBuf, “Hello, World!”);
nBufLen = lstrlen(pszBuf);
// send the datagram
nBytesSent
=
sendto(s,
pszBuf,

nBufLen,
(LPSOCKADDR)&addr, sizeof(addr));
if (nBytesSent == SOCKET_ERROR) { //... }
else { //... }
closesocket(s);
}

0,

 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
s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == INVALID_SOCKET)
{
nError = WSAGetLastError();
// ...
}
else
{
// fill out the name this server will read data from

addr.sin_family = AF_INET;
addr.sin_port = htons(2050);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
// bind the name to the socket
if
(bind(s,
(LPSOCKADDR)&addr,
sizeof(addr))
==
SOCKET_ERROR)
{
nError = WSAGetLastError();
// ...
}
else

CuuDuongThanCong.com

/>

{
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.
_ Chọn chế độ xử lý bất đồng bộ:
int WSAAsyncSelect (SOCKET s, HWND hWnd, UINT message, long IEvent),

trong đó sự kiện mong đợi (IEvent) bao gồm:
• FD_ACCEPT, FD_CONNECT.
• FD_READ, FD_WRITE.
• FD_CLOSE.
• FD_OOB.
_ Đăng ký nhiều sự kiện:
• Đúng:
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;

CuuDuongThanCong.com

/>

c) 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;
return bSuccess;
}
LRESULT <tên lớp>::<tên trình xử lý>(WPARAM wParam, LPARAM lParam)
{
if (WSAGETSELECTERROR (lParam) == 0)
{
switch (WSAGETSELECTEVENT)
{
case FD_READ: ReceiveData(); break;
case FD_CLOSE: closesocket (m_hSocket); break;
}
}
else { //... }
return 0L;
}

_ Đăng ký trình xử lý:


CuuDuongThanCong.com

/>

BEGIN_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.

VII. Ứng dụng MiniChat
1. Mô tả
_ Hai thành phần:
• Server:
 Quản lý người dùng theo nhóm.
 Tổ chức đăng nhập theo nhóm.
 Tổ chức trao đổi trong nhóm.
• Client:
 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.
 Khi nhận các lệnh:
<mã hồi đáp> <khoảng trắng (SP)><thông điệp>

trong đó:
 <mã hồi đáp>: 0 là thành công, 1 là thất bại.
 <thông điệp>:
 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>

2. Client
a) Giao diện
_ Hộp thoại chính.
_ Hộp thoại phụ trợ.

b) Trạng thái hoạt động


CuuDuongThanCong.com

/>

c) 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_ULIST, FS_TALKS, FS_LOGOUT};
FSTATE m_fState
 Tên đăng nhập: Cstring m_sUserName

FS_GLIST,

FS_LOGIN,

 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.
 Gởi lệnh ULIST.
 Đặt trạng thái: đang lấy danh sách người dùng.
 Gửi (Send):
 Kiểm tra trạng thái đã đăng nhập.
 Gởi lệnh TALKS.
 Đặ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
đã đóng kết nối
 Xử lý hồi đáp:
 Kết nối (Connect):
 Hiển thị lời chào nhận từ server.

CuuDuongThanCong.com

/>

 Đặ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.
 Gửi (Send):
 Kiểm tra mã hồi đáp: Thành công: đặ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.
 Thao tác phụ trợ:

 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).

3. Server
a) Giao diện
_ Hộp thoại chính.
_ Hộp thoại phụ trợ.

b) Cài đặt
_ Ứng dụng dạng hộp thoại.
_ Các lớp phụ trợ:
• CUserSocket:
 Kế thừa từ CObject.
 Dữ liệu:
 socket handle: SOCKET m_hSocket.
 Tên đăng nhập: CString m_sName.
 Địa chỉ, cổng phía kết nối:
int m_nPeerPort.
CString m_sPeerAddress.

 Thao tác:
 Truy xuất thông tin.

 Cập nhật thông tin.
• CUserGroup:
 Kế thừa từ CObject.
 Dữ liệu:
 Tên nhóm: CString m_sName.
 Danh sách các usersocket:
CTypedPtrList <CObList, CuserSocket*> m_userList.

CuuDuongThanCong.com

/>

 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.
• CGroupList:
 Dữ liệu: Danh sách các nhóm:
CArray <CUserGroup*, CUserGroup*> m_groupList.

 Thao tác:
 Tìm nhóm.
 Theo 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

 Trình xử lý sự kiện:
 Tác động trên phần tử giao diện:
ListBox: Nhóm.
Button: Xóa, ẩn.
 Hoạt động bất đồng bộ.
 Xử lý đáp ứng yêu cầu từ client:
 GLIST:
 Tạo nội dung hồi đáp theo quy định: sử dụng thao tác lấy danh sách tên
nhóm của CGroupList.
 Gởi hồi đáp.
 LOGIN:
 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.
 Cập nhật tên đăng nhập.
 Tạo hồi đáp theo quy định gửi hồi đáp.
 ULIST:
 Kiểm tra là người dùng đã đăng nhập (hiện diện trong danh sách của một
nhóm).

CuuDuongThanCong.com

/>

 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).
 Gửi hồi đáp.
 LGOUT:
 Kiểm tra là người dùng đã đăng nhập (hiện diện trong danh sách của một
nhóm).
 Chuyển người dùng sang danh sách mới kết nối (trường hợp thành
công).
 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.
 Gửi hồi đáp.
 “Broadcast”:
 Kiểm tra là người dùng đã đăng nhập (hiện diện trong danh sách của một
nhóm).
 Sử dụng thao tác tìm nhóm và người dùng theo socket handle của lớp

CGroupList.
 Tạo thông điệp “broadcast” (tên người dùng gửi + “:” + nội dung trò
chuyện).
 Gửi thông điệp “broadcast” cho các người dùng còn lại trong nhóm.
 Thao tác phụ trợ:
 Tiếp nhận kết nối (AcceptConnection):
 Nhận dữ liệu (ReceiveData).
 Phân tích yêu cầu (ParseRequest):
 Xác định mã lệnh, gọi tác vụ.
 Xừ lý đáp ứng yêu cầu.
 Gửi dữ liệu (SendData).

4. Minh họa
_ Thiết lập kết nối:
bool CChatClDlg::ConnectToServer (const CString &sServerAddress, short
nServerPort)
{
bSuccess = true;
m_hSocket = socket (…, …, 0);
if (m_hSocket != INVALID_SOCKET)
{
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;
}
}

CuuDuongThanCong.com

/>

void CChatClDlg::OnBnClickedConnect()
{
if (m_fState < FSCONNECT) // chưa kết nối
{
ConnectDlg dlg; // hộp thoại để nhập thông tin server
if (dlg_DoModal() == IDOK)
{
if
(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;
case FD_CLOSE:
closesocket (m_hSocket);
m_fState = FS_BEGIN;
m_lbContent.AddString(_T(“...”);
break;
}
}
else { //…}

return LRESULT(0);
}

• Đăng ký trình xử lý:
BEGIN_MESSAGE_MAP (C…Dlg:Cdialog)
...
ON_MESSAGE (MSG_ASYNC, OnAsyncSelect); // tự định nghĩa
END_MESSAGE_MAP
const UNIT MSG_ASYNC = WM_USER + 1;

• Hàm thành phần thực hiện nhận dữ liệu:
const int BUF_LEN = 255;
void C…Dlg::ReceiveData()
{
char szBuffer[BUF_LEN + 1];
int nRecvBytes = recv (m_hSocket, szBuffer, BUF_LEN , 0);
if (nRecvBytes > 0)
{
szBuffer[nRecvBytes] = ‘\0’;
switch (m_fState):
{
case FS_CONNECT: m_lbContent.AddString (szBuffer);
break;
case
FS_GLIST:
ProcessGListReply(nRecvBytes);
break;
}
}


CuuDuongThanCong.com

/>

}
void C…Dlg::SendData(const CString &sData)
{
return send(m_hSocket, sData, sData.GetLength
SOCKET_ERROR);
}

(),

0)

!=

_ Xử lý yêu cầu lấy danh sách nhóm:
• Gởi yêu cầu (lệnh GLIST): khi người dùng nhấn nút GetGroup  Cài đặt trình xử lý sự kiện
nhấn nút GetGroup.
• Xử lý hồi đáp: khi có nhận dữ liệu từ server và client đang ở trạng thái “yêu cầu danh sách
nhóm” (FS_GLIST).
• Khi nhấn nút GetGroup:
void C…Dlg::OnBnClickedGetGroup()
{
if (m_fState >= FS_CONNECT) //đã kết nối
{
m_fState = FS_GLIST;
}
}


• Hàm thành phần xử lý hồi đáp cho yêu cầu lấy danh sách nhóm:
void C…Dlg::ProcessGListReply (const CString &sReply)
{
if (sReply[0] == “MaHoiDap”)
{
int end, begin = HEADER_LEN // tự định nghĩa
m_lbGroups.ResetContent();
while ((end = sReply.Find (‘,’, begin)) >= 0)
{
m_lbGroups.AddString (sReply.Mid (begin, end – begin));
begin = end + 1;
}
m_lbGroups.AddString (sReply.Mid(begin));
}
else
}

_ Xử lý đăng nhập:
• Xử lý gởi yêu cầu (lệnh LOGIN): cần 2 thông số là tên nhóm và tên người dùng.
void C...Dlg::OnBnClickedLogin()
{
if (m_fState >= FS_CONNECT && m_fState < FS_LOGIN)
{
CLoginDlg dlg;
int index = m_lbGroups.GetCurSel();
if (index != LB_ERR)
m_lbGroups.GetText (index, dlg.m_sGroupsName) ;
if (dlg.DoModal() == IDOK)
{

if
(dlg.m_sGroupName.IsEmpty()
||
dlg.m_sUserName.IsEmpty())
MessageBox(_T(“Thiếu thông tni”), _T(“Lỗi”),
MB_OK | MB_ICON ERROR)
else
{
CString sLogin Cmd;
sLoginCmd.Format
(_T(“LOGIN
%S,
%S”),
dlg.m_GroupName, dlg.m_sUserName);
if (SendData (sLoginCmd))
{

CuuDuongThanCong.com

/>

m_fState = FS_LOGIN;
m_UserName = dlg.m_UserName;
}
}
}
}
}

• Xử lý hồi đáp.

void C…Dlg::ProcessLoginReply (const CString &sReply)
{
if (sReply[0] == ‘0’)
m_fState = ...;// sẵn sàng nhận nội dung trò chuyện
trong nhóm
else
{
m_lbContent.AddString (sReply.Mid(HEADER_LEN));
m_fState = FS_CONNECT;
}
}

_ Xử lý yêu cầu lấy danh sách người dùng:
• Xử lý gởi yêu cầu (lệnh ULIST): tương tự trường hợp yêu cầu danh sách nhóm nhưng
m_fState >= FS_LOGIN.
• Xử lý hồi đáp: tương tự trường hợp xử lý hồi đáp cho yêu cầu danh sách nhóm:
 Hiển thị danh sách trên listbox m_lbUsers.
 m_fState = ...;// sẵn sàng nhận nội dung trò chuyện.
_ Xử lý yêu cầu trò chuyện:
• Xử lý gởi yêu cầu (lệnh TALKS): có một thông số là nội dung trò chuyện.
• Xử lý hồi đáp: hiển thị nội dung trò chuyện.
void C…Dlg::OnBnClickedSend()
{
if (m_fState >= FS_LOGIN)
{
UpdataData(true);
if (SendData (_T(“TALKS “) + m_sMessage))
{
m_lbContent.AddString (m_sUserName + _T(“: “) +
m_sMessage);

m_fState = FS_TALKS;
m_sMessage.Empty();
UpdataData(false);
}
}
}

_ Xử lý yêu cầu đăng xuất:
• Xử lý gởi yêu cầu (lệnh LOGOUT):
void C…Dlg::OnBnClickedLogout()
{
if (m_fState >= FS_LOGIN)
{
UpdataData(true);
if (SendData (_T(“LGOUT“)) m_fState = FS_LOGOUT;
}
}

• Xử lý hồi đáp:
void C…Dlg::ProcessLooutReply ()
{
if (sReply[0] == ‘0’) m_fState = FS_CONNECT;
m_lbContent.AddString (sReply.Mid(HEADER_LEN));

CuuDuongThanCong.com

/>

}


_ Xử lý khi người dùng đóng ứng dụng:
• Đóng socket.
• Trình xử lý thông điệp: .WM_CLOSE.
void C…Dlg::OnClose()
{
if (m_fState > FS_BEGIN) closesocket (m_hSocket);
}

VIII. Thư viện lớp MFC
1. Giới thiệu
_ MFC:
• Microsoft Foundation Class Library.
• Application Framework.
_ MFC Socket Classes:
• CAsyncSocket
• CSocket.
•…

2. Lớp CASynSocket
_ Đặc tả khái niệm socket.
_ Kế thừa từ CObject:
• Cung cấp giao diện lập trình mạng: Giao diện lập trình mạng mức thấp (che giấu chi tiết sử
dụng Windows API):
 Các hàm thành phần: tương ứng với các hàm Winsock API.
 Các hàm callback: được tự động gọi khi có sự kiện xảy ra với socket.
 Người lập trình tự giải quyết các vấn đề:
 Hoạt động blocking.
 Sự khác biệt: Trật tự byte và mã ký tự.
• Thành phần:
 Dữ liệu: SOCKET m_hSocket.

 Tác vụ:
 Tạo lập:
 CASyncSocket(…).
 Create(…).
 Truy xuất thông tin:
 GetSockName(…).
 GetSockNameEx(…) (cho IPv6).
 Tạo, đóng socket:
 Socket(…).
 Close(…).
 Thiết lập cầu nối:
 Bind(…).
 Listen(…).
 Accept(…).
 Connect(…).
 Gởi nhận dữ liệu:
 Send(…).
 Receive(…).
 SendTo(…).
 ReceiveFrom(…).
 SendToEx(…).
 ReceiveFromEx(…).
 Khác:
 Attach(…).
 Detach(…).

CuuDuongThanCong.com

/>


 Callback:
 OnAccept(…): FD_ACCEPT.
 OnConnect(…): FD_CONNECT.
 OnSend(…): FD_WRITE.
 OnReceive(…): FD_READ.
 Chi tiết sử dụng:
 Tạo đối tượng socket:
 Quá trình hai bước:
 Thiết lập.
 Gọi hàm Create:
bool Create
(
UINT nSocketPort = 0;
int nSocketType = SOCK_STREAM,
long lEvent = FD_READ | FD_WRITE | FD_OOB
| FD|ACCEPT | FD_CONNECT | FD_CLOSE
LPCTSTR lpszSocketAddress = NULL
);

 Minh họa:
 Cấp phát tĩnh:
CasyncSocket sock;
Sock.Create(…);

 Cấp phát động:
CAsyncSocket *pSock = new CAsyncSocket;
pSocke->Create(…);

 Thiết lập cầu nối:
 Lắng nghe:

bool Listen (int nConnectionBacklog = 5);
sock.Listen(…);
pSock->Listen(…);
 Tiếp nhận: Không gọi hàm Create cho đối tượng rConnectedSocket:
CAsyncSocket connectedSocket;
sock.Accept (connectedSocket, ...);
CAsyncSocket *pConnectedSocket = new CAsyncSocket;
pSock->Accept (**pConnectedSocket, ...);

 Kết nối:
bool

Connect

(LPCTSTR

lpszHostAddress,

UINT

nHostPort);
bool

Connect

(const

SOCKADDR*

lpSockAddr,


int

nSockAddrLen);
sock.Connect (“127.0.0.1”, 2012);
pSock->Connect (“127.0.0.1”, 2012);

 Gởi nhận dữ liệu:
 Có cầu nối:
virtual int Send (const void *lpBuf, int nBufLen,
int nFlags = 0);
virtual int Receive (void *lpBuf, int nBufLen, int
nFlags = 0);

 Không cầu nối.
 Hủy đối tượng socket:
 Cấp phát tĩnh: tự hủy khi thực thi khỏi tầm vực khai báo.
 Cấp phát động: delete pSock.
 Phương thức hủy tự động gọi thao tác Close.
 Xử lý sự kiện xảy ra với socket:
 Định nghĩa lại thao tác xử lý cho các hàm callback.
virtual void OnAccept (int nErrorCode);
virtual void OnClose (int nErrorCode);

CuuDuongThanCong.com

/>

virtual
virtual

virtual
virtual

void
void
void
void

OnConnect (int nErrorCode);
OnReceive (int nErrorCode);
OnSend (int nErrorCode);
OnOutOfBandDate (int nErrorCode);

 Các hàm callback được tự động gọi khi có sự kiện xảy ra với socket.

3. CSocket
a) Khái quát
_ Kế từ từ lớp CasyncSocket: mức trừu tượng cao.
_ Trừu tượng hóa họat động gửi nhận dữ liệu:
• CsocketFile.
• CArchive.
_ Chế độ hoạt động: blocking (phù hợp với CArchive).

b) Thành phần
_ Tạo đối tượng:
CSocket();
bool Create
{
UNIT nSocketPort = 0;
int nSocketyType = SOCK_STREAM;

LPCTSTR lpszSocketAddress = NULL;
}

_ Liên quan đến blocking mode:
bool IsBlocking();
void CancelBlockingCall();
virtual bool OnMessagPending();
static CSocket * PASCAL FromHandle (SOCKET hSocket);

c) Chi tiết sử dụng
_ Tạo đối tượng socket.
_ Thiết lập cầu nối:
• Server:
 Socket.Listen();
 Sock.Accept(…);
 pSock->Listen();
 pSock->Accept(…);
• Client:
 sock.Connect(…);
 pSock->Connect(…);
_ Gửi nhận dữ liệu:
• Tạo đối tượng CSocketFile (liên kết với đối tượng CSocketFile):
CSocketFile sockFile (&sock,
CSocketFile sockFile (psock,
• Để nhận: CArchive arIn (&sockFile,
• Để gởi: CArchive arOut (&sockFile,

…);
…);
CArchive::load, ...);

CArchive::store, ...);

• CArchive không làm việc với Datagram Socket.
_ Kết thúc: Hủy đối tượng CArchive, CSocketFile, CSocket.

4. Vấn đề thiết kế
a) Xây dựng lớp socket
_ Kế thừa từ CAsyncSelect, CSocket.
_ Bổ sung thành phần mới.
_ Định nghĩa lại các thao tác:
CAsyncSelect::OnReceive(...).
CAsyncSelect::OnSend(...).
CAsyncSelect::OnAccept(...).
CAsyncSelect::OnClose(...).
...
CSocket::OnMessagePeding(...).

CuuDuongThanCong.com

/>

×