通信、socket与http协议
通信
我们讲通信,是指一方对另一方信息交换的过程。信息交换需要两个条件,一个是信息,一个是载体。
为了通信,我们创造了许多,其中最重要的发明莫过于网络。有了网络我们就可以在不同的主机上传输信息,这其中通信的基础之一就是socket,当然它并不是最基础的,在计算机世界还有更底层的物理硬件层面的传输技术,但对写代码来说socket是网络通信最基础的技术了。
socket是什么
首先要明确,我们编码中用到的所有知识,技巧都来自于OS(操作系统),OS提供了什么样的api,代码层面就拥有什么能力。socket则在操作系统被创造时便赋予的能力,通过socket技术,我们就可以在不同的主机间通过网络传输数据了。
以LINUX为例,通过查看linux手册可以获取到socket接口的基本信息(在linux命令行中输入man socket),这里只是贴出定义,不要求看懂,可以直接看下方的总结
socket的定义
socket用于创建端到端的通信。定义socket需要三个参数。
1.domain参数指定了通信的域(域的理解就是,某种类型的抽像设备),设置domain将帮助socket选择通信的协议family(族?)
常见参数值的比如:
- AF_UNIX 用于本地通信,例如同主机上的进程间通信
- AF_INET 用于因特网通信,即不同主机间的进程通信
2.type参数指定通信语义
通常我们使用SOCK_STREAM,指定连接提供顺序的,可靠的,双向的,基于连接的字节流。 (其他参数在本文讨论的通信范畴里不会用到。)
3.protocol,该参数指定socket所使用的协议。通常,给定的协议族的socket类型只支持一种协议,这种情况下protocol可以为0.(即通常情况下,我们不会用到这个参数)
Python中的socket用法
1.建立socket server
1 | import socket |
使用socket要经过bind,listen,accept等流程,这是定义时已被决定的流程。
socket.AF_INET表示我们正在使用因特网,socket.SOCK_STREAM表明这个socket是因特网链接的一个端点,传输字节数据。
bind函数告诉操作系统内核将socket地址即(127.0.0.1,8085)与socket描述符s联系起来(在类unix系统中,一切设备都是文件,而文件的读写要通过描述符来进行)。
listen函数将描述符s转化为监听描述符,同时也告诉内核,这个描述符是被服务器使用,即当前是个server socket进程。
accept函数等待,客户端的连接请求是否到达bind时的socket地址。当有请求来时返回已连接描述符。当建立已连接描述符时,说明可以在服务端和客户端间传输数据了。
2.使用socket建立客户端并发送数据
1 | import socket |
与服务端不同的是,客户端直接使用connect方法连接到远端的socket地址,客户端connect请求被服务端accept接收到。
当完成这个步骤后就可以使用send传输数据了。发送完毕后通过close()关闭socket连接,便完成了一次socket通信。
tips:前面提到的socket.SOCK_STREAM参数值是全双工(双向工作)的,因此,服务器也可以向客户端发送数据。
归纳推导
通过socket可以传输任意的文本输入了。
仅仅是发送文本还不够,我们会自然的想到,对文本约定一些格式,就可以传输更多类型。
比如:
传送dict类型的数据,我们可以约定字符串格式形如:“key1=value1,key2=value2……keyn=valuen”,
服务端收到时,反向解析一下,即可得到期望数据,解析函数如下:
1 | def parse(data): |
所以此时我们可以通过socket client发送数据
1 | s.send(b"name=test,pass=pppp") |
而服务端解析
1 | with conn: |
得到结果
1 | D:\env\Python38\python.exe D:/service/material/socket/server.py |
由此,延展这一点,我们知道,可以指定越来越规范严格的约束,来传送更多的数据。
所以http来了,超文本传输协议。
HTTP协议
HTTP对socket传输的数据做了各种各样的约束,以至于可以传输媒体文件,超文本传输协议真不是浪的虚名。
因此,web服务器便是实现了http协议的socket服务器,浏览器则是以http约束数据格式发送数据的socket客户端。
我们可以构造自己的简单的web服务器,这需要一点点的http知识。
重要的两个概念:
Request: 客户端发送的数据
请求行(request line)、请求头部(header)、空行和请求数据四个部分组成。
以这样的定义,我们构造一个GET请求
1 | GET / HTTP/1.1 \r\nHOST 127.0.0.1:8085\r\n |
Resonse: 客户端接收到的数据(服务端发送的数据)
响应也由四个部分组成,分别是:状态行、消息报头、空行和响应正文。
实现自己http服务器
1 | #!/bin/python |
测试结果:
1 | D:\env\Python38\python.exe D:/service/material/socket/http_server.py |
到此为止,只是实现了简单的http服务,http协议还有很多的约束用于数据传输。但是本质上所有的web服务器底层的工作原理都是这样。
为了提高服务器性能,流行的web框架采用了各种各样的技术,但这些技术本质上也是操作系统提供的api而已。
下一次,我们将继续丰富我们的web服务器,添加更多的http支持,完成HTTPServer与HTTPClient类。
下载代码:
参考资料: