搭建web框架

# 通常网址一般由以下几个部分组成
#
# 1. 协议(protocol): http, https(加密的 http)
# 2. 主机(host): baidu.com, google.com, localhost......
# 3. 端口(port): HTTP 默认是 80 端口, https 是 443
# 4. 路径(path): 端口后面的 / 后面的内容
# 5. 参数(query): ? 后面的内容, 以 & 分隔
#
# 以下面几个为例:
# https://www.bilibili.com/video/BV1Wf4y1g7SY
# 协议是 https
# 主机是 www.bilibili.com
# 端口是默认端口, 所以没有填写
# path 是 /video/BV1Wf4y1g7SY
#
# https://www.bilibili.com/video/BV1P3411m7AX?spm_id_from=333.851.b_7265636f6d6d656e64.2
# 这个后面多了一串, 从 ? 开始, 这是 query, 是 key-value 形式的参数
# 这里的参数值是 {spm_id_from: 333.851.b_7265636f6d6d656e64.2}
#
#
# 又比如 http://localhost:8000?a=1&b=2&c=9
# 协议是 http
# 主机 localhost
# 端口 8000
# path: /
# 参数 {a: 1, b: 2, c: 9}
#
#
#
# 计算机其实是靠 ip 地址通信的。
# 但是一连串的 ip 很难记, 所以就发明了域名这个玩意儿。
# 上面的 bilibili.com 就是个域名。当你访问它的时候, 计算机会去 DNS 服务器查找域名对应的 ip。
# localhost 比较特殊, 他一般指向本机的 ip 127.0.0.1(Linux 下面 cat /etc/hosts 可以看到)
# 扩展阅读: https://www.cnblogs.com/isme-zjh/p/11553165.html
#
#
# 两个小知识点:
#
# 1. 有时候电脑能聊 QQ, 但是上不了网页, 经常会说换一个 DNS, 这里实际上就是换一个 DNS 服务器地址(我去 A DNS 服务器进行 DNS 解析失败了, 那我换一个 B DNS 服务器)
#
# 2. ping www.baidu.com, 会看到一个 ip 地址, 直接通过 ip 访问也是一样的。其他网站同理。
#
#
#
# 端口是什么?
# 计算机通过了 ip 找到了对方, 但是我并不知道你是哪个程序和我建立的这个链接, 端口就是用来干这个的。
# 比如你看的那边 flask 书, 会用 localhost:5000 访问你写的 flask 网站, 这里就是你写的 flask 程序在监听 5000 这个端口。
# 端口是一个 16 位的数字, 所以范围是 0-65535(2^16)
#
#
#
# HTTP是一个协议, 协议就是一个大家都遵守的规范, 大家都按这个规则来。
#
# 1. 浏览器(客户端)按照规定的格式发送文本数据(请求)到服务器
# 2. 服务器解析请求, 按照规定的格式返回文本数据到浏览器
# 3. 浏览器解析得到的数据, 并做相应处理
#
#
# 请求和返回是一样的数据格式, 大致分为 4 个部分:
# 1. 请求行或者响应行
# 2. Header(请求的 Header 中 Host 字段是必须的, 其他都是可选)
# 3. \r\n\r\n(连续两个换行回车符, 用来分隔 Header 和 Body)
# 4. Body(可选)
#
#
# 请求的格式举例(这是一个不包含 Body 的请求)
#
# 原始数据如下
# 'GET / HTTP/1.1\r\nlocalhost:5000\r\n\r\n'
# 打印出来如下
# GET / HTTP/1.1
# Host: localhost:5000
#
# 其中
# 1. GET 是请求方法(还有POST等, 这就是个标志字符串而已)
# 2. / 是请求的路径(这代表根路径)
# 3. HTTP/1.1 中, 1.1 是版本号, 通用了几十年
#
#
# 响应格式如下
#
# HTTP/1.1 200 OK
# Content-Type: text/html; charset=utf-8
# Content-Length: 11
# Server: Werkzeug/1.0.1 Python/3.8.2
# Date: Fri, 15 Oct 2021 14:26:18 GMT
#
# ......(这里是 Body, 省略了)
#
# HTTP/1.1 200 OK 是响应行, HTTP/1.1 是版本, 200 是状态码, OK 是状态码的描述
# 后面是一些其他的 response header, 你现在可以不用关心
#
# 浏览器会自动解析响应, 将响应的 Body 渲染成网页显示出来。
#
#
#
# web 服务器(相当于你写的 flask 应用)的主要工作是什么?
#
# 主要就是解析请求(request), 根据 request 返回相应的响应(response)给客户端。
#
# --------分割线--------------------
#
#
# 下面是两段代码

# 1. client.py, 这个代码模拟了浏览器发送请求到网页服务端的行为
import socket


log = print

# socket 是操作系统用来进行网络通信的接口, 你现在不需要关心

# 首先创建一个 socket 对象
# 参数 socket.AF_INET 表示是 ipv4 协议
# 参数 socket.SOCK_STREAM 表示是 tcp 协议
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

# 主机(域名或者ip)和端口
host = 'baidu.com'
port = 80
# 用 connect 函数连接上主机
s.connect((host, port))

# 连接上后, 可以通过这个函数得到本机的 ip 和端口
ip, port = s.getsockname()
log(f'本机 ip: {ip}, port: {port}')

# 构造一个 HTTP 请求
http_request = f'GET / HTTP/1.1\r\nhost:{host}\r\n\r\n'
# 发送 HTTP 请求给服务器
# send 函数只接受 bytes 作为参数
# str.encode 把 str 转换为 bytes, 编码是 utf-8
request = http_request.encode('utf-8')
log('请求', request)
s.send(request)

# 接受服务器的响应数据
# 参数是长度, 这里为 1024 字节
# 所以这里服务器返回的数据中超过 1024 的部分你就得不到了
response = s.recv(1024)

# 输出响应的数据, bytes 类型
log('响应', response)
# 转成 str 再输出
log('响应的 str 格式', response.decode('utf-8'))


# 2. server.py  这是一个简单的 server 程序

import socket


log = print


# 运行这个程序后, 浏览器打开 localhost:8888 就可能可以访问
# (我试了一下, Chrome 版本 83.0.4103.116(正式版本) (64 位)会收不到响应, 很奇怪, 但是 firefox 是正常的)
# 你还可以把上面的 client.py 的主机和端口改成这个 server 绑定的主机和端口看结果
host = '0.0.0.0'
port = 8888

# s 是一个 socket 实例
s = socket.socket()
# s.bind 用于绑定
s.bind((host, port))


# 用一个无限循环来处理请求
while True:
    # 用 s.listen 开始监听, 这个 5 的含义你不需要关心
    # 你如果想知道, 到时候我可以告诉你
    # 这些创建 socket 的代码, 你就把它当做一个套路就行了, 需要用的时候按套路这样写
    # 这些 api 的设计是很失败的, 暴露了这么多垃圾概念, 数据, 接口给你
    # 人做出来的东西都是有缺陷的, 如果深究就说明你会觉得“专家”必有深意, 容易溺毙在粪坑
    # 比如这个 listen(5) 就是一个不应该随意暴露的 api, 因为这对普通程序没什么意义
    s.listen(5)
    # 当有客户端过来连接的时候, s.accept 函数就会返回 2 个值
    # 分别是 连接 和 客户端 ip 地址
    connection, address = s.accept()

    # recv 可以接收客户端发送过来的数据
    # 参数是要接收的字节数
    # 返回值是一个 bytes 类型
    request = connection.recv(1024)

    # bytes 类型调用 decode('utf-8') 来转成一个字符串(str)
    log(f"ip and request, {address}\n{request.decode('utf-8')}")

    # b'' 表示这是一个 bytes 对象
    response = b'<h1>Hello World!</h1>'
    # 用 sendall 发送给客户端
    connection.sendall(response)
    log('发送完毕')
    # 发送完毕后, 关闭本次连接
    connection.close()
    log('关闭本次连接')



# ------------------------分割线----------------------------
# 这下面是你要做的事情


# 1. 实现这个方法
def parsed_url(url):
    '''
    解析 url
    返回一个 tuple, 内容如下(protocol, host, port, path), 先不考虑 query
    '''
    pass


# 2. 实现下面的代码

def get(url):
    '''
    使用上面的 client.py 中的方式连接 url 服务器
    获取服务器返回的数据并返回
    你需要注意的是, 给你的例子只取了 1024 的长度, 而这里你需要完整的读取所有数据
    '''
    pass


# 使用
def __main():
    url = 'https://www.baidu.com'
    r = get(url)
    print(r)


if __name__ == '__main__':
    __main()
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值