Sử dụng MFC:

Một phần của tài liệu 20101005023343_lvmmt7 (Trang 61 - 68)

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

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

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,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.Close();

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

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(); }

Một phần của tài liệu 20101005023343_lvmmt7 (Trang 61 - 68)

Tải bản đầy đủ (DOC)

(88 trang)
w