基于C語言編寫一個簡單的Web服務器
概述
C語言可以干大事,我們基于C語言可以完成一個簡易的Web服務器。當你能夠自行完成web服務器,你會對C語言有更深入的理解。對于網絡編程,字符串的使用,文件使用等等都會有很大的提高。
關于網絡的TCP協(xié)議在這里不在多說,大家可以查閱些資料。
工具
開發(fā)工具: CLion,編譯器
演示效果圖



創(chuàng)建socket對象
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
???????if (0 > server_socket) {
printf("[服務器] 創(chuàng)建socket對象失敗,服務器啟動失敗...\n");
return -1;
}
printf("[服務器] 創(chuàng)建socket成功....\n");
綁定服務器端口
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
int bind_ret = bind(server_socket, (struct sockaddr*) &my_addr, sizeof(my_addr));
if (0 > bind_ret) {
printf("[服務器]綁定端口%d失敗,服務器啟動失敗\n", PORT);
return -2;
}
printf("[服務器] 綁定端口:%d成功....\n", PORT);
監(jiān)聽服務器端口
int listen_ret = listen(server_socket, BACK_LOG);
if (0 > listen_ret) {
printf("監(jiān)聽端口:%d失敗,服務器運行失敗....\n", PORT);
return -3;
}
printf("[服務器] 監(jiān)聽端口:%d成功....\n", PORT);
建立連接
struct sockaddr_in accept_in;
socklen_t socklen = sizeof(accept_in);
int accept_socket = accept(server_socket, (struct sockaddr *) &accept_in, &socklen);
if (-1 == accept_socket) {
printf("[服務器] 接收請求失敗,建立連接失敗... \n");
return -4;
}
printf("[服務器] 建立連接成功....\n");
獲取客戶端請求
char buffer[BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
ssize_t data = recv(accept_socket, buffer, sizeof(buffer), RECV_FLAG);
if (data == 0) {
printf("[服務器] 超時或對端主動關閉...\n");
break;
}
if (0 > data) {
printf("[服務器] 接收數(shù)據失敗...\n");
break;
}
printf("[服務器] 與客戶端建立連接成功...\n");
啟動服務器
[服務器] 創(chuàng)建socket成功....
[服務器] 綁定端口:9999成功....
[服務器] 監(jiān)聽端口:9999成功....
[服務器] 建立連接成功....
[服務器] 與客戶端建立連接成功...
解析前端(瀏覽器)發(fā)起的請求
tips: 本次只處理前端GET方式請,即標簽,或者從瀏覽器直接發(fā)起請求。
解析客戶端請求
此次項目獲取的頁面GET請求。
char req[100];
memset(req, 0, sizeof(req));
get_method_req(req_buffer, req);
url_decode(req);
printf("[服務器] 來自客戶端的請求==>%s\n", req);
定義字符數(shù)組存儲請求數(shù)據
char req[100]; memset(req, 0, sizeof(req));
將請求數(shù)據寫入req數(shù)組
void get_method_req(char *req_buff, char *req);
void get_method_req(char *req_buff, char *req) {
int count = 0;
for (int i = 6; i < strlen(buffer); i++) {
if (buffer[i] == ' ') {
break;
}
res[count++] = buffer[i];
}
res[count] = '\0';
}
將瀏覽器中的數(shù)據重新編碼
瀏覽器會對中文進行編碼,我們需要將其重新解碼回中文形式。

int hex2dec(char c);
void url_decode(char url[]);
int hex2dec(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'f') {
return c - 'a' + 10;
} else if ('A' <= c && c <= 'F') {
return c - 'A' + 10;
} else {
return -1;
}
}
void url_decode(char url[]) {
int i = 0;
int len = strlen(url);
int res_len = 0;
char res[100];
for (i = 0; i < len; ++i) {
char c = url[i];
if (c != '%') {
res[res_len++] = c;
} else {
char c1 = url[++i];
char c0 = url[++i];
int num = 0;
num = hex2dec(c1) * 16 + hex2dec(c0);
res[res_len++] = num;
}
}
res[res_len] = '\0';
strcpy(url, res);
}
運行結果

問題:如何關閉windows進程
如果在啟動web服務器時出現(xiàn)以下問題

查詢指定端口
netstat -aon | findstr 端口號
netstat -aon|findstr 9999

終止指定進程
taskkill /f /t /im 進程ID
taskkill /f /t /im 10200

到此這篇關于基于C語言編寫一個簡單的Web服務器的文章就介紹到這了,更多相關C語言編寫Web服務器內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
結構體類型數(shù)據作為函數(shù)參數(shù)(三種方法)
將一個結構體中變量中的數(shù)據傳遞給另一個函數(shù),有以下三種方法。需要的朋友可以過來參考下,希望對大家有所幫助2013-10-10

