黏包现象和HTTP协议

  • 黏包现象
    • 什么是黏包
    • 解决方案
  • HTTP协议
    • HTTP协议概念
    • URL的概念
    • 查看HTTP通信过程
    • HTTP请求报文分析
    • HTTP响应报文分析
  • 静态web服务器
    • 什么是静态web服务器
    • 搭建python自带的静态web服务器
    • 搭建自己的静态web服务器

黏包现象

什么是黏包

  • 当发送网络数据时,tcp协议会根据Nagle算法将时间间隔短,数据量小的多个数据包打包成一个数据包,先发送到自己操作系统的缓存中,然后操作系统将数据包发送到目标程序所对应操作系统的缓存中,最后将目标程序从缓存中取出,而第一个数据包的长度,应用程序并不知道,所以会直接取出数据或者取出部分数据,留部分数据在缓存中,取出的数据可能第一个数据包和第二个数据包粘到一起
  • 下面通过代码来说明黏包现象
  • 通过结果我们可以看到,客户端其实是发了两条信息,而服务端将这两条信息合并为了一条信息,这就是黏包现象,因为应用程序并不知道第一个数据的长度,是从缓存中直接抽取一部分数据,所以可能会出现这种,两次的信息黏在一起的现象。

解决方案

  • 接下来讨论上述黏包现象的解决方案,在这之前先引入一个模块,叫做struct模块,struct模块中最重要的两个函数为pack和unpack
  • pack函数:作用是将数据以一定的方式打包成二进制格式。
  • unpack函数:作用是从写好的二进制文件中读出文件。
  • 引入struct模块以后,我们解决黏包的思路就有了,因为黏包现象是因为不知道第一个数据的长度引起的,故而我们可以在发送真正的数据之前,先发送第一个数据的长度给服务端,而pack函数固定将数据打包成4个长度的二进制文件使得我们可以将第一次接收的长度设为固定的4,从而很好的阻止接收长度时出现黏包现象,有了长度之后不但可以解决黏包现象,还可以解决由于数据过大,超过接收的最大值导致数据一次不能接收完成的问题。
  • 具体的代码如下:
  • 客户端
import socket
import structdef main():client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)client.connect(('127.0.0.1', 7890))# 1.先接收报头header = client.recv(4)# 2.从报头中解析出数据长度data_size = struct.unpack('i', header)[0]# 3.接收真实的数据recv_size = 0total_data = b''while recv_size < data_size:data_recv = client.recv(1024)total_data += data_recvrecv_size += len(data_recv)print(total_data.decode('utf-8'))if __name__ == '__main__':main()
  • 服务端:
import socket
import structdef main():# 创建套接字server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server.bind(('127.0.0.1', 7890))server.listen(128)new_socket, addr = server.accept()content = """Windows IP 配置"""res = struct.pack('i', len(content))new_socket.send(res)new_socket.send(content.encode('utf-8'))if __name__ == '__main__':main()

HTTP协议

HTTP协议概念

  • HTTP 协议的全称是(HyperText Transfer Protocol),翻译过来就是超文本传输协议。
    超文本是超级文本的缩写,是指超越文本限制或者超链接,比如:图片、音乐、视频、超链接等等都属于超文本。HTTP 协议的制作者是蒂姆·伯纳斯-李,1991年设计出来的,HTTP 协议设计之前目的是传输网页数据的,现在允许传输任意类型的数据。传输 HTTP 协议格式的数据是基于 TCP 传输协议的,发送数据之前需要先建立连接。
  • 作用:它规定了浏览器和 Web 服务器通信数据的格式,也就是说浏览器和web服务器通信需要使用http协议。

URL的概念

  • URL的英文全拼是(Uniform Resoure Locator),表达的意思是统一资源定位符,通俗理解就是网络资源地址,也就是我们常说的网址。
  • URL的组成
    URL的样子:https://news.163.com/18/1122/10/E178J2O4000189FH.html
  • URL的组成部分:
    • 协议部分: https://、http://、ftp://
    • 域名部分: news.163.com
    • 资源路径部分: /18/1122/10/E178J2O4000189FH.html
  • 域名:
    域名就是IP地址的别名,它是用点进行分割使用英文字母和数字组成的名字,使用域名目的就是方便的记住某台主机IP地址。
  • URL的扩展:
    https://news.163.com/hello.html?page=1&count=10
  • 查询参数部分: ?page=1&count=10
    • 参数说明:

      • ? 后面的 page 表示第一个参数,后面的参数都使用 & 进行连接

查看HTTP通信过程

  • 首先需要安装Google Chrome浏览器,然后Windows和Linux平台按F12调出开发者工具, mac OS选择 视图 -> 开发者 -> 开发者工具或者直接使用 alt+command+i 这个快捷键,还有一个多平台通用的操作就是在网页右击选择检查。

  • 开发者工具的标签选项说明:

    • 元素(Elements):用于查看或修改HTML标签
    • 控制台(Console):执行js代码
    • 源代码(Sources):查看静态资源文件,断点调试JS代码
    • 网络(Network):查看http协议的通信过程
  • 开发者工具的使用说明:

    • 点击Network标签选项
    • 在浏览器的地址栏输入百度的网址,就能看到请求百度首页的http的通信过程
    • 这里的每项记录都是请求+响应的一次过程
  • 主要信息

  • 请求头信息

  • 响应头信息

  • 响应体信息

HTTP请求报文分析

  • HTTP请求报文是浏览器发送给服务器的数据
  • 最常见的请求报文分两种:
    • get方式的请求报文
    • post方式的请求报文
  • 说明:
    • get:获取服务器数据
    • post:向服务器提交数据
  • get请求报文说明:
GET / HTTP/1.1  # GET请求方式 请求资源路径 HTTP协议版本
---- 请求头 -----
Host: www.baidu.com  # 服务器的主机地址和端口号,默认是80
Connection: keep-alive # 和服务端保持长连接
Upgrade-Insecure-Requests: 1 # 让浏览器升级不安全请求,使用https请求
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36  # 用户代理,也就是客户端的名称
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 # 可接受的数据类型
Accept-Encoding: gzip, deflate # 可接受的压缩格式
Accept-Language: zh-CN,zh;q=0.9 #可接受的语言
Cookie: pgv_pvi=1246921728; # 登录用户的身份标识---- 空行 ----
  • get请求原始报文说明:
Host: www.baidu.com\r\n
Connection: keep-alive\r\n
Upgrade-Insecure-Requests: 1\r\n
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36\r\n
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\n
Accept-Encoding: gzip, deflate\r\n
Accept-Language: zh-CN,zh;q=0.9\r\n
Cookie: pgv_pvi=1246921728; \r\n
\r\n  (请求头信息后面还有一个单独的’\r\n’不能省略)
  • 概括来说,请求报文所有行后面加上\r\n就是原始请求报文
  • post 请求报文说明:
POST /xmweb?host=mail.baidu.cn&_t=1542884567319 HTTP/1.1 # POST请求方式 请求资源路径 HTTP协议版本
---- 请求头 ----
Host: mail.itcast.cn # 服务器的主机地址和端口号,默认是80
Connection: keep-alive # 和服务端保持长连接
Content-Type: application/x-www-form-urlencoded  # 告诉服务端请求的数据类型
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36 # 客户端的名称
---- 空行 ----
---- 请求体 ----
username=hello&pass=hello # 请求参数
  • 对比总结

    • 一个HTTP请求报文可以由请求行、请求头、空行和请求体4个部分组成。
    • 请求行是由三部分组成:
      • 请求方式
      • 请求资源路径
      • HTTP协议版本
    • GET方式的请求报文没有请求体,只有请求行、请求头、空行组成。
    • POST方式的请求报文可以有请求行、请求头、空行、请求体四部分组成,注意:POST方式可以允许没有请求体,但是这种格式很少见。

HTTP响应报文分析

  • 响应报文即是服务器向浏览器发送的数据
  • 响应报文说明:
HTTP/1.1 200 OK # HTTP协议版本 状态码 状态描述
--- 响应头 ---
Server: Tengine # 服务器名称
Content-Type: text/html; charset=UTF-8 # 内容类型
Transfer-Encoding: chunked # 发送给客户端内容不确定内容长度,发送结束的标记是0\r\n, Content-Length表示服务端确定发送给客户端的内容大小,但是二者只能用其一。
Connection: keep-alive # 和客户端保持长连接
Date: Fri, 23 Nov 2018 02:01:05 GMT # 服务端的响应时间
--- 空行 ---
--- 响应体 ---
<!DOCTYPE html><html lang=“en”> …</html> # 响应给客户端的数据
  • HTTP状态码介绍
状态码 说明
200 请求成功
307 重定向
400 错误的请求,请求地址或者参数有误
404 请求资源在服务器不存在
500 服务器内部源代码出现错误

静态web服务器

什么是静态web服务器

  • 可以为发出请求的浏览器提供静态文档的程序。平时我们浏览百度新闻数据的时候,每天的新闻数据都会发生变化,那访问的这个页面就是动态的,而我们开发的是静态的,页面的数据不会发生变化。

搭建python自带的静态web服务器

  • 搭建Python自带的静态Web服务器使用 python -m http.server 端口号
  • 通过浏览器访问搭建的静态服务器
  • 它显示的目录,即为我们执行命令的当前文件夹下的文件目录
  • 我们也可以将目录设定在python的文件夹下,使用python创建html文件,然后通过静态服务器来访问

搭建自己的静态web服务器

  • HTTP协议是基于TCP协议的,所以第一步要搭建一个TCP协议的服务器,然后接受请求报文并返回响应报文给浏览器,接下来是实现的具体过程。
import socketdef main():tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcp_server.bind(('192.168.0.104',8080))tcp_server.listen(128)new_socket,addr = tcp_server.accept()recv_request = new_socket.recv(1024).decode('utf-8')with open('index.html','r') as f:response_body = f.read()response_line = 'HTTP/1.1 200 OK\r\n'response_header = "Server: PWS/1.1\r\n"response_data = response_line + response_header + '\r\n' + str(response_body)new_socket.send(response_data.encode('utf-8'))

运行程序,并通过浏览器对自定义的服务器进行访问,可以得到如下结果:

  • 上述程序是自定义一个静态web服务器,返回一个固定页面,我们可以对代码进行一些优化,让其返回我们指定的页面,而当访问的页面不存在时,返回404,优化代码如下:
import socketdef main():tcp_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)tcp_server.bind(('192.168.0.104',8080))tcp_server.listen(128)while True:new_socket, addr = tcp_server.accept()recv_request = new_socket.recv(4096).decode('utf-8')print('recv_request:',recv_request)recv_request1 = recv_request.split(" ")print('split:',recv_request1)request_path = recv_request1[1]print('path:',request_path)try:with open('static'+request_path,'r',encoding='utf-8') as f:response_body = f.read()except Exception as e:print(e)response_line = 'HTTP/1.1 404 Not Found\r\n'response_header = "Server: PWS/1.1\r\n"with open('static/404.html','r',encoding='utf-8') as b:response_body = b.read()response_data = response_line + response_header + '\r\n' + response_bodynew_socket.send(response_data.encode('utf-8'))else:response_line = 'HTTP/1.1 200 OK\r\n'response_header = "Server: PWS/1.1\r\n"response_data = response_line + response_header + '\r\n' + str(response_body)new_socket.send(response_data.encode('utf-8'))finally:new_socket.close()if __name__ == '__main__':main()

黏包现象和HTTP协议相关推荐

  1. socket补充:通信循环、链接循环、远程操作及黏包现象

    socket补充:通信循环.链接循环.远程操作及黏包现象 socket通信循环 server端: import socketphone = socket.socket(socket.AF_INET,s ...

  2. 黏包现象及其解决方法

    1.黏包现象 服务端: 客户端: 第一次 dir 数据 < 1024 接收所有数据 第二次 ipconfig 数据 > 1024 接收1024个字节 第三次 dir 数据 < 102 ...

  3. python 心电处理包_python 黏包现象及其解决方案

    一.数据缓冲区 缓冲区(buffer),它是内存空间的一部分.也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区,显然缓冲区是具有一定大小的 ...

  4. 黏包现象和解决黏包的方法

    一, 缓冲区:  将程序和网络解耦 输入缓冲区 输出缓冲区 二,  sunbprocess模块 import subprocess sub_obj = subprocess.Popen('ipconf ...

  5. 网络编程- 解决黏包现象方案一(六)

    队列 利用队列的思路来解决黏包问题 总结 转载于:https://www.cnblogs.com/mys6/p/10797907.html

  6. 【Python基础篇021】黏包现象丨udp的socket服务

  7. python学习day32 黏包 struct模块

    为什么会出现黏包问题?  首先只有在TCP协议中才会出现黏包现象 是因为TCP协议是面向流的协议 在发送的数据 传输过程中 有缓存机制 来避免数据丢失 因此 在连续发送小数据的时候 以及接收大小不符的 ...

  8. 04、Netty学习笔记—(黏包半包及协议设计解析)

    文章目录 一.粘包与半包 1.1.现象分析 1.1.1.粘包.半包情况分析 1.1.2.滑动窗口.MSS限制.Nagle算法介绍 1.2.粘包.半包现象复现 1.2.1.粘包复现 1.2.2.半包复现 ...

  9. Python Socket通信黏包问题分析及解决方法

    参考:http://www.cnblogs.com/Eva-J/articles/8244551.html#_label5 1.黏包的表现(以客户端远程操作服务端命令为例) 注:只有在TCP协议通信的 ...

最新文章

  1. 绩效管理领域对管理者的任务和能力要求
  2. linux添加、修改环境变量
  3. iOS之深入解析Xcode的拼写检查
  4. 使用Google Test的一个简单例子
  5. 03JavaScript程序设计修炼之道-2019-06-20_20-31-49
  6. android 应用自动重启,Android 应用崩溃后自动重启的方法
  7. Why Redis 4.0?
  8. bash颜色、变量、数组、相关脚本示例
  9. HTML5教程:1.1 迎接新的Web时代
  10. 标准Lena测试图像下载
  11. [WARNING]: Could not match supplied host pattern, ignoring: servers
  12. 计算机每次启动时系统时间不更新,电脑每次开机都要重新设置时间
  13. python 怕网页_如何像玩游戏一样学Python?
  14. 测试智商多高的软件,智商测试:测测你的智商多高
  15. h5画三角形_H5如何在网页中绘制三角形,值得一看
  16. 阿里巴巴离职DBA_35岁总结的职业生涯
  17. y40.第三章 Kubernetes从入门到精通 -- k8s 资源对象(十三)
  18. Django网站开发 01.Web网站与前端HTML标签
  19. 热烈欢呼天宫一号与神八首次交会对接成功!
  20. 基于spring websocket+sockjs实现的长连接请求

热门文章

  1. proxychains全局代理设置
  2. 研究生期间遇到放养式导师该怎么办
  3. linux的vi编辑器课件,Linux课件vi编辑器的使用.ppt
  4. go每日新闻(2021-06-22)——毛老师的管理之道
  5. 【多元统计分析】19.因子分析
  6. 一本你肯定可以读懂的Java图书
  7. HTMl中a标签的用法
  8. AirSim 如何更换无人机模型
  9. 1200兆路由器网速_50兆光纤用1200兆路由器可以吗
  10. 网站服务器Win2003系统网络安全设置全攻略