server
想在Linux下實現一個簡單的web Server並不難。一個最簡單的HTTP Server不過是一個高級的文件服務器,不斷地接收客戶端(瀏覽器)發送的HTTP請求,解析請求,處理請求,然後像客戶端回送數據。在大多是情況下,(GET、POST命令),服務求回傳給客戶端的都是文件(HTML 文檔, 圖片,JavaScript腳本等等)。
下面是一個極簡單的HTTP Server的demo,雖然只處理GET請求併發送單一文件,但基本展示了web server的框架。我的例子試圖將功能和結構做到最精簡,這樣,一個http server的基本結構,便一目瞭然。
#include<sys/socket.h>
#include<errno.h>
#include<netinet/in.h>
#include<string.h>
#include<stdio.h>
#define BUF_LEN 1028
#define SERVER_PORT 8080
//定義好的html頁面,實際情況下web server基本是從本地文件系統讀取html文件
const static char http_error_hdr[] = "HTTP/1.1 404 Not Found\r\nContent-type: text/html\r\n\r\n";
const static char http_html_hdr[] = "HTTP/1.1 200 OK\r\nContent-type: text/html\r\n\r\n";
const static char http_index_html[] =
"<html><head><title>Congrats!</title></head>"
"<body><h1>Welcome to our HTTP server demo!</h1>"
"<p>This is a just small test page.</body></html>";
//解析到HTTP請求的文件後,發送本地文件系統中的文件
//這裏,我們處理對index文件的請求,發送我們預定好的html文件
//呵呵,一切從簡!
int http_send_file(char *filename, int sockfd)
{
if(!strcmp(filename, "/")){
//通過write函數發送http響應報文;報文包括HTTP響應頭和響應內容--HTML文件
write(sockfd, http_html_hdr, strlen(http_html_hdr));
write(sockfd, http_index_html, strlen(http_index_html));
}
else{
// 文件未找到情況下發送404error響應
printf("%s:file not find!\n",filename);
write(sockfd, http_error_hdr, strlen(http_error_hdr));
}
return 0;
}
//HTTP請求解析
void serve(int sockfd){
char buf[BUF_LEN];
read(sockfd, buf, BUF_LEN);
if(!strncmp(buf, "GET", 3)){
char *file = buf + 4;
char *space = strchr(file, ' ');
*space = '\0';
http_send_file(file, sockfd);
}
else{
//其他HTTP請求處理,如POST,HEAD等 。這裏我們只處理GET
printf("unsupported request!\n");
return;
}
}
void main(){
int sockfd,err,newfd;
struct sockaddr_in addr;
//建立TCP套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd < 0){
perror("socket creation failed!\n");
return;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
//這裏要注意,端口號一定要使用htons先轉化爲網絡字節序,否則綁定的實際端口
//可能和你需要的不同
addr.sin_port = htons(SERVER_PORT);
addr.sin_addr.s_addr = INADDR_ANY;
if(bind(sockfd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in))){
perror("socket binding failed!\n");
return;
}
listen(sockfd, 128);
for(;;){
//不間斷接收HTTP請求並處理,這裏使用單線程,在實際情況下考慮到效率一般多線程
newfd = accept(sockfd, NULL, NULL);
serve(newfd);
close(newfd);
}
}