1. 程式人生 > >Linux C小專案 —— 簡單的web伺服器

Linux C小專案 —— 簡單的web伺服器

簡單的Web伺服器

實現一個基於HTTP通訊協議的web伺服器。客戶端向伺服器程式傳送所需檔案的請求,伺服器端分析請求並將檔案傳送個客戶端。

1、整體程式設計

客戶端傳送所需檔案,伺服器返回該檔案,通訊結束。

伺服器程式的任務大致分為3步:

a、解析客戶端程式發來的內容,找到需求檔案的路徑或者名字

b、在伺服器主機上查詢該檔案

c、將該檔案內容組織成客戶端程式可以理解的形式,並將其發回給客戶端。

步驟一:解析客戶端傳送的內容

Note:客戶端程式使用web瀏覽器,瀏覽器程式是預設使用HTTP通訊協議。通常,http預設使用的埠號是80

開啟瀏覽器,在位址列輸入需要訪問的伺服器的ip地址和埠號。例,

”httP://127.0.0.1:8080” 表示瀏覽器希望從地址為127.0.0.1的伺服器上使用8080埠的應用程式那裡接收資料,這些資料是遵守http通訊協議的。

這時,瀏覽器向伺服器程式傳送一個HTTP協議的“協議頭”,包含了一些客戶端程式的基本資訊,例如客戶機的ip地址、瀏覽器版本、使用協議版本以及請求檔案的方式等。協議頭:

GET / HTTP/1.1

Host: 192.168.159.2:8080

User-Agent: Mozilla/5.0 (X11; U; Linux i586; en-US; rv:1.8.1.6)

Gecko/20061201 Firefox/2.0.0.6 (Redhat-feisty)

Accept:

text/xml, application/xml, application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5

Accept-Language: en-us,en; q=0.5

Accept-Encoding: gzip, deflate

Accept-Charset: ISO-8859-1, utf-8; q=0.7,*;q=0.7

Keep-Alive: 300

Connection: keep-alive

附:協議頭最後有一個空行。

和本程式有關的是第一行。該行包括以下3個資訊:

a、GET請求檔案的方式,預設使用的是GET

的方法。這個方法其實只是一個約定,具體的還要看伺服器程式的實現。

b、“/”請求伺服器程式的根目錄。這個目錄可由伺服器程式編寫時自行配置。例,如果伺服器程式的根目錄是“/home/admin”,那麼“/”所代表的就是這個目錄。

c、HTTP協議的版本號,本程式中使用的是1.1版本。這個欄位對本程式沒有什麼影響。

伺服器程式的第1步就是要解析“協議頭”的第1行,檔案請求方式和協議版本我們不關心,主要是要找到請求的目錄。如果瀏覽器位址列輸入“http://192.168.11.6:8080”表示的是伺服器程式根目錄“/home/admin”,那麼“http://192.168.11.6:8080/web/test.html”就表示的是“/home/admin/web/test.html”檔案。因此,伺服器程式的第一個任務就是解析出這個客戶端請求的目錄和該目錄下的檔案。

步驟二:尋找客戶端需要的檔案

在指定目錄下尋找檔案。如果是一個普通檔案,且該檔案沒有執行許可權,則將其開啟,把檔案返回給客戶端。如果該檔案是一個可執行檔案,例如二進位制可執行檔案或者直譯器檔案,則執行該檔案,將執行的輸出結果返回給客戶端,這種可執行檔案成為CGI程式。

步驟三:將客戶端所請求的資訊返回

Note:客戶端使用的是瀏覽器,簡單地返回一個文字檔案是不對的,理想的方式是返回一個客戶端可以理解的格式的檔案,這裡使用HTML格式的檔案。

檔案index.html的內容如下所示:

<html>

<head><title>This is a test</title></head>

<body>

<p>successfully communicate</p>

<img src=’test.jpg’>

</body>

</html>

這個頁面只有一行字和一張圖片,圖片的路徑是根目錄下的test.jpg檔案。

除了瀏覽器可以解析的正文外,伺服器還需要為返回的資訊加上HTTP的協議頭。該協議頭包含2行:第1行是版本資訊和應答碼,其後是一個隨便寫的字串“OK”用於除錯目的;第2行是即將傳送的檔案型別。

版本協議和客戶端傳送來的是一致的,連線成功,應答碼為200;如果失敗,例如指定的檔案不存在,應答碼為404。檔案型別為text/html,是因為index.html檔案中既有文字又有圖片,單純的文字型別為text/plain,單純的圖片型別為image/jpg等。完整的返回資訊應該如下所示:

HTTP/1.1 200 OK # 協議版本和應答碼

Content-Type: text/html # 檔案型別

# 注意協議頭結束後有一個空行

<html>

<head><title>This is a test</title></head>

<body>

<p>successfully communicate</p>

<img src=’test.jpg’>

</body>

</html>

到此,伺服器程式的任務就結束了,完成傳輸後,伺服器端需要主動將連線斷開,這樣客戶端就知道資料已經傳輸完畢。這是由HTTP協議所規定的。

瀏覽器接收到index.html後,發現裡面需要一張圖片,因此瀏覽器會再次向伺服器發出一次請求,要求獲得相應的檔案。

經過兩次請求後,客戶端的瀏覽器獲得了index.html所需要的所有檔案。這時,瀏覽器就可以正確顯示該頁面了,至於如何顯示則交給瀏覽器去做。

測試:

web_server程式所在的目錄下準備配置檔案config.ini

Port:  8080

Root-path: /home/trb331617/www

該程式使用8080埠,使用/home/trb331617/www作為根目錄

/home/trb331617/www目錄下準備index.html檔案;準備圖片png_favicon.pngtest.jpg

shell中執行該程式:“./build

附:

Signal(SIGCHLD, SIG_IGN);

Signal(SIGPIPE, SIG_IGN);

網路程式設計

服務端

// 填充服務端地址結構

Bzero(serv_addr, sizeof(struct sockaddr_in));

Serv_addr->sin_family = AF_INET;

Serv_addr->sin_addr.s_addr = htonl(INADDR_ANY);

Serv_addr->sin_port = htons(port);

Listenfd = socket(AF_INET, SOCK_STREAM, 0); // socket建立套接字

Bind(fd, (struct sockaddr *)serv_addr, sizeof(struct sockaddr_in)); // bind 套接字和填充好的地址繫結

Listen(fd, 20); // listen 監聽套接字

Accept(listenfd, (struct sockaddr *)&serv_addr, &len); // accept 接受連線請求

檔案操作

Int fd = open(path, O_RDONLY);

FILE *fp = fopen(“./config.ini”, “r”);

Fgets(buf, BUFFSIZE, fp);

Read(connfd, buf, BUFFSIZE);

Write(connfd, buf, strlen(buf));

Struct stat stat_buf; fstat(fd, &stat_buf);

S_ISREG(stat_buf.st_mode); // 判斷是否為普通檔案

Stat_buf.st_mode & S_IXOTH // 判斷是否為可執行檔案

Dup2(connfd, STDOUT_FILENO); // dup2重定向標準輸出至連線套接字

Execl(path, path, NULL); // execl執行

字串操作

Strstr(buf, “port”); // 返回指定字元子串第一次出現的位置

Strcpy(path, p); // 複製字串

Strcat(path, “/index.html”); // 連線字串

Strtok(&buf[4], “ ”); // strtok 分割字串

原始碼檔案彙總:

  1 /*
  2  * FILE: main.c
  3  * DATE: 20180205
  4  * ===============
  5  */
  6 
  7 #include "common.h"
  8 
  9 int main(void)
 10 {
 11         struct sockaddr_in serv_addr, cli_addr;
 12         struct stat stat_buf;
 13         int listenfd, connfd, len, fd, port;
 14         pid_t pid;
 15         char path[BUFFSIZE];
 16 
 17 
 18         signal(SIGCHLD, SIG_IGN);       // signal 訊號處理
 19         signal(SIGPIPE, SIG_IGN);
 20 
 21         printf("initializing ...\n");
 22         if(init(&serv_addr, &listenfd, &port, path) < 0)        // 自定義init初始化
 23         {
 24                 DEBUG("error during initializing\n");
 25                 exit(-1);
 26         }
 27         while(1)
 28         {
 29                 DEBUG("waiting connection ...\n");
 30                 connfd = accept(listenfd, (struct sockaddr *)&serv_addr, &len);
 31                 if(connfd < 0)
 32                 {
 33                         perror("fail to accept");
 34                         exit(-2);
 35                 }
 36                 pid = fork();   // fork 子程序,併發處理請求
 37                 if(pid < 0)
 38                 {
 39                         perror("fail to fork");
 40                         exit(-3);
 41                 }
 42                 if(pid == 0)
 43                 {
 44                         close(listenfd);        // 關閉監聽套接字
 45                         if(get_path(connfd, path) < 0)  // 分析客戶端發來的資訊,得到請求檔案路徑
 46                         {
 47                                 DEBUG("error during geting filepath\n");
 48                                 exit(-4);
 49                         }
 50                         DEBUG("%s\n", path);
 51                         if((fd=open(path, O_RDONLY)) < 0)
 52                         {
 53                                 error_page(connfd);
 54                                 close(connfd);
 55                                 exit(0);
 56                         }
 57                         if(fstat(fd, &stat_buf) < 0)
 58                         {
 59                                 perror("fail to get file status");
 60                                 exit(-5);
 61                         }
 62                         if(!S_ISREG(stat_buf.st_mode))  // S_ISREG 判斷是否為普通檔案
 63                         {
 64                                 if(error_page(connfd) < 0)      // 自定義error_page 輸出出錯頁面
 65                                 {
 66                                         DEBUG("error during writing error-page\n");
 67                                         close(connfd);
 68                                         exit(-6);
 69                                 }
 70                                 close(connfd);
 71                                 exit(0);
 72                         }
 73                         if(stat_buf.st_mode & S_IXOTH)  // 可執行檔案,說明是一個CGI檔案
 74                         {
 75                                 dup2(connfd, STDOUT_FILENO);    // dup2重定向標準輸出到連線套接字
 76                                 if(execl(path, path, NULL) < 0) // exec 執行該CGI檔案
 77                                 {
 78                                         perror("fail to exec");
 79                                         exit(-7);
 80                                 }
 81                         }
 82                         if(write_page(connfd, path, fd) < 0)    // 若為普通檔案,則將檔案內容傳送給客戶端
 83                         {
 84                                 DEBUG("error during writing page\n");
 85                                 exit(-8);
 86                         }
 87                         close(fd);      // 關閉檔案
 88                         close(connfd);  // 伺服器端主動關閉連線套接字,表示資料傳輸完畢
 89                         exit(0);        // 子程序正常退出
 90                 }
 91                 else
 92                         close(connfd);  // 父程序關閉連線套接字,繼續監聽
 93         }
 94         return 0;
 95 
 96 }
 97 
 98 
 99 
100 /* FILE: web_server.c
101  * DATE: 20180205
102  * ===============
103  */
104 
105 #include "common.h"
106 /*
107  * 讀取配置檔案,對埠號和根目錄進行配置。
108  * 只在本檔案內呼叫,使用static關鍵字進行宣告。
109  * port: 埠號 path: 伺服器程式的根目錄
110  */
111 static int configuration(int *port, char *path)
112 {
113         FILE *fp;
114         char buf[BUFFSIZE];
115         char *p;
116         // 開啟配置檔案。該檔案放在伺服器程式所在目錄下
117         fp = fopen("./config.ini", "r");
118         if(fp == NULL)
119         {
120                 perror("fail to open config.ini");
121                 return -1;
122         }
123         while(fgets(buf, BUFFSIZE, fp) != NULL) // fgets 讀取檔案每一行的內容
124         {
125                 if(buf[strlen(buf)-1] != '\n')  // 判斷檔案格式
126                 {
127                         printf("error in config.ini\n");
128                         return -1;
129                 }
130                 else
131                         buf[strlen(buf)-1] = '\0';      // 將換行符\n改為結束符\0
132                 // 埠號的配置格式為 port: 8080,注意冒號:後面有一個空格
133                 if(strstr(buf, "port") == buf)  // 匹配port關鍵字,讀取埠號
134                 {
135                         if((p=strchr(buf, ':')) == NULL)
136                         {
137                                 printf("config.ini expect ':'\n");
138                                 return -1;
139                         }
140                         *port = atoi(p+2);      // 跳過冒號:和空格得到埠號
141                         if(*port <= 0)
142                         {
143                                 printf("error port\n");
144                                 return -1;
145                         }
146                 }
147                 // 根目錄的配置格式為 root-path: /root,注意冒號:後面有一個空格
148                 else if(strstr(buf, "root-path") == buf)
149                 {
150                         if((p=strchr(buf, ':')) == NULL)
151                         {
152                                 printf("config.ini expect ':'\n");
153                                 return -1;
154                         }
155                         p = p + 2;      // 跳過冒號和空格,得到根目錄
156                         strcpy(path, p);
157                 }
158                 else
159                 {
160                         printf("error in config.ini\n");
161                         return -1;
162                 }
163         }
164         return 0;
165 }
166 
167 int init(struct sockaddr_in *serv_addr, int *listenfd, int *port, char *path)
168 {
169         int fd;
170 
171         configuration(port, path);
172 
173         bzero(serv_addr, sizeof(struct sockaddr_in));   // bzero
174         serv_addr->sin_family = AF_INET;        // sin_family   AF_INET
175         serv_addr->sin_addr.s_addr = htonl(INADDR_ANY); // sin_addr.s_addr      INADDR_ANY
176         serv_addr->sin_port = htons(*port);     // sin_port
177 
178         if((fd=socket(AF_INET, SOCK_STREAM, 0)) < 0)    // socker 建立套接字
179         {
180                 perror("fail to creat socket");
181                 return -1;
182         }
183         // bind 將已建立的套接字與填充好的服務端地址繫結
184         if(bind(fd, (struct sockaddr *)serv_addr, sizeof(struct sockaddr_in)) < 0)
185         {
186                 perror("fail to bind");
187                 return -2;
188         }
189         if(listen(fd, 20) < 0)  // listen 監聽套接字
190         {
191                 perror("fail to listen");
192                 return -3;
193         }
194         *listenfd = fd;
195         return 0;
196 }
197 
198 /*
199  * 分析http協議頭的第一行,得到請求檔案方式和檔案路徑
200  * connfd: 連線套接字
201  * path: 伺服器程式的根目錄,用於和解析出的檔名拼成完整的檔案路徑
202  */
203 int get_path(int connfd, char *path)
204 {
205         char buf[BUFFSIZE];
206 
207         read(connfd, buf, BUFFSIZE);    // 讀取HTTP協議頭的第一行
208         // HTTP協議頭第一行的格式為“GET / HTTP/1.1”
209         // 第四個字元為空格,第五個字元開始是所要求的檔案路徑
210         if(strstr(buf, "GET") != buf)   // 協議的開始說明取得檔案的方式“GET”
211         {
212                 DEBUG("wrong request\n");
213                 return -1;
214         }
215         // 若沒有指定檔名,則使用預設檔案index.html
216         if(buf[4]=='/' && buf[5]==' ')
217                 strcat(path, "/index.html");
218         else
219         {
220                 strtok(&buf[4], " ");   // strtok 分割字串
221                 strcat(path, &buf[4]);  // strcat 連線字串
222         }
223         return 0;
224 }
225 
226 int error_page(int sockfd)
227 {
228         char err_str[BUFFSIZE];
229         #ifdef DEBUG_PRINT      // 除錯時,用於向客戶端輸出出錯資訊
230                 sprintf(err_str, "HTTP/1.1 404 %s\r\n", strerror(errno));
231         #else   // 釋出版,則不輸出具體出錯資訊
232                 sprintf(err_str, "HTTP/1.1 404 Not Exsit\r\n");
233         #endif
234         // http協議頭第一行
235         write(sockfd, err_str, strlen(err_str));
236         // 協議頭第2行,說明頁面的型別。只輸出出錯資訊,所以頁面型別為文字型別text/html
237         write(sockfd, "Content-Type: text/html\r\n\r\n", strlen("Content-Type: text/html\r\n\r\n"));
238         // 輸出html內容
239         write(sockfd, "<html><body> the file dose not exsit </body></html>",
240                         strlen("<html><body> the file not exist </body></html>"));
241         // http協議的每一行以\r\n結尾,整個協議的結尾還有額外的一行\r\n
242         return 0;
243 }
244 // 向客戶端輸出需要的頁面
245 // 將檔案內容傳送給客戶端,同樣,伺服器程式需要為該檔案新增HTTP協議頭
246 // connfd: 連線套接字   path: 檔案的完整路徑
247 int write_page(int connfd, char *path, int fd)
248 {
249         int len = strlen(path);
250         char buf[BUFFSIZE];
251         // 協議頭的第一行
252         write(connfd, "HTTP/1.1 200 OK\r\n", strlen("HTTP/1.1 200 OK\r\n"));
253         // 協議頭的第2行,頁面型別。需要根據檔案的副檔名來進行判斷
254         write(connfd, "Content-Type: ", strlen("Content-Type: "));
255         // 三種圖片格式
256         if(strcasecmp(&path[len-3], "jpg")==0 || strcasecmp(&path[len-4], "jpeg")==0)
257                 write(connfd, "image/jpeg", strlen("image/jpeg"));
258         else if(strcasecmp(&path[len-3], "gif") == 0)
259                 write(connfd, "image/gif", strlen("image/gif"));
260         else if(strcasecmp(&path[len]-3, "png") == 0)
261                 write(connfd, "image/png", strlen("image/png"));
262         else
263                 write(connfd, "text/html", strlen("text/html"));
264         // 新增協議尾,最後需多出一個\r\n空行
265         write(connfd, "\r\n\r\n", 4);
266 //      fd = open(path, O_RDONLY);
267         while((len=read(fd, buf, BUFFSIZE)) > 0)
268                 write(connfd, buf, len);
269 
270         return 0;
271 }
272 
273 
274 
275 
276 # FILE: Makefile
277 # DATE: 20180205
278 # ==============
279 
280 OBJECTS = common.h web_server.c main.c
281 
282 all: build
283 
284 build: $(OBJECTS)
285         gcc -o build $(OBJECTS)
286 
287 .PHONY: clean
288 clean:
289         rm *.o
290 
291 
292 # FILE: config.ini
293 # DATE: 20180205
294 # ===============
295 
296 port: 8000
297 root-path: /home/admin
298 
299 
300 # FILE: index.html
301 # DATE: 20180205
302 # ===============
303 
304 <html>
305 <head>
306 <title>This is a test</title>
307 <link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
308 <link rel="icon" href="png_favicon.png" type="image/png" >
309 </head>
310 <body>
311         <p>successfully communicate</p>
312         <img src='test.jpg'>
313 </body>
314 </html>


相關推薦

Linux C專案 —— 簡單web伺服器

簡單的Web伺服器 實現一個基於HTTP通訊協議的web伺服器。客戶端向伺服器程式傳送所需檔案的請求,伺服器端分析請求並將檔案傳送個客戶端。 1、整體程式設計 客戶端傳送所需檔案,伺服器返回該檔案,通訊結束。 伺服器程式的任務大致分為3步: a、解析客戶端程式發來的內容,找

c語言實現簡單web伺服器

浪費了“黃金五年”的Java程式設計師,還有救嗎? >>>   

自己開發簡單web伺服器一(C++開源庫websocketpp實現)

簡要 Web伺服器主要處理的是HTTP請求(這裡忽略HTTPS),HTTP協議建立在TCP上。如果自己實現,無非就是網路程式設計(socket接受、傳送),資料解析(HTTP欄位解析),返回HTTP協議字串給客戶端等。說起來簡單,要做到跨平臺和高效,不得不介紹幾個有名的開源

c語言實現簡單web服務器

tps gate choices found lte expect inf tro condition 1http簡單介紹http超文本傳輸協議:host主機地址:port端口/urlhost會被DNS服務器 解析成IP地址,所以有時候可以直接用域名,http默認訪問80端

Linux專案)————shell的實現,包含重定向、內建命令。

bash原理: 通過上面bash的原理我們可以,瞭解到shell的框架與流程: 1.等待使用者輸入命令。 2.解析使用者輸入的字串。 3.建立子程序執行exec程式替換 4.父程序等待子程序退出。 迴圈執行1~4步驟,即可完成my_shell。 最簡單版本的my_shell實現:

go語言實現的簡單web伺服器

go語言讓web伺服器實現和部署變得異常簡潔.終於可以拋開亂七八糟的專案結構和體積龐大的IDE,一窺其基本原理. 首先是一個簡單的伺服器實現程式碼,如果是GET請求,則回送一條This is a GET request訊息,如果是POST請求,則解析POST請

go搭建一個簡單web伺服器

Go語言裡面提供了一個完善的net/http包,通過http包可以很 方便的就搭建起來一個可以執行的web服務。同時使用這個包能很簡單地對web的路由,靜態檔案,模版,cookie等數 據進行設定和操

C專案——電子詞典

C語言專案——查字典 宗旨:技術的學習是有限的,分享的精神是無限的。 【專案需求描述】 一、單詞查詢 給定文字檔案“dict.txt”,該檔案用於儲存詞庫。詞庫為“英-漢”,“漢-英”雙語詞典,每個單詞和其解釋的格式固定,如下所示: #單詞 Trans:解釋[email

註釋轉換(C++專案

將所有以C語言格式的註釋轉換成C++註釋格式,利用檔案指標開啟檔案並讀寫檔案,input,output匯入匯出檔案,轉換後不得改變原檔案的含義並且編譯連線無錯誤,所有的轉換必須符合語法規則,註釋轉換支援註釋巢狀。 #include<stdio.h> #inclu

一個簡單web伺服器的java實現

一個簡單的web伺服器在不考慮其效能及健壯性的情況下,通常只需實現的功能包括伺服器的啟動,它用於監聽某一個埠,接收客戶端發來的請求,並將響應結果返回給客戶端。本文將介紹一個簡單web伺服器的實現原理,它本身只能處理某個目錄下的靜態資原始檔(文字、圖片等)。採用java

C++專案 — 基於huffman壓縮演算法的檔案壓縮專案

先去讀配置檔案,構建huffman樹和huffman編碼,用壓縮檔案裡的編碼去huffman樹中查詢,找到對應的葉子結點. 就把葉子結點的字元寫入到解壓縮 檔案中. 所以總結起來也就是那麼幾步: 1.讀取配置檔案,統計所有字元的個數. 2.構建huffman樹,讀解壓縮檔案,將所讀到的編碼字元的這個節

linux c libcurl的簡單使用

curl->libcurl的手冊可以檢視 http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTWRITEDATA 譯者注:這是一篇介紹如何使用libcurl的入門教程。文件不是逐字逐句按原文翻譯,而是根據筆者對libcurl的理解,參

python uwsgi實現的簡單web伺服器(8程式碼)

python uwsgi實現的簡單web伺服器,一共用了8行程式碼。 先說一下web領域的幾個概念,主要是舉例: web伺服器:apache、iis、nginx等。 web應用伺服器:tomcat、

TinyWS —— 一個C++寫的簡易WEB伺服器(一)

寫在前面 每個碼農可能都會偶爾有自己做一個常用軟體的想法,比如作業系統,編譯器,郵件伺服器/客戶端,文字編輯器等等。這裡面有些很難,比如作業系統,做一個最簡單的也要付出很大的努力,可是大部分常用工具都是可以比較容易的做一個簡易版本(當然也是隻能玩玩而已)。於是我做了一個非常簡陋的WEB伺服器 —— Tiny

ROS的學習(十六)用C++寫一個簡單伺服器(service)和客戶端(client)

      我們將建立一個伺服器節點add_two_ints_server,它將會收到兩個整數,並且返回它們的和。切換目錄到之前建立的beginner_tutorials包下: cd ~/catkin_ws/src/beginner_tutorials      編輯sr

記錄準備看一下的linux開源專案

支援負載均衡. 只要通過配置擴充服務節點數量便可無限擴容.(設計負載上限為單服百萬活躍併發). 認證和登入分離, 支援多平臺認證/繫結, 支援本地帳號密碼認證. 支援一個帳號對應多個角色. 多個客戶端登入同個角色可以互踢. 支援合服. 支援跨服. 節點之間安全認證. 節點之間心跳保保活. 節點之間斷點重連.

自己開發簡單web伺服器二(Node.js實現)

Node.js 剛接觸Node.js沒多久,試用了一下,輕輕鬆鬆幾行程式碼就可以實現一個簡單的HTTP伺服器,開發起來的確比其他語言快多了。 Node.js是一個開源的JavaScript庫,可以跨平臺執行在Windows、Linux、Mac上。JS解析庫用的是大名鼎鼎的G

ngnix 作為django專案web伺服器

鉤子: 1. sudo vi /etc/nginx/nginx.conf  ## # Virtual Host Configs ##

Linux + C + Epoll實現高併發伺服器(執行緒池 + 資料庫連線池)

一, 背景        先說下我要實現的功能,server端一直在linux平臺下面跑,當客戶端有請求過來的時候server端接受到請求,拿到客戶端的資料,根據拿到的資料做出相應的處理,得到處理的結果直接把結果資料傳送給客戶端。這樣一個連線的請求結束,我的不

Java專案WEB-INF下jsp頁面如何訪問?

                                       Java小專案中WEB-INF下jsp頁面如何訪問 一:一般為啥要把jsp頁面放在WEB-INF吶?      這樣主要是為了網站的安全的角度來說的,WEB-INF是安全目錄Tomcat 預設的