溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

c語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單web服務(wù)器

發(fā)布時(shí)間:2020-07-04 08:04:14 來(lái)源:網(wǎng)絡(luò) 閱讀:8190 作者:超級(jí)極客 欄目:編程語(yǔ)言

1http簡(jiǎn)單介紹

http超文本傳輸協(xié)議:host主機(jī)地址:port端口/url

host會(huì)被DNS服務(wù)器 解析成IP地址,所以有時(shí)候可以直接用域名,

http默認(rèn)訪問(wèn)80端口,https默認(rèn)訪問(wèn)443端口


大致流程就是:瀏覽器輸入地址后,首先和web服務(wù)器建立tcp連接,

然后瀏覽器發(fā)送http請(qǐng)求報(bào)文, web服務(wù)器響應(yīng)處理這個(gè)報(bào)文,

然后給他回復(fù)一個(gè)響應(yīng),然后服務(wù)器主動(dòng)斷開(kāi)連接。





2http請(qǐng)求報(bào)文格式

c語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單web服務(wù)器


首先第一個(gè)就是請(qǐng)求的方法,方法有一下這些:
GET,POST,HEAD,PUT,DELETE,OPTIONS,TRACE,CONNECT;


1GET

在瀏覽器輸入的網(wǎng)址,瀏覽器就會(huì)發(fā)送GET的http報(bào)文請(qǐng)求。

如果不寫url 默認(rèn)就是 "/"  服務(wù)器 可根據(jù)這個(gè)響應(yīng)對(duì)應(yīng)的頁(yè)面.

頭部信息就包含一些重要的請(qǐng)求信息,如主機(jī)地址.

瀏覽器版本 , 手機(jī)的頁(yè)面就是根據(jù)這個(gè)去做的.

GET 攜帶參數(shù)是在url里面的, POST是攜帶在包體里面的.

包體成為body,請(qǐng)求頭部叫做head。

GET傳遞參數(shù),格式  /url?username=xxx&passwd=bbb  通過(guò)問(wèn)號(hào)解析參數(shù)部分

url的傳遞參數(shù)是有限制的,每個(gè)瀏覽器限制都不一樣。url不允許有回車換行



2POST 

POST也是一個(gè)請(qǐng)求操作,他的數(shù)據(jù)參數(shù)攜帶在http請(qǐng)求的body里面。

所有的參數(shù)都不允許有回車換行的存在, 很多時(shí)候如果必須要攜帶

回車換行的話,必須先把數(shù)據(jù)轉(zhuǎn)換成base64編碼,因?yàn)樗鼪](méi)有回車換成.他是解決網(wǎng)絡(luò)傳輸?shù)某S梅椒ā?/span>





3http響應(yīng)報(bào)文格式

c語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單web服務(wù)器


1狀態(tài)碼:請(qǐng)求是否成功,狀態(tài)碼描述:成功或失敗的原因

有時(shí)候訪問(wèn)一網(wǎng)頁(yè) 會(huì)出現(xiàn)404,這個(gè)404就是這個(gè)狀態(tài)碼.




4http數(shù)據(jù)傳輸模式

1傳輸中兩個(gè)重要的參數(shù): 寫在頭里面

transfer-encoding:identity,chunked表示當(dāng)前這個(gè)body是什么協(xié)議發(fā)過(guò)來(lái)的

content-length:length:數(shù)據(jù)包的長(zhǎng)度



2identity 直接發(fā)送模式,length在后面表示數(shù)據(jù)長(zhǎng)度


3chunked 模式,后面跟的是每一個(gè)chunk包 [包頭,包數(shù)據(jù)]

包頭:第一個(gè)字節(jié)表示一個(gè)ASSIC數(shù)據(jù),第二個(gè)字節(jié)也是ASSIC數(shù)據(jù)

兩個(gè)字節(jié)加起來(lái),組成一個(gè)16進(jìn)制數(shù)據(jù)。

后面兩個(gè)字節(jié),固定的0d0a(回車換行符)兩個(gè)字節(jié)這4個(gè)字節(jié)就是一個(gè)chunk的包頭,

后面的數(shù)據(jù)包 根據(jù)前面的兩個(gè)字節(jié)來(lái)決定。數(shù)據(jù)包的結(jié)束標(biāo)志是

30  0d  0a  30ascll碼代表的是0

也就是說(shuō)chunk包的結(jié)束:是遇到一個(gè)為等于0的chunk結(jié)束。

然后把這個(gè)包整合一下,形成完整的數(shù)據(jù)。





5http狀態(tài)碼和表

/*

{

[100] = "Continue",

[101] = "Switching Protocols",

[200] = "OK",

[201] = "Created",

[202] = "Accepted",

[203] = "Non-Authoritative Information",

[204] = "No Content",

[205] = "Reset Content",

[206] = "Partial Content",

[300] = "Multiple Choices",

[301] = "Moved Permanently",

[302] = "Found",

[303] = "See Other",

[304] = "Not Modified",

[305] = "Use Proxy",

[307] = "Temporary Redirect",

[400] = "Bad Request",

[401] = "Unauthorized",

[402] = "Payment Required",

[403] = "Forbidden",

[404] = "Not Found",

[405] = "Method Not Allowed",

[406] = "Not Acceptable",

[407] = "Proxy Authentication Required",

[408] = "Request Time-out",

[409] = "Conflict",

[410] = "Gone",

[411] = "Length Required",

[412] = "Precondition Failed",

[413] = "Request Entity Too Large",

[414] = "Request-URI Too Large",

[415] = "Unsupported Media Type",

[416] = "Requested range not satisfiable",

[417] = "Expectation Failed",

[500] = "Internal Server Error",

[501] = "Not Implemented",

[502] = "Bad Gateway",

[503] = "Service Unavailable",

[504] = "Gateway Time-out",

[505] = "HTTP Version not supported",

}

*/





6使用http_parmer解析 URL讀取 然后返回給客戶端

//解析我們的http報(bào)文
http_parser p;
http_parser_init(&p,HTTP_REQUEST);
http_parser_settings s;
http_parser_settings_init(&s);
//解析到了url 回調(diào)
s.on_url = ws_on_url;
//重置解析信息
init_ws_params();
// 解析器執(zhí)行。返回解析的字節(jié)數(shù)
http_parser_execute(&p,&s,http_req,len);
//設(shè)置回調(diào)函數(shù)
switch (p.method)  //報(bào)文響應(yīng)的方式
{
case HTTP_GET:
{
int len_URL = filter_url(WS_HTTP.url);
//訪問(wèn)的網(wǎng)頁(yè)  
if (strncmp("/", WS_HTTP.url, len_URL) == 0){ //訪問(wèn)test這個(gè)html
strncpy(WS_HTTP.url, "www_root/index.html", strlen("www_root/index.html"));
}
else if (strncmp("/test", WS_HTTP.url, len_URL) == 0){ //訪問(wèn)默認(rèn)的url 根目錄
strncpy(WS_HTTP.url, "www_root/test.html", strlen("www_root/test.html"));
}
char* file_data = open_files(WS_HTTP.url);
//發(fā)送報(bào)文  也就是響應(yīng)客戶端
//釋放內(nèi)存
free(file_data);
}
break;
case HTTP_POST:
break;
}
//end
printf("\n");


讀取文件
static char* 
open_files(char* filename)
{
	//讀取這個(gè)文件
	FILE* f = fopen(filename,"rb");
	//文件大小
	int file_size = 0;
	fseek(f,0,SEEK_END);
	file_size = ftell(f);
	//指針又到文件頭
	fseek(f, 0, 0);

	char* file_data = malloc(file_size + 1);
	fread(file_data, file_size,1, f);
	file_data[file_size] = 0;


	fclose(f);
	return file_data;
	
}




7響應(yīng)請(qǐng)求報(bào)文

//使用identity來(lái)發(fā)送響應(yīng)報(bào)文 
static void
write_ok_identity(int sock, char* body)
{
int len = strlen(body);
//使用直接模式 transfer-encoding:identity
char* send_line = malloc(len + 8096);
memset(send_line, 0, sizeof(send_line));
//回應(yīng)http的頭
sprintf(send_line, "HTTP/1.1  %d %s\r\n", 200, "OK");
//設(shè)置頭部的一些信息  比如傳送模式 body的長(zhǎng)度
char* walk = send_line;
//跳過(guò)這個(gè)頭部
walk = walk + strlen(walk);
sprintf(walk,"transfer-encoding:%s\r\n","identity");
//body的長(zhǎng)度
walk = walk + strlen(walk);  //頭結(jié)束
sprintf(walk, "content-length: %d\r\n\r\n0", len);
//寫入數(shù)據(jù)部分
walk = walk + strlen(walk);
sprintf(walk, "%s", body);
//發(fā)送報(bào)文 響應(yīng)  給客戶端
send(sock, send_line, strlen(send_line), 0);
free(send_line);
walk = NULL;
}





向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI