212-HTTP协议与web服务器
浏览器与服务器通信过程
HTTP是超文本传输协议,除了文字以外,还可以进行声音,图片的传输。
html是超文本标记语言。可以告诉浏览器应该在什么地方显示什么东西。会把主干框架搭起来。
当我们在浏览器输入网址,接下来会发生什么事情?
这其中发生了什么事情?
首先我们有一个服务器端(自己发的网站),我们有一个客户端(浏览器)。
HTTP协议是属于应用层。TCP,UDP在传输层,IP在网络层。我们用户会参与对HTTP的解析和组装。
当我们在浏览器输入www.baidu.com时,
浏览器与 web 服务器在应用层通信使用的是 HTTP 协议(超文本传输协议),而 HTTP协议在传输层使用的是 TCP 协议。那么浏览器需要和 web 服务器三次握手建立连接后,才可以发送 HTTP 请求报文,服务器收到请求报文后,向浏览器回复 HTTP 应答报文。
浏览器向服务器发起连接前,需要得到服务器的 IP 及端口。用户在浏览器中通常只输入网址(网站域名),浏览器会通过 DNS (域名解析)服务查询获取到服务器的 IP 地址。对于端口来讲,使用 HTTP 协议的程序一般默认使用 80 端口。
浏览器和服务器建立连接后,
如果两次以上的请求复用同一个 TCP 连接,则称之为长连接。
如果浏览器发送一次请求报文,服务器回复一次应答就断开连接,下次交互再重新进行三次握手建立连接,那么就被称作短连接。
使用长连接显然是更好一些,可以减少网络中的同步报文,也使得服务器的响应速度变快。
长连接比较普遍,而且节省资源。因为我们点开可能要不断地进行交互。
常见的 web 服务器有:
◼ Apache: 简单、速度快、性能稳定,并可做代理服务器使用
◼ IIS(Internet Information Server):安全性、强大、灵活
◼ Nginx:小巧而高效,可以做高效的负载均衡反向代理
◼ Tomcat:技术先进、性能稳定、免费
HTTP 请求报头
HTTP 的请求报头结构
close(短连接)
keep-alive(长连接)
HTTP 的请求方法
HTTP 应答报头
数据是在via的后面,但是没有显示出来,后面还有8024个字节
HTTP 的应答报头结构
HTTP 的应答状态
我们先进行简单的实现
编译运行
现在我们打开浏览器(客户端)
这个ok就是我们刚才send给浏览器发送的
浏览器发过来的报文
浏览器可以统计出来,你是哪一种访问我,访问多少次。
我们可以写一个应答报文,写一个文件发给浏览器
vi index.html
头部是显示在状态栏(新标签页)。
body就是下面的一大部分了。
然后我们修改刚才的代码
运行起来!
我们可以把乱码改掉,通过改写index.html文件
Web 服务器的 C 语言实现
Web 服务器对应的文件是 MyHttp.c,代码示例如下, 其中使用到的页面文件(.html)需要用户自己提供,并且和程序在同一个位置。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <sys/stat.h>
#define DATALENGTH 1024
#define PATHLENGTH 128
//发送 HTTP 应答报头
void SendHeadData(int c, int size, int flag)
{
char buff[DATALENGTH] = "HTTP/1.0 ";
if (flag)
{
strcat(buff, "200 OK\r\n");
}
else
{
strcat(buff, "404 Not Found\r\n");
}
strcat(buff, "Server: MyWeb/1.0\r\n");
strcat(buff, "Content-Length: ");
sprintf(buff + strlen(buff), "%d", size);
strcat(buff, "\r\n");
strcat(buff, "Content-Type: text/html;charset=utf-8\r\n");
strcat(buff, "\r\n");
send(c, buff, strlen(buff), 0);
}
//发送页面文件的内容
void SendFileData(int c, int fd)
{
while (1)
{
char buff[DATALENGTH] = {
0 };
ssize_t n = read(fd, buff, DATALENGTH - 1);
if (n <= 0)
{
break;
}
send(c, buff, (size_t)n, 0);
}
}
//处理客户端的请求数据
void DealClientData(int c)
{
char requestBuff[DATALENGTH] = {
0 };
int n = recv(c, requestBuff, DATALENGTH - 1, 0);
if (n <= 0)
{
return;
}
char *file = strtok(requestBuff, " ");
file = strtok(NULL, " ");
int flag = 1;
char path[PATHLENGTH] = "."; //程序所在位置
strcat(path, file);
int fd = open(path, O_RDONLY);
if (fd == -1)
{
fd = open("./404.html", O_RDONLY);
flag = 0;
}
struct stat st;
fstat(fd, &st);
SendHeadData(c, st.st_size, flag);
SendFileData(c, fd);
close(fd);
}
// 初始化服务器的套接字
int InitSocket()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) return -1;
struct sockaddr_in saddr;
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(80);
saddr.sin_addr.s_addr = inet_addr("127.0.0.1");
int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
if(res == -1) return -1;
res = listen(sockfd, 5);
if(res == -1) return -1;
return sockfd;
}
int main()
{
int sockfd = InitSocket();
assert(sockfd != -1);
while ( 1 )
{
struct sockaddr_in caddr;
socklen_t len = sizeof(caddr);
int c = accept(sockfd, (struct sockaddr*)&caddr, &len);
if (c < 0)
{
continue;
}
DealClientData(c);
close(c);
}
exit(0);
}
http服务器实现(上)
我们先让浏览器和web服务器连接上,接收浏览器(作为我们的客户端)给我们发过来的信息:
web服务器(http服务器)就是TCP的服务端
myhttp.c
这是个短连接。收1次发1次就关闭了
只有管理员用户才能运行80号端口
现在打开浏览器,去链接
favicon是请求小图标
http服务器实现(中)
我们看看http服务器给浏览器回复的是什么报文:myhttp.c
显示的是浏览器的信息
http服务器实现(下)
我们实现让web服务器可以给浏览器返回请求的真正的文件(资源),像正常上网浏览网页一样。
myhttp.c
index.html
我们修改index.html
我们创建一个test.html
还没有评论,来说两句吧...