[VC++] Lập Trình Mạng Với Thư Viện Winsock - Tài Liệu Text - 123doc

[VC++] Lập Trình Mạng Với Thư Viện Winsock

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

<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>

<b>[VC++] L</b>

<b>ậ</b>

<b>p Trình M</b>

<b>ạ</b>

<b>ng </b>

</div><span class='text_page_counter'>(2)</span><div class='page_container' data-page=2>

<b>[VC++] L</b>

<b>ập Tr</b>

<b>ình M</b>

<b>ạng Với Thư Viện Winsock</b>

I. KHỞI ĐỘNG WINSOCK

Để lập trình được Winsock chúng ta sẽ khai báo thư viện winsock2.h (chứa các prototypes) và 1 file lib (chính là file .cpp đã được biên dịch thành .lib) có tên là ws2_2.lib.

Bây giờ hãy tạo 1 project Windows32 Console Project.

Lưu ý: Chúng ta không khai báo trong file .cpp có hàm main mà khai báo trong

file stdafx.h. Đây là cách khai báo thư viện của Visual C++.

#include <tchar.h> ...

#include <winsock2.h>

#pragma comment (lib,"ws2_32.lib")

Và bây giờ sẽ là những hàm để khởi tạo Winsock:

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

Trong đó:

- wVersionRequested là phiên bản thư viện mà mình sử dụng. Ở đây sẽ là giá trị 0x0202 có nghĩa là phiên bản 2.2. Chúng ta có thể dùng macro

MAKEWORD(2,2) để trả về giá trị 0x0202.

- lpWSData là một số thông tin bổ sung sẽ được trả về sau khi gọi khởi tạo

Winsock.:

typedef struct WSAData {

WORD wVersion; // Phiên bản hiện tại

WORD wHighVersion; // Phiên bản có thể hỗ trợ

char szDescription[WSADESCRIPTION_LEN + 1]; // Ghi chú

char szSystemStatus[WSASYS_STATUS_LEN + 1]; // Trạng thái hệ

thống

unsigned short iMaxSockets; // Không sử dụng từ Version 2 trở đi

unsigned short iMaxUdpDg; // Không sử dụng từ Version 2 trở đi

char FAR * lpVendorInfo; // Không sử dụng từ Version 2 trở đi

} WSADATA, FAR * LPWSADATA;

Và cuối cùng là hàm hủy Winsock khi kết thúc chương trình. nt WSACleanup (void);

</div><span class='text_page_counter'>(3)</span><div class='page_container' data-page=3>

using namespace std;

int _tmain(int argc, _TCHAR* argv[]) {

WSADATA SData;

int iResult = WSAStartup(0x0202,&SData); if (iResult!=0){

cout << "KHONG THE KHOI DONG WINSOCK"; return 1;

}

II. SOCKET 1. Socket là gì?

“Socket là một cổng logic mà một chương trình sử dụng để kết nối với một chương trình khác chạy trên một máy tính khác trên Internet. Chương trình mạng có thể sử dụng nhiều Socket cùng một lúc, nhờ đó nhiều chương trình có thể sử dụng Internet cùng một lúc.”

Ở đây ta hiểu Socket trong Winsock như là một “phương tiện” để ứng dụng

mạng có thể trao đổi dữ liệu. Nghĩa là 1 Server thì sẽ cần một Socket để lắng

nghe, chờ đợi các kết nối từ client và Client thì phải cần có một Socket để kết

nối tới Sever.

2. Khởi tạo Socket

Chúng ta sử dụng cấu trúc SOCKET để lưu giữ 1 Socket. Và có thể sử dụng hàm sau đây để tạo Socket.

SOCKET socket ( int af,

int type, int protocol );

Ví dụ:

SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);

Trong đó:

* af: Là một con số ID để quyết định Socket của chúng ta sử dụng giao thức (protocol) để kết nối.

</div><span class='text_page_counter'>(4)</span><div class='page_container' data-page=4>

liệu)

- AF_NETBIOS: NetBIOS (Giao thức dùng tên máy để truyền dữ liệu)

- AF_APPLETALK: AppleTalk - AF_ATM: ATM

Và ở trong Tut này mình chỉ nghiên cứu tới TCP/IP.* type: Quy định giao thức vận chuyển dữ liệu

Ví dụ với giao thức TCP/IP thì có 2 giao thức cốt lõi là UDP và TCP:

- SOCK_DGRAM: Hay là giao thức UDP. Khi chương trình chúng ta dùng

UDP để truyền dữ liệu thì chuyện gì sẽ xảy ra giữa bên gởi và bên nhận? Bên gửi cứ gửi và gửi và nó khơng hề quan tâm tới vấn đề bên nhận có nhận được

nó hay khơng?

=> Ưu điểm: Tốc độ truyền dữ liệu nhanh.

=> Nhược điểm: Khả năng sai, mất dữ liệu sẽ rất lớn.

Vậy dùng UDP khi nào? Những ứng dụng cần dữ liệu tức thời như:

- Chương trình nghe nhạc trực tuyến. Vấn đề sai bit (vấp khi nghe nhạc) không

quan trọng mấy vì u cầu của nó là đảm bảo tốc độ nhanh.

- Chương trình Chat chẳn hạn.

- Hoặc GameOnline (thỉnh thoảng bạn bị trường hợp LAG chính là do bị mất

dữ liệu trên đường truyền đó)

- SOCK_STREAM: Đây là giao thức TCP. Nó ngược với UDP vì nó đảm bảo

giữa bên gửi và bên nhận dữ liệu phải chính xác. Vì vậy 2 bên sẽ phải bắt tay rất nhiều lần khi truyền được dữ liệu (ví dụ như bên gửi sẽ gửi n gói tin

(packet), bên nhận sẽ kiểm tra có bị mất hay sai gói tin nào hay khơng, nếu đủ

thì nó sẽ u cầu bên gửi gửi tiếp n gói tin tiếp theo, ngược lại thì nó sẽ u cầu gửi lại)

=> Ưu điểm: Chất lượng gởi tin cậy.=> Nhược điểm: Chậm hơn UDP.

Những ứng dụng như WEB, MAIL, FTP,…

- SOCK_RAW:

Là giao thức để kiểm soát mạng, kiểm tra kết nối…

Ví dụ:

Start -> Run -> CMD: “ping diendantinhoc.com”.

Nếu bạn nhận được Reply có nghĩa là giữa máy tính của bạn với máy chủ

“diendantinhoc.com” có “thơng mạng” với nhau. Và gói tin mà bạn PING

</div><span class='text_page_counter'>(5)</span><div class='page_container' data-page=5>

* protocol: Chỉ định rõ lại giao thức mà thôi. Vì SOCK_RAW có 2 protocol là ICMP và RAW nên nó cần điều này

- SOCK_DGREAM -> protocol là: IPPROTO_UDP - SOCK_STREAM -> protocol là: IPPROTO_IP

- SOCK_RAW -> protocol có thể là: IPPROTO_RAW hay IPPROTO_ICMP Các bạn có thể tham khảo thêm bảng thể hiện các thuộc tính của hàm

</div><span class='text_page_counter'>(6)</span><div class='page_container' data-page=6>

hostent* pMyServer = gethostbyname(lpName);

u_long myIP = *(u_long*)pMyServer->h_addr_list[0]; strcpy(lpMyIP,inet_ntoa(*(in_addr*)&myIP));

// --- // Đưa thông tin IP và PORT cho SOCKET

nResult = bind(*sock,(sockaddr*)pAddr,sizeof(sockaddr)); if (nResult == -1){

cout << "Loi thiet lap IP va PORT\n"; HuyWinsock(sock);

return 1; }

cout << "Dang lang nghe ket noi tren IP: " << lpMyIP << " port: " << MY_PORT << "\n\n";

int nAddrLen; int nRevc; int nSend;

sockaddr_in IPClient;

char buff[512]={0}; while (1){

// Nhận kết nối từ CLIENT

nAddrLen = sizeof(sockaddr_in); nRevc = recvfrom(*sock,buff,sizeof(buff),0, (sockaddr*)&IPClient,&nAddrLen);

buff[nRevc-1] = 0;

cout << "Nhan ket toi tu CLIENT IP: " << inet_ntoa(IPClient.sin_addr) << "\n";

cout << "Noi dung: \"" << buff << "\"\n"; // Kiểm tra yêu cầu của CLIENT

</div><span class='text_page_counter'>(7)</span><div class='page_container' data-page=7>

nSend =

sendto(*sock,lpMyIP,strlen(lpMyIP),0,(sockaddr*)&IPClient,sizeof(IPClient));

cout << "Gui lai client: " << nSend << " Bytes\n"; }

else{

cout << "Khong hieu yeu cau tu Client!\n"; }

cout << "\n"; }

b. CLIENT

-> Nhiệm vụ chính của CLIENT là gửi 1 gói tin BROADCAST với PORT quy định sẵn

Trong chương trình của CLIENT có 1 hàm rất quan trọng để cho phép

SOCKET gởi tới địa chỉ BROADCAST

setsockopt(*sock,SOL_SOCKET,SO_BROADCAST,(char*)&b SockBroadcast,sizeof(BOOL));

- Op tùy chọn ở đây là : SO_BROADCAST (gởi gói tin Broadcast);

- bSockBroadcast: TRUE (cho phép), FALSE (khơng cho phép). Hàm này có rất nhiều Option. Các bạn có thể tham khảo thêm MSDN. int FindServer(SOCKET* sock,sockaddr_in* pServerAddr){ BOOL bSockBroadcast=true;

setsockopt(*sock,SOL_SOCKET,SO_BROADCAST,(char*)&bSockBroadcast,sizeof(BOOL));

pServerAddr->sin_family = AF_INET;

pServerAddr->sin_port = htons(MY_PORT);

pServerAddr->sin_addr.S_un.S_addr = inet_addr("255.255.255.255"); // Địa

chỉ đích là MULTICAST

</div><span class='text_page_counter'>(8)</span><div class='page_container' data-page=8>

int nRevc;

int nAddrLen;

char buff[512]="IP may chu dau???"; // Thông tin gửi tới máy chủ

// Gửi tới máy chủ nSend =

sendto(*sock,buff,sizeof(buff),0,(sockaddr*)pServerAddr,sizeof(sockaddr_in));

cout << "Da gui " << nSend << " bytes\n";

// Nhận hồi âm của máy chủ

sockaddr_in ServerIP;

nAddrLen = sizeof(sockaddr_in);

nRevc = recvfrom(*sock,buff,sizeof(buff),0, (sockaddr*)&ServerIP, &nAddrLen);

buff[nRevc] = 0;

cout << "Da nhan " << nRevc << " bytes\n";

cout << "Noi dung nhan <IP SERVER>: " << buff << "\n"; return 0;

}

c. Download Demo here Còn tiếp ...

</div><!--links-->

Từ khóa » Thư Viện Ws2tcpip.h