顺着教程1,以及教程2,完成以上2个教程了,我们就可以进行这个章节的操作了,完成一个支持静态页面的web服务器了,再次献上运行成功的截图
那咱们开始做些准备工作,并测试些代码,看看浏览器发送给Server端的跟Client发送给Server端有什么不同
1.准备aaa.html这个界面
<html>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>哈哈 鹏哥的第一个web服务器</title>
<body>
</body>
![](http://upload-images.jianshu.io/upload_images/3066128-92db3ca10bba590a.jpg?imageMogr2/auto-orient/strip)
<span style="font-size:20px;font-color:yellow">鼓掌鼓掌</span>
</html>
2.编写测试代码,查看浏览器发送这个链接地址时Server端收到了哪些数据
在Server端编写以下代码
while (1) {
n = Read(connfd, buf, MAXLINE);
if (n == 0) {
printf("the other side has been closed.\n");
break;
}
printf("received from %s at PORT %d,message is %s\n",
inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
ntohs(cliaddr.sin_port),buf);
//解析来自浏览器的buf
printf("buf=%s\n",buf);
}
主要查看
//解析来自浏览器的buf
printf("buf=%s\n",buf);
这个代码到底打印了什么
哦,可以看到这个是请求的header头,在chrome中也可以看到一模一样的,主要看第一行,GET /aaa.html HTTP/1.1,
嗯,可以看到浏览器传输给Server是什么信息
协议是HTTP/1.1,请求方式是GET,请求的文件是 当前目录的aaa.html文件
很简单,所以我们可以很轻易的得出将aaa.html文件内容传输给浏览器就好了,下面开始码代码了
解析来自浏览器的buf
//解析来自浏览器的buf
printf("buf=%s\n",buf);
sscanf(buf, "%s %s %s", method, uri, version);
printf("method:%s\n",method);
printf("uri:%s\n",uri);
printf("version:%s\n",version);
这里的方式有很多,在php中使用expode(" ",$str),这样的方式就能够分割第一行的字符串,得到method,uri,version。但是c中没有这样的方式,c语言中有两种方式可以实现,大家可以分别选择去使用,这里我用了第一种方式
1.int sscanf( string str, string fmt, mixed var1, mixed var2 ... );
2.char * strtok(char *s, const char *delim);
找到uri指向的文件,并包装返回结果回写给浏览器
//这块先支持get请求
if(strcasecmp(method, "GET") == 0 && strstr(version,"HTTP")) {
printf("method=%s,uri=%s\n",method,uri);
//这里是根据uri得出filename的位置
if(find_url(uri,filename)) {
printf("filename=%s\n",filename);
//封装response
wrap_response(connfd,filename);
}
}
这里我将find_url()以及wrap_response()写到wrap_socket.c文件里面
int find_url(char *uri,char *filename) {
char *ptr;
//说明走的是静态网址
if(!strstr(uri, "cgi-bin")) {
strcpy(filename, ".");
strcat(filename, uri);
if (uri[strlen(uri)-1] == '/')
strcat(filename, "index.html");
return 1;
}else {
ptr = index(uri, '?');
strcpy(filename, ".");
strcat(filename, uri);
return 0;
}
}
/**
* @desc 封装response 支持静态页面以及php页面
*
*/
void wrap_response(int connfd,char *filename) {
struct stat sbuf;
int filefd,phpfd;
char *php_result;
char *srcp;
char response[MAXLINE],filetype[MAXLINE];
if(stat(filename,&sbuf) < 0) {
error_response(connfd);
exit(1);
}else {
//获取文件类型
get_filetype(filename,filetype);
//打开文件并将其写入内存,并由浏览器展示
filefd = open(filename,O_RDONLY);
//拼接静态文件的response头
sprintf(response, "HTTP/1.0 200 OK\r\n");
sprintf(response, "%sServer: Pengge Web Server\r\n",response);
sprintf(response, "%sConnection: close\r\n",response);
sprintf(response, "%sContent-length: %lld\r\n",response,sbuf.st_size);
sprintf(response, "%sContent-type: %s\r\n\r\n",response,filetype);
Write(connfd, response, strlen(response));
printf("Response headers:\n");
printf("%s\n",response);
srcp = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, filefd, 0);
Close(filefd);
//清空srcp空间
Write(connfd, srcp, sbuf.st_size);
munmap(srcp, sbuf.st_size);
}
}
这里代码能看出来主要逻辑是这样的:
- stat(filename,&sbuf) //判断是否有这个文件
- get_filetype(filename,filetype);//获取文件类型
- 封装response,具体内容可以参考chrome下的response头
- mmap()读取filename 的内容写给浏览器
srcp = mmap(0, sbuf.st_size, PROT_READ, MAP_PRIVATE, filefd, 0);
Close(filefd);
//清空srcp空间
Write(connfd, srcp, sbuf.st_size);
这个时候调调bug,输入
<b>这个查看下是否有页面出来了吧!</b>
做出来是不是非常有成就感,接下来就要进行动态页面的开发了,在浏览器中输入
在第四章,我们将要实现支持动态页面以及报错界面的制作以及对该项目可以增加功能点的建议原文章链接