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



創(chuàng)建socket對(duì)象
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
???????if (0 > server_socket) {
printf("[服務(wù)器] 創(chuàng)建socket對(duì)象失敗,服務(wù)器啟動(dòng)失敗...\n");
return -1;
}
printf("[服務(wù)器] 創(chuàng)建socket成功....\n");
綁定服務(wù)器端口
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("[服務(wù)器]綁定端口%d失敗,服務(wù)器啟動(dòng)失敗\n", PORT);
return -2;
}
printf("[服務(wù)器] 綁定端口:%d成功....\n", PORT);
監(jiān)聽(tīng)服務(wù)器端口
int listen_ret = listen(server_socket, BACK_LOG);
if (0 > listen_ret) {
printf("監(jiān)聽(tīng)端口:%d失敗,服務(wù)器運(yùn)行失敗....\n", PORT);
return -3;
}
printf("[服務(wù)器] 監(jiān)聽(tīng)端口:%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("[服務(wù)器] 接收請(qǐng)求失敗,建立連接失敗... \n");
return -4;
}
printf("[服務(wù)器] 建立連接成功....\n");
獲取客戶端請(qǐng)求
char buffer[BUFFER_SIZE];
memset(buffer, 0, sizeof(buffer));
ssize_t data = recv(accept_socket, buffer, sizeof(buffer), RECV_FLAG);
if (data == 0) {
printf("[服務(wù)器] 超時(shí)或?qū)Χ酥鲃?dòng)關(guān)閉...\n");
break;
}
if (0 > data) {
printf("[服務(wù)器] 接收數(shù)據(jù)失敗...\n");
break;
}
printf("[服務(wù)器] 與客戶端建立連接成功...\n");
啟動(dòng)服務(wù)器
[服務(wù)器] 創(chuàng)建socket成功....
[服務(wù)器] 綁定端口:9999成功....
[服務(wù)器] 監(jiān)聽(tīng)端口:9999成功....
[服務(wù)器] 建立連接成功....
[服務(wù)器] 與客戶端建立連接成功...
解析前端(瀏覽器)發(fā)起的請(qǐng)求
tips: 本次只處理前端GET方式請(qǐng),即標(biāo)簽,或者從瀏覽器直接發(fā)起請(qǐng)求。
解析客戶端請(qǐng)求
此次項(xiàng)目獲取的頁(yè)面GET請(qǐng)求。
char req[100];
memset(req, 0, sizeof(req));
get_method_req(req_buffer, req);
url_decode(req);
printf("[服務(wù)器] 來(lái)自客戶端的請(qǐng)求==>%s\n", req);
定義字符數(shù)組存儲(chǔ)請(qǐng)求數(shù)據(jù)
char req[100]; memset(req, 0, sizeof(req));
將請(qǐng)求數(shù)據(jù)寫(xiě)入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ù)據(jù)重新編碼
瀏覽器會(huì)對(duì)中文進(jìn)行編碼,我們需要將其重新解碼回中文形式。

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);
}
運(yùn)行結(jié)果

問(wèn)題:如何關(guān)閉windows進(jìn)程
如果在啟動(dòng)web服務(wù)器時(shí)出現(xiàn)以下問(wèn)題

查詢指定端口
netstat -aon | findstr 端口號(hào)
netstat -aon|findstr 9999

終止指定進(jìn)程
taskkill /f /t /im 進(jìn)程ID
taskkill /f /t /im 10200

到此這篇關(guān)于基于C語(yǔ)言編寫(xiě)一個(gè)簡(jiǎn)單的Web服務(wù)器的文章就介紹到這了,更多相關(guān)C語(yǔ)言編寫(xiě)Web服務(wù)器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語(yǔ)言container of()函數(shù)案例詳解
這篇文章主要介紹了C語(yǔ)言container of()函數(shù)案例詳解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
c++中explicit與mutable關(guān)鍵字的深入探究
這篇文章主要給大家介紹了關(guān)于c++中explicit與mutable關(guān)鍵字的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-05-05
結(jié)構(gòu)體類型數(shù)據(jù)作為函數(shù)參數(shù)(三種方法)
將一個(gè)結(jié)構(gòu)體中變量中的數(shù)據(jù)傳遞給另一個(gè)函數(shù),有以下三種方法。需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助2013-10-10
C++中幾種將整數(shù)轉(zhuǎn)換成二進(jìn)制輸出的方法總結(jié)
下面小編就為大家?guī)?lái)一篇C++中幾種將整數(shù)轉(zhuǎn)換成二進(jìn)制輸出的方法總結(jié)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09
詳解C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用
這篇文章主要介紹了C++設(shè)計(jì)模式編程中責(zé)任鏈模式的應(yīng)用,責(zé)任鏈模式使多個(gè)對(duì)象都有機(jī)會(huì)處理請(qǐng)求,從而避免請(qǐng)求的發(fā)送者和接收者之間的耦合關(guān)系,需要的朋友可以參考下2016-03-03

