天天看點

C 語言實作一個簡單的 web 伺服器(二)

2.6 請求處理層編寫

得到請求後開始編寫處理層。繼續接着代碼往下寫沒有層級,編寫一個函數名為 req,該函數接收請求資訊與一個建立好的連接配接為參數:

void req(char* buf, int access_socket)

{

}

然後先在 while 循環中傳遞需要的值:

req(buf, access_skt);

接着開始編寫 req 函數,首先在 req 函數中标記目前目錄下:

char arguments[BUFSIZ];  
strcpy(arguments, "./");
随後分離出請求與參數:
char command[BUFSIZ];     
sscanf(request, "%s%s", command, arguments+2);
接着我們标記一些頭元素:
char* extension = "text/html";   
char* content_type = "text/plain";     
char* body_length = "Content-Length: ";
接着擷取請求參數,若擷取 index.html,就擷取目前路徑下的該檔案:
FILE* rfile= fopen(arguments, "rb");
擷取檔案後表示請求 ok,我們先傳回一個 200 狀态:
char* head = "HTTP/1.1 200 OK\r\n";    
int len; 
char ctype[30] = "Content-type:text/html\r\n";   
len = strlen(head);      

接着編寫一個發送函數 send_:

int send_(int s, char *buf, int *len) 
{
 int total;          
 int bytesleft;                                
 int n;
 total=0;
 bytesleft=*len;
 while(total < *len) 
 {
  n = send(s, buf+total, bytesleft, 0);
  if (n == -1) 
  {
   break;
  }
  total += n;
  bytesleft -= n;
 }
 *len = total;          
 return n==-1?-1:0;         
}      

send 函數功能并不難在此不再贅述,就是一個周遊發送的邏輯。随後發送 http 響應與檔案類型:

send_(send_to, head, &len);

len = strlen(ctype);

send_(send_to, ctype, &len);

随後獲得請求檔案的描述,需要添加頭檔案#include <sys/stat.h>使用fstat,且向已連接配接的通信發生必要的資訊 :

//擷取檔案描述
struct stat statbuf;
char read_buf[1024];       
char length_buf[20];
fstat(fileno(rfile), &statbuf);
itoa( statbuf.st_size, length_buf, 10 );
send(client_sock, body_length, strlen(body_length), 0);
send(client_sock, length_buf, strlen(length_buf), 0);
send(client_sock, "\n", 1, 0);
send(client_sock, "\r\n", 2, 0);      

最後發送資料:

//·資料發送

char read_buf[1024]; 
len = fread(read_buf ,1 , statbuf.st_size, rfile);
if (send_(client_sock, read_buf, &len) == -1) { 
 printf("error!");   
}      

最後通路位址

http://127.0.0.1:8080/index.html

,得到目前目錄下 index.html 檔案資料,并且在浏覽器渲染:

C 語言實作一個簡單的 web 伺服器(二)

所有代碼如下:

#include <WinSock2.h>
#include<stdio.h> 
#include <sys/stat.h> 
 
int send_(int s, char *buf, int *len) {
 int total;          
 int bytesleft;                                
 int n;
 total=0;
 bytesleft=*len;
 while(total < *len) 
 {
  n = send(s, buf+total, bytesleft, 0);
  if (n == -1) 
  {
   break;
  }
  total += n;
  bytesleft -= n;
 }
 *len = total;          
 return n==-1?-1:0;         
}
 
void req(char* request, int client_sock) {   
 char arguments[BUFSIZ];  
 strcpy(arguments, "./");
 
 char command[BUFSIZ];     
 sscanf(request, "%s%s", command, arguments+2);
 
 char* extension = "text/html";   
 char* content_type = "text/plain";     
 char* body_length = "Content-Length: ";
 
 FILE* rfile= fopen(arguments, "rb");
 
 
 char* head = "HTTP/1.1 200 OK\r\n";    
 int len; 
 char ctype[30] = "Content-type:text/html\r\n";   
 len = strlen(head);
  
 send_(client_sock, head, &len);
 len = strlen(ctype);
 send_(client_sock, ctype, &len);
 
 
 struct stat statbuf;
       
 char length_buf[20];
 fstat(fileno(rfile), &statbuf);
 itoa( statbuf.st_size, length_buf, 10 );
 send(client_sock, body_length, strlen(body_length), 0);
 send(client_sock, length_buf, strlen(length_buf), 0);
 
 send(client_sock, "\n", 1, 0);
 send(client_sock, "\r\n", 2, 0);
 
 
 char read_buf[1024]; 
 len = fread(read_buf ,1 , statbuf.st_size, rfile);
 if (send_(client_sock, read_buf, &len) == -1) { 
  printf("error!");   
 }
 
 return;
}
 
 
int main(){
 WSADATA wsaData;
 if (WSAStartup(MAKEWORD(1, 1), &wsaData) != 0) {
  exit(1);
 }
 
 int skt = socket(PF_INET, SOCK_STREAM, 0);
 if (skt == -1) {         
  return -1;
 }
 
 struct sockaddr_in server_addr;
 server_addr.sin_family = AF_INET;
 server_addr.sin_port = htons(8080);
 server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
 memset(&(server_addr.sin_zero), '\0', 8);
 
 if (bind(skt, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1) {       
  return -1; 
 } 
 
 if (listen(skt, 10) == -1 ) {    
  return -1;
 }
 
 while(1){
 
  printf("Listening ... ...\n");
  struct sockaddr_in c_skt; 
  int s_size=sizeof(struct   sockaddr_in);
  int access_skt = accept(skt, (struct sockaddr *)&c_skt, &s_size);
 
  char buf[1024];
  if (recv(access_skt, buf, 1024, 0) == -1) {
   exit(1);
  }
  
  req(buf, access_skt);
 } 
 
}

      

繼續閱讀