Linux套接子(c语言)模拟http请求、应答
有关套接子和http请求报文的博客在CSDN有很多比如,点这里查看,这里我就不再做过多赘述了,下面我们直接实战,模拟http请求。
要求:浏览器访问本地的localhost,在浏览器页面打印出 Hello World
首先:ping 一下百度的网址得到一个百度的ip,我们可以利用这个ip来查看http应答报头
39.156.69.79这是我们得到的百度的ip,事实上我下面用到的代码是另一个ip(220.181.112.244 是 baidu.com 另一个 ip 地址)。代码呈上
#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: 220.181.112.244\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("220.181.112.244");
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;
}
通过上面这段代码我们可以得到百度的http应答格式,以便于我们模仿这种格式写出我们自己的服务端代码。浏览器返回的信息如下所示:
HTTP/1.1 200 OK
Accept-Ranges: bytes
Cache-Control: no-cache
Content-Length: 14615
Content-Type: text/html
Date: Thu, 24 Oct 2019 18:06:08 GMT
P3p: CP=" OTI DSP COR IVA OUR IND COM "
P3p: CP=" OTI DSP COR IVA OUR IND COM "
Pragma: no-cache
Server: BWS/1.1
Set-Cookie: BAIDUID=0F88738275DFC145AFA84697D48B8087:FG=1; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BIDUPSID=0F88738275DFC145AFA84697D48B8087; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: PSTM=1571940368; expires=Thu, 31-Dec-37 23:55:55 GMT; max-age=2147483647; path=/; domain=.baidu.com
Set-Cookie: BAIDUID=0F88738275DFC1456A9A4114F710FF71:FG=1; max-age=31536000; expires=Fri, 23-Oct-20 18:06:08 GMT; domain=.baidu.com; path=/; version=1; comment=bd
Traceid: 1571940368268139802612049320315244439823
Vary: Accept-Encoding
X-Ua-Compatible: IE=Edge,chrome=1
Connection: close<!DOCTYPE html><!--STATUS OK-->
<html>
<head>…… 这里省略一大堆内容 ……
</body></html>
以上我们可以得到:
- HTTP/1.1 200 OK //1.1表示http协议版本 200为状态码 OK为状态描述
- Accept-Ranges: bytes //标识自身支持范围请求 更多
- Cache-Control: no-cache //指定请求和响应遵循的缓存机制
- Content-Length: 14615 //要发送的内容长度
- Connection: close //短连接,表示服务器给客户端发送信息之后就断开了
其次:是服务器端的代码,这里我使用了多线程,以便实现多个客户端(页面)同时访问
#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 <pthread.h>
//套接子通讯服务端,全双工
//多线程
void thread_fun(void* arg)
{
int c = (int)arg;
//保存http应答头部信息
char Http[2048] = "HTTP/1.1 200 OK\r\nAccept-Ranges: bytes\r\n\
Content-Length: 13\r\nConnection: close\r\n\\r\n";
//客户端要接收的内容,与头部中的Content-Length对应
char buff[128] = "hello world!";//发送的数据
strcpy(Http, buff);
char tmp[1024] = {0};//接受客户端请求
int n = recv(c,tmp,1023,0);
printf("%s\n",tmp);//打印客户端请求
send(c,Http,strlen(Http),0);//向客户端应答
close(c);//每个客户端只接收一次就关闭
printf("client close\n");
}
int main()
{
int sockfd = socket(AF_INET, SOCK_STREAM, 0);//文件标识符
assert( sockfd != -1);
struct sockaddr_in saddr,caddr;//ipv4地址结构
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");//自己主机ip
int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));/*绑定监听的ip地址和端口*//*端口或ip错误会导致绑定失败*/
assert( res != -1);
listen(sockfd, 5);//创建监听队列,开始监听,不会阻塞
//循环执行多次响应 注:如果不使用多线程或多进程的方式处理,只能同时响应一个客户端,其他客户端在监听队列排队,直到上一个客户端关闭,这里使用了多线程
while(1)
{
int len = sizeof(caddr);
int c = accept(sockfd, (struct sockaddr*)&caddr, &len);//c为监听套接子
if( c < 0)
{
continue;//如果接收失败,重新接收
}
//printf("accept c = %d\n",c);//打印文件描述符,表示这是第几个客户端,其中0、1、2号不可用,为标准输入、输出、错误输出,3号为sockfd,因此客户端从4开始
printf("accept(ip:%s,port:%d) c = %d\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),c);
//多线程
pthread_t id;
pthread_create(&id,NULL,thread_fun,(void*)c);//这里没有传递c的地址,防止c多次使用时值被改变
}
}
至此,服务端就完成了,由于我们使用了80号端口,所以运行时请用管理员权限。另外,服务端关闭后服务端的状态不会马上成为CLOSED状态,此时服务端处于TIME_WAIT状态,两分钟左右后才会完全关闭,服务端才能再次运行,具体原理请查资料TCP状态转移图 。用到的命令主要有以下几个:
编译: $gcc -o ser_http ser_http.c -pthread
运行: $sudo ./ser_http
$netstat -natp 此命令可查看使用TCP网络资源的进程
最后:我们根据服务端接受的来自网页的请求报文,还可以自己写一个客户端的代码
步骤:运行服务端,浏览器输入 localhost 回车,在服务端上已经打印出了来自浏览器的请求报文,如下所示:
accept(ip:127.0.0.1,port:37022) c = 4
GET / HTTP/1.1
Host: localhost
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0
Accept: image/webp,*/*
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: keep-alive
以上我们可以得到:
- GET / HTTP/1.1 //用GET方式请求,http协议,版本1.1
- Host: localhost //本地主机
- User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:69.0) Gecko/20100101 Firefox/69.0 //用户代理:操作系统、浏览器等的信息
- Connection: keep-alive //长链接
根据以上信息模拟客户端的http请求,代码如下:
#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>
int main()
{
int sockfd = socket(AF_INET,SOCK_STREAM, 0);
assert( sockfd != -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 = connect(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));
assert( res != -1);
//模拟http请求报头
char str[1024] = "GET / HTTP/1.1\r\nHost: 127.0.0.1\r\nConnection: Close\r\n\r\n";
send(sockfd, str, strlen(str), 0);//发送请求
memset(str, 0, 1024);
recv(sockfd,str,1023,0);//接受
printf("%s\n",str);
close(sockfd);
}
以上只实现了固定格式的http的应答方式,也就是说不管客户端发送的请求内容是什么,我们服务端都回复相同的信息,但真实的服务器是会根据请求内容的不同向客户端发送不同的内容,因此我们可以重新设计服务端实现动态的根据客户端的请求内容进行相应的响应应答。模拟web服务器http请求应答
Linux套接子(c语言)模拟http请求、应答的更多相关文章
- 模拟web服务器http请求应答
我们在浏览器打开网页,其实是向远端服务器提出页面发送请求,远端服务器在接到请求后,就开始执行请求页面的程序文件,然后将执行结果通过html格式,发送到你的浏览器,再显示出来.以下用百度(www.bai ...
- 在Linux上利用curl 命令模拟 HTTP GET/POST 请求
本文系转载,原文地址:https://www.cnblogs.com/alfred0311/p/7988648.html 序言 在 Linux 操作系统上对后端程序进行测试的时候,需要进行模拟连接或者 ...
- Linux用C语言模拟‘ls‘命令
原理 在linux下使用C语言,通过调用Linux系统的目录访问API来实现一个类似于ls命令功能的小程序,主要是可以练习程序对命令的解析和目录API函数的使用. 实现代码 #include < ...
- 第五十九节,模拟浏览器请求Python结合html基本格式
模拟浏览器请求Python结合html基本格式 用Python模拟一个客户端,结合打开一个HTML页面 创建客户端 #!/usr/bin/env python # -*- coding:utf8 -* ...
- linux 套接字编程入门--Hello World
下述代码是linux套接字编程的入门代码.分为服务端和客户端源码. 服务端代码的主要流程是绑定ip地址和端口号建立套接字,等待客户端发起访问.接受客户端请求之后,向客户端发送字符串"hell ...
- socket - Linux 套接字
总览 #include <sys/socket.h> mysocket = socket(int socket_family, int socket_type, int protocol) ...
- 使用 jQuery Mockjax 插件模拟 Ajax 请求
在实际的开发过程中,前端后台协商好了统一的接口,就各自开始自己的任务了.这时候我有这么一个 Ajax 请求需要从后台获取数据: $.ajax({ url: '/products/' }).done(f ...
- Linux 内核 链表 的简单模拟(1)
第零章:扯扯淡 出一个有意思的题目:用一个宏定义FIND求一个结构体struct里某个变量相对struc的编移量,如 struct student { int a; //FIND(struct stu ...
- Linux 套接字编程中的 5 个隐患(转)
本文转自IBM博文Linux 套接字编程中的 5 个隐患. “在异构环境中开发可靠的网络应用程序”. Socket API 是网络应用程序开发中实际应用的标准 API.尽管该 API 简单,但是开发新 ...
随机推荐
- Specified cast is not valid(C#) 引发的思考(装箱,拆箱本质)
没有很华丽的语言,直接拿代码说事情把. 这段代码,会报错吗? 结论:当然不会 这段代码会报错了.原因是为啥? 这里面的水比较深.也要提醒各位写代码的适合要引起注意.异常:System.Invalid ...
- AcWing 288. 休息时间
传送门 思路: 考虑DP,设dp[i][j][1]为牛在前小时休息j个小时且第i个小时休息时,回复的最多体力:dp[i][j][0]为牛在前小时休息j个小时且第i个小时没有休息时,回复的最多体力. 可 ...
- 量化研究之“大A打板敢死队”是如何做换手板与撬板的?
更多精彩内容,欢迎关注公众号:数量技术宅,也可添加技术宅个人微信号:sljsz01,与我交流. 涨停跌停板分类 涨停.跌停是A股特有的现象,其他主要市场,例如美股.港股都不存在涨跌停的规则.涨停.跌停 ...
- docker学习笔记(6)——docker场景问题汇总(centos7 由于内核版本低带来的一系列问题,docker彻底卸载,安装、启动日志报错分析)
参考资料: https://nachuan.blog.csdn.net/article/details/96041277 https://www.cnblogs.com/xzkzzz/p/962765 ...
- Spring框架第一天(搭建项目)
Spring框架 1.简介 1.1 Spring是什么 一个开源的框架,是JavaEE开源框架 Spring是分层的 Java SE/EE应用 full-stack 轻量级开源框架,以IoC(Inve ...
- info sharp Are you trying to install as a root or sudo user? Try again with the --unsafe-perm flag
执行 npm install 编译出错,提示 ERR! sharp EACCES: permission denied, mkdir '/root/.npm' info sharp Are you t ...
- Ubuntu系统中防火墙的使用和开放端口
目录 Ubuntu系统 防火墙的使用和开放端口 1.安装防火墙 2.查看防火墙状态 3.开启.重启.关闭防火墙 4.Ubuntu添加开放.关闭端口 5.开放规定协议的端口 6.关闭指定协议端口 7.开 ...
- web服务器-nginx默认网站
web服务器-nginx默认网站 一 默认网站 server { listen 80; server_name localhost; location / { root html; index ind ...
- OpenMLDB 在线模块架构解析
本文介绍 OpenMLDB 在线模块的架构,欢迎通过以下渠道了解关于 OpenMLDB 的更多信息 GitHub:GitHub - 4paradigm/OpenMLDB: OpenMLDB is an ...
- web安全常用端口
21 FTP 22 SSH 23 Telent 25 SMTP 53 DNS 80 HTTP 135 139 443 HTTPS 445 SMB 1433 SQLSERVER 1521 ORCAL 3 ...