基于C語言編寫一個(gè)簡單的Web服務(wù)器
概述
C語言可以干大事,我們基于C語言可以完成一個(gè)簡易的Web服務(wù)器。當(dāng)你能夠自行完成web服務(wù)器,你會(huì)對C語言有更深入的理解。對于網(wǎng)絡(luò)編程,字符串的使用,文件使用等等都會(huì)有很大的提高。
關(guān)于網(wǎng)絡(luò)的TCP協(xié)議在這里不在多說,大家可以查閱些資料。
工具
開發(fā)工具: CLion,編譯器
演示效果圖
創(chuàng)建socket對象
int server_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ???????if (0 > server_socket) { printf("[服務(wù)器] 創(chuàng)建socket對象失敗,服務(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)聽服務(wù)器端口
int listen_ret = listen(server_socket, BACK_LOG); if (0 > listen_ret) { printf("監(jiān)聽端口:%d失敗,服務(wù)器運(yùn)行失敗....\n", PORT); return -3; } printf("[服務(wù)器] 監(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("[服務(wù)器] 接收請求失敗,建立連接失敗... \n"); return -4; } printf("[服務(wù)器] 建立連接成功....\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("[服務(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)聽端口:9999成功....
[服務(wù)器] 建立連接成功....
[服務(wù)器] 與客戶端建立連接成功...
解析前端(瀏覽器)發(fā)起的請求
tips: 本次只處理前端GET方式請,即標(biāo)簽,或者從瀏覽器直接發(fā)起請求。
解析客戶端請求
此次項(xiàng)目獲取的頁面GET請求。
char req[100]; memset(req, 0, sizeof(req)); get_method_req(req_buffer, req); url_decode(req); printf("[服務(wù)器] 來自客戶端的請求==>%s\n", req);
定義字符數(shù)組存儲(chǔ)請求數(shù)據(jù)
char req[100]; memset(req, 0, sizeof(req));
將請求數(shù)據(jù)寫入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ì)對中文進(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é)果
問題:如何關(guān)閉windows進(jìn)程
如果在啟動(dòng)web服務(wù)器時(shí)出現(xià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語言編寫一個(gè)簡單的Web服務(wù)器的文章就介紹到這了,更多相關(guān)C語言編寫Web服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++中指針的數(shù)據(jù)類型和運(yùn)算相關(guān)知識(shí)小結(jié)
這篇文章主要介紹了C++中指針的數(shù)據(jù)類型和運(yùn)算相關(guān)知識(shí)小結(jié),是C++入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下2015-09-09C語言實(shí)現(xiàn)跨文件傳輸數(shù)據(jù)的幾種方式
C語言是一種強(qiáng)大的、通用的編程語言,常用于系統(tǒng)級(jí)編程,包括硬件交互,如中斷處理和數(shù)據(jù)采集,在本文中,我們將深入探討如何使用C語言進(jìn)行跨文件數(shù)據(jù)傳輸,文中有相關(guān)的代碼供大家參考,需要的朋友可以參考下2024-08-08深入解析C++編程中基類與基類的繼承的相關(guān)知識(shí)
這篇文章主要介紹了C++編程中基類與基類的繼承的相關(guān)知識(shí),包括多個(gè)基類繼承與虛擬基類等重要知識(shí),需要的朋友可以參考下2016-01-01C++實(shí)現(xiàn)棧與分析棧的知識(shí)點(diǎn)
這篇文章主要介紹了C++實(shí)現(xiàn)棧與分析棧的知識(shí)點(diǎn),棧(stack)是計(jì)算機(jī)中常用的一種線性數(shù)據(jù)結(jié)構(gòu),經(jīng)常有資料使用“操作受限”來形容棧,因?yàn)樗膲喝霔:蛷棾鰲2僮髦荒茉跅m斶M(jìn)行,下文更多相關(guān)資料,需要的小伙伴可以參考一下2022-03-03如何通過函數(shù)指針調(diào)用函數(shù)(實(shí)現(xiàn)代碼)
指針可以不但可以指向一個(gè)整形,浮點(diǎn)型,字符型,字符串型的變量,也可以指向相應(yīng)的數(shù)組,而且還可以指向一個(gè)函數(shù)2013-09-09