我们在浏览器打开网页,其实是向远端服务器提出页面发送请求,远端服务器在接到请求后,就开始执行请求页面的程序文件,然后将执行结果通过html格式,发送到你的浏览器,再显示出来。以下用百度(www.baidu.com)为例:

我们可以通过GET请求可以获得,百度的http应答格式,详情点我查看。或者通过 "$curl -l www.baidu.com"的方式获得,如果提示没有curl命令则表示你的Linux没有安装curl,安装方法也很简单,拿ubuntu为例,输入以下命令"$sudo apt-get install curl",一路回车即可安装。

查询命令也很简单,输入"$curl -i www.baidu.com"

得到百度的服务器的http应答头部信息后,我们可以仿照这种格式,写一个我们自己的服务端。

百度服务器响应http应答头部信息

HTTP/1.1 200 OK

Accept-Ranges: bytes

Cache-Control: private, no-cache, no-store, proxy-revalidate, no-transform

Connection: Keep-Alive

Content-Length: 2381

Content-Type: text/html

Date: Tue, 29 Oct 2019 01:11:38 GMT

Etag: "588604c8-94d"

Last-Modified: Mon, 23 Jan 2017 13:27:36 GMT

Pragma: no-cache

Server: bfe/1.0.8.18

Set-Cookie: BDORZ=27315; max-age=86400; domain=.baidu.com; path=/

这里我们先简单的模拟其中的部分:

  1. HTTP/1.1 200 OK
  2. Server: myhttp
  3. Content-Length: 330
  4. 发送html文件

核心思想:将浏览器的请求信息解析,提取出相应内容作为返回信息的方法。

服务器代码实现如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <assert.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h> #define PATH "/home/stu/mydir/html_test" /*这里是html文件所在的根目录*/ int create_socket();
int main()
{
int sockfd = create_socket();
assert( sockfd != -1 ); while( 1 )
{
struct sockaddr_in caddr;
int len = sizeof(caddr);
int c = accept(sockfd,(struct sockaddr*)&caddr,&len); /*accept()返回新的连接套接子,表示网络已经存在点对点的连接*/
if ( c < 0 )
{
continue;
} char buff[1024] = {0}; /*buff用于接收浏览器(客户端)的请求*/
int res = recv(c,buff,1023,0); char * s = strtok(buff," "); /*分割字符串函数,用于提取http中的信息*/
if ( s == NULL )
{
close(c);
continue;
} printf("方法:%s\n",s); /*服务端打印请求方法,如:GET*/
printf("read:\n%s\n",buff); /*服务端打印读取到信息*/ s = strtok(NULL," ");
if ( s == NULL )
{
send(c,"404",3,0); //该路经下没有该文件,404错误
close(c);
continue;
} if ( strcmp(s,"/") == 0 ) /*如果客户端没有标明想访问哪一个文件,则默认访问index.html文件*/
{
s = "/index.html";
} char path[256] = {PATH}; /*网页文件路径*/
strcat(path,s); /*文件路径+文件*/ printf("file:%s\n",path); /*服务端打印文件的地址*/ int fd = open(path,O_RDONLY); /*定义文件描述符,读取文件内容,发送回浏览器(客户端)*/
if ( fd == -1 )
{
close(c);
continue;
} int size = lseek(fd,0,SEEK_END); /*返回文件大小*/
lseek(fd,0,SEEK_SET); /*文件指针回正,指向文件开头*/ /*http应答头部信息拼装与head_buff中*/
char head_buff[256] = {"HTTP/1.1 200 OK\r\n"};
strcat(head_buff,"Server: myhttp\r\n");
sprintf(head_buff+strlen(head_buff),"Content-Length: %d\r\n",size);
strcat(head_buff,"\r\n"); /*流式数据,可多次发送,先发送应答头部信息*/
send(c,head_buff,strlen(head_buff),0); /*读取index.html文件,发送回客户端*/
char data[1024] = {0};
int num = 0;
while( ( num = read(fd,data,1024)) > 0 ) /*循环读取,直到读完整个文件*/
{
send(c,data,num,0); /*边读取边发送*/
} close(fd); /*关闭文件描述符*/
close(c); /*短连接,断开连接*/ } close(sockfd);
exit(0); } //封装套接子为create_socker()方法
int create_socket()
{
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);//root
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;
} if ( listen(sockfd,5) == -1 )
{
return -1;
} return sockfd;
}

服务器代码已经实现,现在只需一个index.html文件就可以进行测试。

<html>
<head>
<meta charset=utf-8>
<title>我的html页面</title>
</head> <body background="11.PNG">
<center>
<h3><测试标题> </h3>
<hr>
<br>
这是第一行,<br>
这是第二行. <br>
这是第三行,<br>
这是第四行. <br>
</center>
</body>
</html>

简单的写一个html文档,把文档命名为 index.html ,存放于 我们定义的路径下。

打开浏览器,输入 localhost 或 127.0.0.1 即可看见我们的网页内容了,测试截图如下:

在上图中我们可以看到,浏览器显示的是经过处理的文件内容,我们服务端发送的应答头部信息和原本的内容已经经过处理,如果我们想看到服务端发送的具体内容,我们还可以自己再写一个客户端,让客户端连接自己的服务端并打印出服务端发送的内容。

客户端代码:

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int main(){
int sockfd;
int len;
struct sockaddr_in address;
int result;
char *strings="GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: Close\r\n\r\n";
char ch; sockfd = socket(AF_INET, SOCK_STREAM, 0);
address.sin_family = AF_INET;
address.sin_addr.s_addr = inet_addr("127.0.0.1");
address.sin_port = htons(80); len = sizeof(address);
result = connect(sockfd, (struct sockaddr *)&address, len);
if(result == -1){
perror("oops: client1");
return 1;
} write(sockfd,strings,strlen(strings)); while(read(sockfd,&ch, 1)){
printf("%c", ch);
}
close(sockfd); return 0;
}

运行服务端、在运行客户端,我们可以在客户端上看到如下内容:

ps:实现本机访问后也可以试试局域网内互相访问,只需修改服务器端代码,把ip地址改成做服务端的主机的ip地址即可,在另一台主机上输入服务端主机的ip即可访问该网页内容。此博客在上一篇博客Linux套接子(c语言)模拟http请求、应答的基础上做了加强,更加接近真实的http访问协议。

模拟web服务器http请求应答的更多相关文章

  1. [转] c# 模拟Asp.net页面中的某个按钮的点击,向web服务器发出请求

    在没有做题目中所述的内容的时候,感觉这应该是很简单的东西,但是当真正开始做的时候却发现,有很多问题现在在这里写出来,供和我一样水平不高的参考一下. 在写本文之前参照了一下文章 欢迎使用CSDN论坛阅读 ...

  2. 模拟web服务器 (小项目) 搭建+部署

    模拟web服务器:可以从浏览器中访问到自己编写的服务器中的资源,将其资源显示在浏览器中. 技术选型: corejava 线程池 同任务并发执行 IO流 传递数据 客户端也会像服务端发送数据, 服务器像 ...

  3. web服务器获取请求客户端真实地址的方法

    服务器获取客户端或者网页的请求,获取IP时需要注意,因为一个请求到达服务器之前,一般都会经过一层或者多层代理服务器,比如反向代理服务器将http://192.168.1.10:port/ 的URL反向 ...

  4. 第一篇 先用socket模拟web服务器

    一.用socket来模拟网站访问 socket为python2.7 #!/usr/bin/env python # -*- coding:utf-8 -*- import socket def han ...

  5. Socket模拟Web服务器

    效果如下: 源码下载地址:https://github.com/doyoulaikeme/DotNetSample/tree/master/DotNetSample3/SocketWebServer

  6. C#中使用Socket请求Web服务器过程

    最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生. 而有人或许会问: ...

  7. 详谈socket请求Web服务器过程

    最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生. 而有人或许会问: ...

  8. 详谈socket请求Web服务器过程(转)

    最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有“连接建立”的发生. 而有人或许会问: ...

  9. 【网络开发】详谈socket请求Web服务器过程

    最开始我们需要明白一件事情,因为这是这篇文章的前提: HTTP协议只是一个应用层协议,它底层是通过TCP进行传输数据的.因此,浏览器访问Web服务器的过程必须先有"连接建立"的发生 ...

随机推荐

  1. idea看不到class文件

    Ctrl + Shift + Alt + S进入Project Structure,或者File -> Project Structure,点开文件夹或Source,class文件就出现了

  2. 反压缩 js ,我的万花筒写轮眼开了,CV 能力大幅提升

    前言 因为比较菜,所以经常需要读一些别人的代码学习学习. 有源码的代码当然好,但是很多网站不开源.这些网站的 js 又都是打包压缩过的,学习起来很难受. 所以我做了一个小工具,通过修改抽象语法树,来处 ...

  3. JAVA_Scanner 键盘输入

    键盘输入语句 介绍:在编程中,需要接收用户输入的数据,就可以使用键盘输入语句来获取.Input.java , 需要一个 扫描器(对象), 就是 Scanner 步骤: 导入该类的所在包, java.u ...

  4. C# form捕捉方向键事件

    在C# Form中监听键盘输入事件本身是很简单的,但是如果是想监听键盘上的上下左右这四个方向键,实现起来有所不同.下面我就以一个Demo简单陈述一下实现过程. 一.为了让界面能够监听键盘事件,必须实现 ...

  5. 'javac' 不是内部或外部命令,也不是可运行的程序或批处理文件

    记录在配置环境变量中被 Path 环境坑的一次前提:保证自己电脑中jdk环境配置都没有问题,即JAVA_HOME.Path.CLASSPATH均配置成功. 在这里我就不操作如何配置环境变量了,百度上面 ...

  6. 2022年官网下安装Elasticsearch最全版与官网查阅方法(8.1.0最新安装)

    目录 一.环境整合(需要提前装好) 构建工具(参考工具部署方式) 二.官方下载Elasticsearch部署安装 1.百度搜索"Elasticsearch",或者访问官网https ...

  7. vue项目部署到阿里云服务器(windows),Nginx代理!

    项目构成: 前端:vue+vant-ui, 数据库:mysql, 后端:node.js 部署方式:nginx代理: 一,首先要拥有自己的服务器,阿里,腾讯都可以,我用的是阿里的: 如果只是做个人项目的 ...

  8. ## [湖南省赛2019]Findme ###

    [湖南省赛2019]Findme 1.题目概述 2.解题过程 010打开这几张图片 先简单分析一下这几张图片 简单分析 1.png 从外观上,1.png明显高度太低,需要更改 2.png 2.png末 ...

  9. mysqkl修改存放位置 列的数据

    1.表一旦创建后,列的数据是否可以修改?如果可以说明语法 update 表名称 set 列名='新内容' where 列名=某值  橙色代表条件列 2.修改存放数据的文件夹 先关闭mysql  把da ...

  10. 4月13日 python学习总结 组合与封装

    一.组合      解决类与类之间代码冗余问题有两种解决方案:1.继承 2.组合 1.继承:描述的是类与类之间,什么是什么的关系 2.组合:描述的是类与类之间的关系,是一种什么有什么关系 一个类产生的 ...