Tải bản đầy đủ (.doc) (8 trang)

Lập trình mạng bằng pocket PC-part 7 ppt

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 (103.69 KB, 8 trang )

Đóng Socket :
Một khi đã hoàn thành việc sử dụng socket, dù ở trên Server hay Client,
chúng ta phải giải phóng tài nguyên thiết bị đã được liên kết với socket đó.
Trước khi ta thực sự đóng một socket, ta nên gọi hàm shutdown (). Chúng
ta có thể trực tiếp hủy một socket bằng cách đóng nó, nhưng tốt hơn ta nên gọi
hàm shutdown() trước tiên bởi vì điều này đảm bảo rằng: tất cả dữ liệu trong hàng
đợi vận chuyển TCP đã được gửi hoặc nhận hết trước khi socket bị đóng:
int shutdown( SOCKET s , int how) ;
Tham số s là handle của socket mà ta muốn đóng. Tham số how xác định
cách thức những hàm socket xảy ra sau được xử lý trên socket này. Có ba tùy
chọn: SD_RECEIVE, SD_SEND, SE_BOTH. Chọn SD_RECEIVE sẽ ngăn chặn
việc gọi hàm recv() và SD_SEND sẽ ngăn chặn việc gọi hàm send(). Rõ ràng
SD_BOTH sẽ dừng việc gửi và nhận dữ liệu trên socket (tuy nhiên, tất cả dữ liệu
đã nằm trong hàng đợi sẽ được xử lý ).
Nếu không có lỗi, hàm shutdown() sẽ trả về 0. Một khi socket đã bị
shutdown(), chúng ta không thể dùng nó được nữa, trừ khi chúng ta đóng nó bằng
hàm closesocket().
int closesocket(SOCKET s) ;
với s làm handle của socket mà ta muốn đóng.
Sử dụng MFC:
Giới thiệu về lớp CSocket:
Hình 3.41 Sơ đồ kế thừa của lớp CSocket.
Lớp CSocket kết thừa từ lớp cha của nó là CAsyncSocket, do đó nó thừa
hưởng những thành phần Windows sockets API của lớp CasyncSocket.Xem chi
tiết trong MSDN.
Những phần tiếp theo chúng ta sẽ khảo sát những thành phần cơ bản của
lớp CSocket hỗ trợ cho việc lập trình mạng.
Client:
Để có thể sử dụng được thư viện CSocket, cần phải làm hai công việc, một
là thêm dòng #include <afxsock.h> vào đầu tập tin có sử dụng lớp Csocket.
Công việc thứ hai cần làm là để có thể sử dụng thư viện CSocket là phải gọi


hàm AfxSocketInit(NULL) trước khi sử dụng các hàm của lớp Csocket, mục đích
là để khởi tạo thư viện. Nếu không, mọi hàm sử dụng thư viện tuy được biên dịch
thành công nhưng vẫn báo lỗi khi thi hành chương trình.
Để kết nối đến một cổng chở kết nối, trước tiên ta phải khởi tạo một socket
với hàm như sau:
BOOL Create(): Hàm tạo socket ở phia Client không có tham số. Nếu việc
tạo socket thành công thì hàm sẽ trả về kết quả khác 0; nếu xảy ra lỗi thì hàm sẽ
trả về kết quả là 0. Ta có thể dùng hàm int GetLastError() để lấy thông tin mã lỗi.
Sau khi đã tạo một socket thành công, bước tiếp theo là ta sẽ dùng socket
đó để kết nối đến Server đang mở dịch vụ, ta sẽ dùng hàm sau để kết nối:
BOOL Connect(LPCTSTR lpszHostAddress, UINT nHostPort).
lpszHostAddress: là địa chỉ của Server mà ta cần kết nối đến. Ta có thể
truyền cho tham số này theo tên miền hoặc theo địa chỉ IP. Ví dụ:
“ftp.microsoft.com” hoặc “128.56.22.8” đều được. Mỗi máy tính đều có một địa
chỉ IP mặc định là “127.0.0.1” hoặc “localhost”. Do đó, nếu như chúng ta thực
hành kết nối cho cả Server và Client trên cùng một máy thì ta có thể kết nối đến
địa chỉ này.
nHostPort: Là số cổng của dịch vụ mà server đang mở. Ví dụ cổng của
dịch vụ web là 80, cổng của dịch vụ ftp là 21
Sau đây là ví dụ cho việc tạo và kết nối đến dịch vụ cổng 1111 trên Server.
CSocket skConnect;
If(!skConnect.Create() || !skConnect.Connect(“localhost”,1111))
{
cout<<”ket noi khong thanh cong”<<endl;
exit(0);
}
else cout<<”kết nối thành công”;
Sau khi đã kết nối được server, ta sẽ dùng hai hàm sau đây để gửi và nhận
thông điệp.
Hàm gửi thông điệp:

int Send( const void* lpBuf, int nBuffeLen, int nFlags = 0 );
lpBuf: là bộ đệm dùng để chứa dữ liệu được gửi.
nBuffeLen: Chiều dài của dữ liệu lpBuf dưới dạng Byte.
nFlags: Mặc định là 0, ta có thể không cần truyền tham số này.
Nếu không có lỗi xảy ra thì hàm này sẽ trả về giá trị tổng số kí tự được gửi,
( giá trị này phải nhỏ hơn giá trị của nBufLen). Nếu xảy ra lỗi thì hàm sẽ trả về giả
trị SOCKET_ERROR. Chúng ta có thể tìm được mã lỗi thông qua hàm int
GetLastError(). Xem thêm trong MSDN.
Hàm nhận thông điệp từ socket:
virtual int Receive(const void* lpBuf, int nBuffeLen, int nFlags = 0);
Tất cả những tham số này đều có ý nghĩa tương tự như các tham số của
hàm Send() ở trên.Nếu không có lỗi xảy ra thì giá trị trả về của hàm này là tổng số
byte nhận được. Nếu đã đóng kết nối socket, thì kết quả trả về là 0. Nếu xảy ra lỗi
thì kết quả trả về sẽ là một SOCKET_ERROR được xác định trong hàm int
GetLastError(). Tham khảo mã lỗi trong MSDN.
Ví dụ sau sẽ trình bày minh họa cho việc gửi và nhận dữ liệu:
Char msg[1000];
Int msg_len;
While(1)
{
cout<<”Nhap thong diep: “;
gets(msg);
msg_len = strlen(msg);
//Gửi thông điệp đến server
skConnect.Send(&msg_len, sizeof(msg_len)); //Gửi chiều dài thông điệp.
skConnect.Send(msg,msg_len);//Gửi nội dung thông điệp.
//Nhận thông điệp đến server
skConnect.Receive(&msg_len, sizeof(msg_len)); //nhận chiều dài thông
điệp.
skConnect.Receive(msg,msg_len);//Nhận nội dung thông điệp.

}
Cuối cùng, sau khi hoàn tất truyền dữ liệu, đóng kết nối với câu lệnh như
sau:
virtual void Close( );
Sau đây là toàn bộ nội dung đã thực hiện cho client.
CSocket skConnect;
If(!skConnect.Create() || !skConnect.Connect(“localhost”,1111))
{
cout<<”ket noi khong thanh cong”<<endl;
exit(0);
}
else cout<<”kết nối thành công”;
Char msg[1000];
Int msg_len;
While(1)
{
cout<<”Nhap thong diep: “;
gets(msg);
msg_len = strlen(msg);
//Gửi thông điệp đến server
skConnect.Send(&msg_len, sizeof(msg_len)); //Gửi chiều dài thông điệp.
skConnect.Send(msg,msg_len);//Gửi nội dung thông điệp.
//Nhận thông điệp đến server
skConnect.Receive(&msg_len, sizeof(msg_len)); //nhận chiều dài thông
điệp.
skConnect.Receive(msg,msg_len);//Nhận nội dung thông điệp.
skConnect[msg_len] = 0;//Kết thúc chuỗi.
}
skConnect.Close();
Server:

Cũng tương tự như các phía Client, điều trước tiên chúng ta cần làm là khởi
tạo một socket dùng để tạo dịch vụ. Câu lệnh khởi tạo socket phía server có hơi
khác so với phía Client. Nguyên mẫu của hàm như sau:
BOOL Create(UINT nSocketPort = 0,int nSocketType =
SOCK_STREAM,LPCTSTR *lptstr = NULL );
nSocketPort: Số cổng mà ta sử dụng để mở dịch vụ.
nSocketType: SOCK_STREAM( tương ứng với giao thức TCP) hoặc là
SOCK_DGRAM( tương ứng với giao thức UDP). Mặc định của hàm là
SOCK_STREAM.
*lptstr: là chuỗi con trỏ chứa địa chỉ mạng của một kết nối socket. Mặc
định là NULL.
Giá trị khác 0 sẽ được hàm này trả về nếu không có lỗi xảy ra. Ngược lại là
0.Chúng ta có thể tham khảo mã lỗi thông qua hàm int GetLastError();
Trong CSocket, chúng không cần thiết phải gọi hàm bind(), bởi vì sau khi
gọi hàm Create() thì tự động hàm bind() sẽ được gọi để kết buộc socket đến địa
chỉ xác định.
Sau khi đã khởi tạo socket thành công, tiếp theo ta sử dụng hàm Listen để
nghe ngóng kết nối.
BOOL Listen(int backlog = 5 );
backlog: Chiều dài tối đa có mà hàng đợi của những kết nối vào có thể
chứa được. Giá trị này giới hạn trong khoảng từ 1 đến 5; mặc định là 5.
Nếu không có lỗi thì hàm này sẽ trả về giá trị khác 0; ngược lại sẽ cho giá
trị là 0 và mã lỗi sẽ được xác định thông qua hàm GetLastError.
Để chấp nhận một kết nối vào trước tiên cần phải khởi tạo socket bằng hàm
Create, sau đó một backlog (dãy) các kết nối vào sẽ được xác định bởi hàm Listen.
Sau đó những kết nối này sẽ được chấp nhận bởi hàm Accept. Hàm Listen chỉ áp
dụng cho những socket hỗ trợ kết nối, điển hình là dạng SOCK_STREAM. Socket
này được đặt ở chế độ “bị động”_ chế độ mà những kết nối vào được thừa nhận và
được xếp hàng chờ đợi bởi tiến trình này.
Hàm này thường được sử dụng ở Server( hoặc có thể ở bất kỳ ứng dụng

nào muốn chấp nhận kết nối vào) cho phép có nhiều hơn một kết nối được yêu
cầu ở cùng một thời điểm. Nếu có yêu cầu kết nối nhưng hàng đợi đã
đầy(nConnectionBacklog = 5) thì client sẽ nhận một lỗi WSAECONNREFUSED .
Tiếp theo, ta sử dụng hàm Accept để chấp nhận kết nối.
virtual BOOL Accept(CAsyncSocket& rConnectedSocket,
SOCKADDR* lpSockAdd = NULL, int* lpSockAddr = NULL);
rConnectedSocket: Tham chiếu đến socket mới được lấy tự Client.
lpSockAdd : Là một con trỏ đến cấu trúc SOCKADDR socket kết nối đến.
Nếu lpSockAddr hoặc lpSocketAddrLen có giá trị là NULL thì sẽ không
có thông tin nào về địa chỉ của socket vừa được kết nối được trả về. Mặc
định là NULL.
Tương tự như các phương thức ở trên, giá trị trả về của hàm này là khác 0
nếu hàm chương trình thực hiện thành công, ngược lại sẽ bằng 0. Mã lỗi sẽ được
xác định thông qua hàm GetLastError.(xem chi tiết trong MSDN).
Sau khi đã chấp nhận kết nối, ta có thể dùng các hàm Send, Receive để
truyền và nhận thông điệp và hàm Close để đóng socket giống như đã làm ở
Client.
Ví dụ sau sẽ trình bày cách thức một server chấp nhận một kết nối vào:
Các biến được sử dụng trong ví dụ này sẽ gồm 2 biến CSocket một để mở cổng và
một để truyền dữ liệu (Trong thực tế, một cổng có thể cho phép nhiều client nối
vào, khi đó vẫn chỉ có một CSocket để mở cổng nhưng sẽ có nhiều CSocket để
truyền dữ liệu).
CSocket skListen, skConnect;
If(!skListen.Create(1111) || !skListen.Listen() || !
skListen.Accept(skConnect))
{
cout<<”server socket bi loi”;
exit(0);
}
else

{
//truyền thông điệp qua lại giữa client và server.
char msg[1000];
int msg_len ;
while(1);
{
//Nhận thông điệp từ Client
skConnect.Receive(&msg_len, sizeof(msg_len)); //nhận chiều dài thông
điệp.
skConnect.Receive(msg,msg_len);//Nhận nội dung thông điệp.
skConnect[msg_len] = 0; //Kết thúc chuỗi.
//Gửi thông điệp đến Client
skConnect.Send(&msg_len, sizeof(msg_len)); //Gửi chiều dài thông điệp.
skConnect.Send(msg,msg_len);//Gửi nội dung thông điệp.
}
skConnect.Close();
}

×