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 文件数据,并且在浏览器渲染:
所有代码如下:
#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); } }