Bài này sẽ hướng dẫn các bạn làm 1 ứng dụng client-server cơ bản.
I. Socket
Cơ bản nhất khi lập trình mạng chính là khái niệm socket.
Socket nghĩa là 1 cái "ổ cắm". Có thể tưởng tượng thế này (xin lỗi vì vẽ hơi xấu ^_^):
Tất nhiên đường dây ở trên chỉ là đường dây ảo.
Toàn bộ quá trình trao đổi sẽ diễn ra qua các socket.
1 socket khi được tạo có thể có các trạng thái: bind (gắn vào 1 cổng), listen (chờ kết nối), connected (đã kết nối với socket khác).
Socket khi chỉ bind vào 1 cổng có thể nhận các tin được gửi từ mạng đến cổng đó.
Để tạo 1 socket ta dùng hàm sau:
SOCKET sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
- Tham số thứ nhất là loại kết nối, thường là AF_INET.
- Tham số thứ 2 là kiểu kết nối, SOCK_STREAM cho TCP, SOCK_DGRAM cho UDP và các kiểu connectionless (không cần kết nối).
- Tham số thứ 3 là giao thức, IPPROTO_TCP chỉ dùng cho SOCK_STREAM.
(Để biết thêm về các loại giao thức và kết nối, vào MSDN, ở đây chỉ giải thích qua).
*Chú ý: Ta cần thêm thư viện ws2_32.lib và include file winsock2.h. Để dùng các hàm winsock, trước tiên cần làm thế này:
Mã:
WSADATA wsadata;WSAStartup (&wsadata, MAKEWORD (2, 2));
Hàm API WSAStartup sẽ khởi tạo winsock cho ứng dung với phiên bản yêu cầu, ở đây là 2.2, các thống số về winsock sẽ tra lại trong wsadata
II. Khởi tạo phía server
Các bước thực hiện trên server:
B1: Tạo socket TCP.
Mã:
SOCKET ListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
<font size="3">B2: Bind (gắn) socket này vào 1 cổng, client sẽ nối đến server qua cổng này.
Ở đây dùng cổng 4444:
Mã:
sockaddr_in name;name.sin_family = AF_INET;name.sin_addr.s_addr = inet_addr("127.0.0.1");name.sin_port = htons(4444);bind (ListenSock, (sockaddr*) &name, sizeof (name));
127.0.0.1 là địa chỉ IP quy định đặt cho localhost, cũng có thể dùng địa chỉ ip trong mạng lan như 10.0.0.1....
Hàm inet_addr ("x.x.x.x") chuyển chuỗi địa chỉ ip thành 1 số 4 byte. Và ngược lại là hàm inet_ntoa (long x), chuyển địa chỉ dạng số 4 byte sang chuổi.
B3: Cho socket này listen, chờ kết nối.
Mã:
listen (ListenSock, 1);
Tham số thứ 2 của hàm API listen là backlog, em cũng ko hiểu rõ, nhưng thường được để là 1. Hàm listen là 1 vòng lặp, sẽ kết thúc nếu có 1 yêu cầu kết nối.
B4: Có yêu cầu kết nối. Nếu đồng ý, sẽ có 1 socket khác được tạo và trao đổi với client qua socket này, còn socket để listen sẽ đóng lại và có thể nghe trên 1 cổng khác để tiếp nhận 1 client khác.
Mã:
sockaddr_in clientaddr;SOCKET client = accept (ListenSock, (sockaddr*) &clientaddr, sizeof (clientaddr));closesocket (ListenSock);
Nếu muốn, lặp lại quá trình trên để phục vụ 1 client khác:
Mã:
ListenSock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);.....
Tham số thứ hai trong accept sẽ nhận lại thông tin về client yêu cầu kết nối như địa chỉ ip của client... và bạn có thể ngắt kết nối với client này nếu ko muốn và lặp lại quá trình nghe trên ListenSocket.
Mã:
closesocket (client);
II. Khởi tạo phía client
B1: Tạo socket TCP
Mã:
SOCKET sock = socket (AF_iNET, SOCK_STREAM, IPPROTO_TCP);
B2: Kết nối đên server (kết nối đên cái socket đang listen của server)
Mã:
sockaddr_in name;name.sin_family = AF_INET;name.sin_addr.s_addr = inet_addr("127.0.0.1");name.sin_port = htons(4444);connect (sock, (sockađr*) &name, sizeof (name));
127.0.0.1 là địa chỉ máy server, vì thử nghiệm sever và client trên cùng 1 máy nên dùng cùng 1 địa chỉ ip.
4444 là port (cổng) mà socket phía server được bind vào.
Có thể lấy giá trị lỗi tra về qua hàm WSAGetLastError.
<font size="5">IV. Gửi và nhận dữ liệu
Thông qua phân tích dữ liệu Google từ 86 quốc gia, mới đây, một công ty tại Anh đã công bố bảng xếp hạng kích tấc "cậu nhỏ" của các nước trên thế giới. Kết quả, hầu hết các nước xếp ở nhóm đầu của...
"Chim" của chàng trai Việt thuộc...