題目描述:? ? ??
-
實(shí)現(xiàn)提供靜態(tài)網(wǎng)頁服務(wù)的web服務(wù)器
-
實(shí)現(xiàn)提供cgi動(dòng)態(tài)網(wǎng)頁服務(wù)的web服務(wù)器
-
web服務(wù)器實(shí)現(xiàn)多進(jìn)程服務(wù)
一、綜合實(shí)踐目的與要求
Linux程序設(shè)計(jì)綜合實(shí)踐是我們軟件工程專業(yè)必須經(jīng)歷的過程,是理論與實(shí)踐相結(jié)合的重要方式,使我們?cè)趯?shí)踐中了解Linux操作系統(tǒng)、在實(shí)踐中鞏固知識(shí)。實(shí)習(xí)是個(gè)人綜合能力的檢驗(yàn),除了有一定的課本知識(shí)外,還需有一定的實(shí)踐動(dòng)手能力,操作能力。實(shí)習(xí)是對(duì)我們軟件工程專業(yè)知識(shí)的一種檢驗(yàn),它讓我們學(xué)到了很多在課堂上根本就學(xué)不到的知識(shí),技能開闊視野,又能增長(zhǎng)見識(shí),為我們走向工作打下堅(jiān)實(shí)的基礎(chǔ),也是我們走向工作崗位的第一步。為了將所學(xué)的專業(yè)理論知識(shí)運(yùn)用與實(shí)踐,在實(shí)踐中結(jié)合理論加深對(duì)其認(rèn)識(shí)和總結(jié)。將專業(yè)與實(shí)際接軌,逐步認(rèn)識(shí),體會(huì),從而更好地將所學(xué)的運(yùn)用到工作中去。接觸操作系統(tǒng),認(rèn)識(shí)linux,學(xué)會(huì)C語言,學(xué)會(huì)向老師提問,學(xué)會(huì)團(tuán)結(jié)協(xié)作。通過深入編寫程序,了解Linux和操作系統(tǒng)的現(xiàn)狀,可加深理解并鞏固所學(xué)專業(yè)知識(shí),進(jìn)一步提高認(rèn)識(shí)問題、分析問題、解決問題的能力,使一個(gè)軟件工程專業(yè)的學(xué)生應(yīng)在linux綜合實(shí)踐與設(shè)計(jì)中用所學(xué)知識(shí)解決現(xiàn)實(shí)中的一些問題,對(duì)所學(xué)專業(yè)理論和實(shí)踐知識(shí)進(jìn)行鞏固,同時(shí)提高自學(xué)、獨(dú)立開發(fā)和協(xié)作能力,為走向工作崗位奠定良好的基礎(chǔ)。
綜合實(shí)踐的要求是: 一、要求學(xué)生在實(shí)習(xí)過程中認(rèn)真學(xué)習(xí)技術(shù)知識(shí),積極與指導(dǎo)老師和同學(xué)配合;二、在前期,按時(shí)到勤,認(rèn)真學(xué)習(xí)。積極做好實(shí)習(xí)日志,能夠理解當(dāng)天的內(nèi)容。對(duì)技術(shù)的理論知識(shí)要及時(shí)實(shí)踐;三、在后期,積極與同學(xué)溝通,認(rèn)真完成項(xiàng)目要求的內(nèi)容。在這個(gè)過程中要與老師同學(xué)多做溝通,通過探討項(xiàng)目的`解決方案以及進(jìn)展。
二、綜合實(shí)踐任務(wù)
?????? 完成一個(gè)簡(jiǎn)單Web服務(wù)器程序設(shè)計(jì)與實(shí)現(xiàn),要求學(xué)習(xí)網(wǎng)絡(luò)套接字編程,HTTP協(xié)議、web服務(wù)器等知識(shí);設(shè)計(jì)一個(gè)簡(jiǎn)單Web服務(wù)器,提供靜態(tài)網(wǎng)頁瀏覽服務(wù)功能;Web服務(wù)器可以配置的參數(shù)有主目錄、首頁問價(jià)名、HTTP端口號(hào)等項(xiàng)。
- 學(xué)習(xí)socket編程、http協(xié)議,實(shí)現(xiàn)提供靜態(tài)網(wǎng)頁的web服務(wù)器;
- 學(xué)習(xí)cgi知識(shí),實(shí)現(xiàn)提供cgi動(dòng)態(tài)網(wǎng)頁服務(wù)的web服務(wù)器;
- Web服務(wù)器支持多進(jìn)程服務(wù)。
三、總體設(shè)計(jì)
- 學(xué)習(xí)web服務(wù)器的基本原理。
- 學(xué)習(xí)socket網(wǎng)絡(luò)編程。
- 學(xué)習(xí)http協(xié)議,實(shí)現(xiàn)提供靜態(tài)網(wǎng)頁的web服務(wù)器。
- 學(xué)習(xí)cgi知識(shí),實(shí)現(xiàn)動(dòng)態(tài)網(wǎng)頁服務(wù)的web服務(wù)器。
- 運(yùn)用多線程的知識(shí),實(shí)現(xiàn)并發(fā)的web服務(wù)器。
四、詳細(xì)設(shè)計(jì)說明
- 了解web服務(wù)器的基本原理。Web服務(wù)器其實(shí)就是一類網(wǎng)絡(luò)服務(wù)器,可以提供人們上網(wǎng)時(shí)向?yàn)g覽器發(fā)出一些請(qǐng)求的一種程序。web服務(wù)器同時(shí)是一種比較被動(dòng)的程序,只有你在上網(wǎng)的時(shí)候發(fā)出指令,這時(shí)服務(wù)器才會(huì)響應(yīng)。
?文章來源地址http://www.zghlxwxcb.cn/news/detail-472431.html
- 所謂套接字(Socket),就是對(duì)網(wǎng)絡(luò)中不同主機(jī)上的應(yīng)用進(jìn)程之間進(jìn)行雙向通信的端點(diǎn)的抽象。一個(gè)套接字就是網(wǎng)絡(luò)上進(jìn)程通信的一端,提供了應(yīng)用層進(jìn)程利用網(wǎng)絡(luò)協(xié)議交換數(shù)據(jù)的機(jī)制。從所處的地位來講,套接字上聯(lián)應(yīng)用進(jìn)程,下聯(lián)網(wǎng)絡(luò)協(xié)議棧,是應(yīng)用程序通過網(wǎng)絡(luò)協(xié)議進(jìn)行通信的接口,是應(yīng)用程序與網(wǎng)絡(luò)協(xié)議棧進(jìn)行交互的接口。
?
- 學(xué)習(xí)http協(xié)議實(shí)現(xiàn),靜態(tài)web服務(wù)器。超文本傳輸協(xié)議(Hyper Text Transfer Protocol,HTTP)是一個(gè)簡(jiǎn)單的請(qǐng)求-響應(yīng)協(xié)議,它通常運(yùn)行在TCP之上。它指定了客戶端可能發(fā)送給服務(wù)器什么樣的消息以及得到什么樣的響應(yīng)。請(qǐng)求和響應(yīng)消息的頭以ASCII形式給出;而消息內(nèi)容則具有一個(gè)類似MIME的格式。這個(gè)簡(jiǎn)單模型是早期Web成功的有功之臣,因?yàn)樗归_發(fā)和部署非常地直截了當(dāng)。
?
- 學(xué)習(xí)cgi的相關(guān)知識(shí),實(shí)現(xiàn)提供動(dòng)態(tài)網(wǎng)頁的web服務(wù)器。
?
程度實(shí)現(xiàn):
hanshu.h
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>
#include <errno.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pthread.h>
#define SERVER_PORT 80
static int debug = 1;
int get_line(int sock, char* buf, int size);
void* do_http_request(void* client_sock);
void do_http_response(int client_sock, const char* path);
int headers(int client_sock, FILE* resource);
void cat(int client_sock, FILE* resource);
void not_found(int client_sock);//404
void unimplemented(int client_sock);//500
void bad_request(int client_sock); //400
void inner_error(int client_sock);
http.c
#include "hanshu.h"
void* do_http_request(void* pclient_sock) {
int len = 0;
char buf[256];
char method[64];
char url[256];
char path[256];
int client_sock = *(int*)pclient_sock;
struct stat st;
//讀取客戶端發(fā)送的http請(qǐng)求
len = get_line(client_sock, buf, sizeof(buf));
if (len > 0) {
int i = 0, j = 0;
while (!isspace(buf[j]) && (i < sizeof(method) - 1)) {
method[i] = buf[j];
i++;
j++;
}
method[i] = '\0';
if (debug) printf("request method: %s\n", method);
if (strncasecmp(method, "GET", i) == 0) { //處理get請(qǐng)求
if (debug) printf("method = GET\n");
//獲取url
while (isspace(buf[j++]));
i = 0;
while (!isspace(buf[j]) && (i < sizeof(url) - 1)) {
url[i] = buf[j];
i++;
j++;
}
url[i] = '\0';
if (debug) printf("url: %s\n", url);
do {
len = get_line(client_sock, buf, sizeof(buf));
if (debug) printf("read: %s\n", buf);
} while (len > 0);
//處理url中的?
{
char* pos = strchr(url, '?');
if (pos) {
*pos = '\0';
printf("real url: %s\n", url);
}
}
sprintf(path, "./html_docs/%s", url); // html_doc 網(wǎng)頁目錄
if (debug) printf("path: %s\n", path);
//判斷文件是否存在,如果不存在,就響應(yīng) 404 NOT FOUND.
if (stat(path, &st) == -1) {//文件不存在或是出錯(cuò)
fprintf(stderr, "stat %s failed. reason: %s\n", path, strerror(errno));
not_found(client_sock);
}
else {//文件存在
if (S_ISDIR(st.st_mode)) {
strcat(path, "/index.html");// 如果是ip地址,則添加主頁路徑
}
do_http_response(client_sock, path);
}
}
else {//非get請(qǐng)求響應(yīng)客戶端 501 Method Not Implemented
fprintf(stderr, "warning! other request [%s]\n", method);
do {
len = get_line(client_sock, buf, sizeof(buf));
if (debug) printf("read: %s\n", buf);
} while (len > 0);
unimplemented(client_sock); //請(qǐng)求未實(shí)現(xiàn)
}
}
else {//請(qǐng)求格式有問題,出錯(cuò)處理
bad_request(client_sock); //在響應(yīng)時(shí)再實(shí)現(xiàn)
}
close(client_sock);
if (pclient_sock) free(pclient_sock);//釋放動(dòng)態(tài)分配的內(nèi)存
return NULL;
}
void do_http_response(int client_sock, const char* path) {
int ret = 0;
FILE* resource = NULL;
resource = fopen(path, "r");
if (resource == NULL) {
not_found(client_sock);
return;
}
//1.發(fā)送http 頭部
ret = headers(client_sock, resource);
//2.發(fā)送http body .
if (!ret) {
cat(client_sock, resource);
}
fclose(resource);
}
realization.c
#include "hanshu.h"
// 響應(yīng)文件的頭部
int headers(int client_sock, FILE* resource) {
struct stat st;
int fileid = 0;
char tmp[64];
char buf[1024] = { 0 };
strcpy(buf, "HTTP/1.0 200 OK\r\n");
strcat(buf, "Server: Martin Server\r\n");
strcat(buf, "Content-Type: text/html\r\n");
strcat(buf, "Connection: Close\r\n");
fileid = fileno(resource);
if (fstat(fileid, &st) == -1) {
inner_error(client_sock);
return -1;
}
snprintf(tmp, 64, "Content-Length: %ld\r\n\r\n", st.st_size);
strcat(buf, tmp);
if (debug) fprintf(stdout, "header: %s\n", buf);
if (send(client_sock, buf, strlen(buf), 0) < 0) {
fprintf(stderr, "send failed. data: %s, reason: %s\n", buf, strerror(errno));
return -1;
}
return 0;
}
// 讀取內(nèi)容,發(fā)送給客戶端
void cat(int client_sock, FILE* resource) {
char buf[1024];
fgets(buf, sizeof(buf), resource);
while (!feof(resource)) {
int len = write(client_sock, buf, strlen(buf));
if (len < 0) {//發(fā)送body 的過程中出現(xiàn)問題,怎么辦?1.重試? 2.
fprintf(stderr, "send body error. reason: %s\n", strerror(errno));
break;
}
if (debug) fprintf(stdout, "%s", buf);
fgets(buf, sizeof(buf), resource);
}
}
//返回值: -1 表示讀取出錯(cuò), 等于0表示讀到一個(gè)空行, 大于0 表示成功讀取一行
int get_line(int sock, char* buf, int size) {
int count = 0;
char ch = '\0';
int len = 0;
while ((count < size - 1) && ch != '\n') {
len = read(sock, &ch, 1);
if (len == 1) {
if (ch == '\r') {
continue;
}
else if (ch == '\n') {
break;
}
//處理一般的字符
buf[count] = ch;
count++;
}
else if (len == -1) {//讀取出錯(cuò)
perror("read failed");
count = -1;
break;
}
else {// read 返回0,客戶端關(guān)閉sock 連接.
fprintf(stderr, "client close.\n");
count = -1;
break;
}
}
if (count >= 0) buf[count] = '\0';
return count;
}
void not_found(int client_sock) {
const char* reply = "HTTP/1.0 404 NOT FOUND\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>NOT FOUND</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
<P>文件不存在!\r\n\
<P>The server could not fulfill your request because the resource specified is unavailable or nonexistent.\r\n\
</BODY>\r\n\
</HTML>";
int len = write(client_sock, reply, strlen(reply));
if (debug) fprintf(stdout, reply);
if (len <= 0) {
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void unimplemented(int client_sock) {
const char* reply = "HTTP/1.0 501 Method Not Implemented\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML>\r\n\
<HEAD>\r\n\
<TITLE>Method Not Implemented</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
<P>HTTP request method not supported.\r\n\
</BODY>\r\n\
</HTML>";
int len = write(client_sock, reply, strlen(reply));
if (debug) fprintf(stdout, reply);
if (len <= 0) {
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void bad_request(int client_sock) {
const char* reply = "HTTP/1.0 400 BAD REQUEST\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML>\r\n\
<HEAD>\r\n\
<TITLE>BAD REQUEST</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
<P>Your browser sent a bad request!\r\n\
</BODY>\r\n\
</HTML>";
int len = write(client_sock, reply, strlen(reply));
if (len <= 0) {
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
void inner_error(int client_sock) {
const char* reply = "HTTP/1.0 500 Internal Sever Error\r\n\
Content-Type: text/html\r\n\
\r\n\
<HTML lang=\"zh-CN\">\r\n\
<meta content=\"text/html; charset=utf-8\" http-equiv=\"Content-Type\">\r\n\
<HEAD>\r\n\
<TITLE>Inner Error</TITLE>\r\n\
</HEAD>\r\n\
<BODY>\r\n\
<P>服務(wù)器內(nèi)部出錯(cuò).\r\n\
</BODY>\r\n\
</HTML>";
int len = write(client_sock, reply, strlen(reply));
if (debug) fprintf(stdout, reply);
if (len <= 0) {
fprintf(stderr, "send reply failed. reason: %s\n", strerror(errno));
}
}
Web_Server.c
#include "hanshu.h"
int main(void) {
int sock;
struct sockaddr_in server_addr;
sock = socket(AF_INET, SOCK_STREAM, 0);
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;//IPV4
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//監(jiān)聽本地所有IP地址
server_addr.sin_port = htons(SERVER_PORT);//綁定端口號(hào)
bind(sock, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(sock, 128);
printf("等待客戶端的連接\n");
int done = 1;
while (done) {
struct sockaddr_in client;
int client_sock, len, i;
char client_ip[64];
char buf[256];
pthread_t id;
int* pclient_sock = NULL;
socklen_t client_addr_len;
client_addr_len = sizeof(client);
client_sock = accept(sock, (struct sockaddr*)&client, &client_addr_len);
//打印客戶端IP地址和端口號(hào)
printf("client ip: %s\t port : %d\n",inet_ntop(AF_INET, &client.sin_addr.s_addr, client_ip, sizeof(client_ip)),ntohs(client.sin_port));
//啟動(dòng)線程處理http請(qǐng)求
pclient_sock = (int*)malloc(sizeof(int));
*pclient_sock = client_sock;
pthread_create(&id, NULL, do_http_request, (void*)pclient_sock);
}
close(sock);
return 0;
}
結(jié)果演示
?
?
?文章來源:http://www.zghlxwxcb.cn/news/detail-472431.html
?
到了這里,關(guān)于簡(jiǎn)單Web服務(wù)器程序設(shè)計(jì)與實(shí)現(xiàn)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!