Thật ra ở đây mình không có tham vọng làm 1 Web Server thực sự như IIS hay Apache đâu? Mình chỉ muốn dùng Winsock để làm 1 chương trình có thể biến
máy tính bạn thành 1 máy chủ Web. Nghĩa là có ai đó truy cập vào thì nó sẽ trả
lại 1 Webpage.
Trước hết mình xin giới thiệu giao thức HTTP.
1. Giao thức HTTP
Bước 1: Giả sử người sử dụng gõ địa chỉ URL là: “http://webserver.com/Page?ID=1"
Lúc này thì Client tại người sử dụng sẽ Connect tới Webserver và gởi một nội dung Request như sau:
GET /Page?ID=1 HTTP/1.1 Host: webserver.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.9) Gecko/20071025 Firefox/2.0.0.9
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9 ,text/plain;q=0.8,image/png,*/*;q=0.5
Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300 Connection: keep-alive
Nội dung trên bao gồm:
- GET (lấy trang web). Ngoài ra còn có POST - Host: Tên SERVER muốn kết nối!
- User-Agent: Tên chương trình Web Browser - Ngoài ra còn một số thông tin về ngôn ngữ.
Nếu khi đã nhận được trang WEB mà trong Web còn có hình ảnh hay âm thanh
thì tiếp tục gởi Request tới Server Như:
GET /samples/images/IMAGE.jpg HTTP/1.1
Bước 2: Xử lý tại Server
Lúc này tại Web Server sẽ làm gì? Nó sẽ gửi lại 1 Header như sau:
HTTP/1.0 200 OK Server: <TÊN SERVER> Date:
Content-Type: text/html Accept-Ranges: bytes Last-Modified:
Content-Length: <kich thuoc trang WEB>
Và sau đó nó sẽ căn cứ vào yêu cầu của Client: GET /Page?ID=1 HTTP/1.1 để
gửi trả lại 1 trang HTML hoặc file hình ảnh, âm thanh… tương ứng.
Ví dụ như:
<html> <head> <title>DEMO WEBSERVER - WINSOCKC++</title> </head> <body> <h1>Hello eXecutve!</h1> <br> CopyRight 2007 by eXecutive;
stairwaytoheaven187@yahoo.com Địa chỉ email này đã được bảo vệ từ
spam bots, bạn cần kích hoạt Javascript để xem nó.
</body> </html>
2. Chương trình DEMO
Như vậy đã đủ. Chúng ta sẽ viết chương trình. Hàm Thiết lập lắng nghe trên PORT 80
#define MY_PORT 80 ..
..
int SetupIPWS(SOCKET& ListenSock,sockaddr_in& MyListenIP){ MyListenIP.sin_family = AF_INET;
MyListenIP.sin_port = htons( MY_PORT ); // PORT 80 MyListenIP.sin_addr.s_addr = INADDR_ANY; // IP của mình
int nResult = bind(ListenSock, (sockaddr*) &MyListenIP,sizeof(MyListenIP));
// Gán IP PORT vào SOCKET if (nResult == -1){
cout << "Loi khi thiet lap IP va PORT\n"; WSAGetLastError(); ShutdownWS(ListenSock); return 1; } return 0; } Hàm lắng nghe phục vụ kết nối.
void LoopListen(SOCKET& ListenSock,sockaddr_in& MyListenIP){ SOCKET NewConnection;
sockaddr_in ConnectClient; int nSizeAddr;
int nResult = listen(ListenSock,10); // Lắng nghe kết nối
if (nResult == -1){
cout << "Khong the lang nghe ket noi\n"; WSAGetLastError();
return; }
cout << "Dang lang nghe ket noi... tai IP: " << inet_ntoa(MyListenIP.sin_addr)
<< " PORT: " << MyListenIP.sin_port << "\nCTRL + C de STOP SERVER\n\n";
char lpBuffRevc[1024]={0}; // Nội dung nhận từ CLIENT (REQUEST) // Nội dung gửi trả lại CLIENT
"Server: eXecutive Winsock Server\r\n" "Date: Sat, 3 November 2007\r\n"
"Content-Type: text/html\r\n" "Accept-Ranges: bytes\r\n" "Content-Length: 187\r\n" "\r\n"; // Kết thức Header \n char html[] ="<html>"
"<head><title>DEMO WEBSERVER - WINSOCK C++ - CopyRight eXecutive</title></head> \r\n" "<body>\r\n" "<h1>Hello eXecutve!</h1>\r\n" "<br>\r\n" "CopyRight 2007 by eXecutive<br> \r\n" "
stairwaytoheaven187@yahoo.com Địa chỉ email này đã được bảo vệ từ
spam bots, bạn cần kích hoạt Javascript để xem nó.
\r\n"
"</body>\r\n"
"</html>\r\n\n"; // Kết thúc trang web bằng \n\n while (1){
nSizeAddr = sizeof(sockaddr); // Quan trọng! Xác định kích thước
sockaddr
NewConnection = accept(ListenSock, (sockaddr*) &ConnectClient, &nSizeAddr);
// Chấp nhận 1 kết nối
if (NewConnection == -1){
cout << "Loi ket noi tu Client\n"; continue;
}
cout << "Nhan ket noi tu: "<< inet_ntoa(ConnectClient.sin_addr) << "\n"; cout << "\nNoi dung nhan:\n\n";
// Xóa nội dung REQUEST trước và nhận REQUEST mới.
memset(lpBuffRevc,0,sizeof(lpBuffRevc));
/*
XỬ LÝ REQUEST => Ở ĐÂY MÌNH 1 KHÔNG 1 WEBSERVER CHUYỆN NGHIỆP NÊN BỎ QUA.
*/
// Gửi HEADER của SERVER và trang HTML send(NewConnection,headers,sizeof(headers),0); send(NewConnection,html,sizeof(html),0); cout << lpBuffRevc << "\n"; // Đóng kết nối! closesocket(NewConnection); } }
Có lẽ 1 chương trình kỳ cục. While(1) không có điều kiện kết thúc. Nhưng đó là cách hoat động của SERVER, 1 chương trình có thể chạy quanh năm suốt tháng. Do đó nên không có vấn đề gì?
Địa chỉ mà mình gõ là "http://localhost" tức là địa chỉ cục bộ =
"http://127.0.0.1" = "http://192.168.1.254" (nếu máy tính của mình đặt IP này) Download Demo Here
VI. DEMO MINI WEB BROWSER Lần này mình sẽ DEMO 1 Web Browser.