让你自己跟自己玩——TCP/http协议进行通信和获取静态资源!(python)


如今这个时代,学编程不学Web没有出路。互联网联系了这世界上千千万万个人,拉近了彼此的距离,跨越了山河,你我之间再无距离。
文章不会太长,看完对你会有帮助,如果觉得不错就点赞评论支持一下吧!

前言

学习Web真的很重要,更加重要的是学习Web里面的框架,但是在学习框架前,最基本的通信要牢牢的掌握,我现在回过头来写这篇博客,分享的同时也是对我自身的一种巩固,加油吧!!!!之前说过努力敲代码的程序员们!!!

正文:

TPC是一种传输控制协议(想了解的可以点击蓝字进行跳转)
计算机间的通信离不开传输协议,所以我今天写一个关于Tcp的协议,来实习我们自己和自己玩的目的(狗头),这里先说一下:计算机间数据传输是二进制数据(这里着重看)

套接字(socket),先建立连接!

建立套接字(socket)
都是基本的语法格式,具体说一下这几个
AF_INETIPv4网络协议的套接字类型,AF_INET6 则是 IPv6 的;而 AF_UNIX 则是 Unix 系统本地通信

SOCK_STREAM 是有保障的(即能保证数据正确传送到对方)面向连接的SOCKET,多用于资料(如文件)传送。

SOCK_DGRAM 是无保障的面向消息的socket , 主要用于在网络上发广播信息。

SOCK_STREAM是基于TCP的,数据传输比较有保障。
SOCK_DGRAM是基于UDP的,专门用于局域网,基于广播

SOCK_STREAM 是数据流,一般是tcp/ip协议的编程
SOCK_DGRAM分是数据包,是udp协议网络编程
在这里插入图片描述
大概了解这些以后,我们设置端口复用。那什么是端口复用呢,太深还需要看大佬文章,我可以浅显谈一下自己的,通俗点说,如果服务端结束程序了,但是端口还占用着,如果设置端口复用了下次方便客户端访问(这块不知道对不对,欢迎大佬进行斧正)
然后就是绑定访问的ip和端口了呀,IP是空的就好,说明关于服务器任意一个ip都可以访问,端口随意设置,别用特殊端口和超了就行!监听也一样在这里插入图片描述
Tcp之间有一个三次握手,想要了解可以点击三次握手
写道这里,我们就已经建立好套接字了,就等待客户端访问了!

循环接受客户端请求

# 返回一个元组,第一个是新的套接字,第二个是ip和端口,其他的可以忽略
new_socket, ip_port = tcp_server_socket.accept()  

在这里插入图片描述

这样我们就获得了一个新的套接字,传输数据的套接字了,之前的的套接字是建立连接的!
接下来我们服务端就要接受数据了!
为了我们方便观察谁连接了服务端,所以我们把ip和端口给显现出来
在这里插入图片描述

数据传输!!!

recv_data = new_socket.recv(4096)

4096是要接受的数据大小
但是啊,万一客户端和服务端连接上了,但是没有传输数据,那么程序是不是就报错了(不信可以自己尝试一下)所以我们要加个if语句,保证有传输的数据,不然就关闭我们的套接字
在这里插入图片描述
接下来就要注意了,因为计算机间传输数据都是以二进制传输数据,所以接受过来的数据要进行解码
如果不解码就会出现以下这种情况
在这里插入图片描述
传输过来的数据很麻烦,我们要得到什么,要得到路径,请求路径,请求那个静态资源的路径,所以我们除了路径那个信息,我们什么都不要,所以我们用切片来得到路径
在这里插入图片描述
有了路径,客户端才能拿到想要的静态资源
所以接下来的代码就是一系列打开文件路径的语法,就不过多赘述了!

        try:
            with open('static' + recv_path, "rb") as file:
                file_data = file.read()
        except Exception as e:
            # 代码如果执行到了这里,说明没有这个静态文件所以要返回404界面

            # 一定要注意响应行
            #         响应头         他们的后面都要有一个\r\n
            #         空行            !!!!
            #         响应体           !!!!
            response_line = 'HTTP/1.1 404 Not Found\r\n'
            response_header = "Server: py/1.0\r\n"
            with open('static/error.html', "rb") as file:
                file_data = file.read()
            '''
            有了文件开始响应,发送http数据包
            http数据包括什么呢?
            响应行
            响应头
            空行
            响应体
            '''
            # 响应体
            response_body = file_data

            # 接下来进行http数据的封装
            response = (response_line + response_header+'\r\n').encode("utf-8") + response_body
            # 封装好了就要发送给客户端浏览器
            new_socket.send(response)
        else:
            # 响应行
            response_line = 'HTTP/1.1 200 OK\r\n'
            # 响应头
            response_header = "Server: py/1.0\r\n"
            # 响应体
            response_body = file_data
            # 进行封装
            response = (response_line + response_header+'\r\n').encode("utf-8") + response_body
            new_socket.send(response)
        finally:
            new_socket.close()

其中要注意的是,数据传输遵循http协议,要有响应报文,所以我们要吧数据进行一个封装,封装成响应报文发给客户端,然后有不会的可以 F12 分享一波百度,就知道要封装什么进去了
响应中要有的是:响应行,响应头,空行,响应体
记得每个响应行,响应头,空行,响应体后面都要有\r\n
响应行\r\n
响应头\r\n
空行\r\n
响应体\r\n
这样才是一个正确的响应报文格式
然后别忘了,因为计算机之间是进行二进制传输的,所有str字符类型的东西,我们要进行编码,然后吧所有数据糅合在一起形成响应报文,然后发送给客户端。

最后总结和代码

完整代码如下:

import socket
import os
import threading


def main():
    # 创建服务端TCP套接字
    tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # 设置端口复用,结束运行释放端口
    tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    # 绑定端口号
    tcp_server_socket.bind(('', 9000))
    # 设置监听,通常都是128
    tcp_server_socket.listen(128)
    # 循环接受客户端请求
    while True:
        new_socket, ip_port = tcp_server_socket.accept()  # 返回一个元组,第一个是新的套接字,第二个是ip和端口
        print(f'连接成功新的套接字是:{new_socket}\nip端口是{ip_port}')
        # 成功建立连接,接下来进行数据的传输
        recv_data = new_socket.recv(4096)
        if len(recv_data) == 0:
            new_socket.close()
            return
        # 因为计算机之间通信是二进制数据,所以就需要编码和解码
        recv_content = recv_data.decode("UTF-8")
        # 对传输过来的数据进行切片以获得请求路径
        recv_list = recv_content.split(" ", maxsplit=2)
        recv_path = recv_list[1]
        print(recv_path)
        if recv_path == '/':
            recv_path = '/index.html'

        try:
            with open('static' + recv_path, "rb") as file:
                file_data = file.read()
        except Exception as e:
            # 代码如果执行到了这里,说明没有这个静态文件所以要返回404界面

            # 一定要注意响应行
            #         响应头         他们的后面都要有一个\r\n
            #         空行            !!!!
            #         响应体           !!!!
            response_line = 'HTTP/1.1 404 Not Found\r\n'
            response_header = "Server: py/1.0\r\n"
            with open('static/error.html', "rb") as file:
                file_data = file.read()
            '''
            有了文件开始响应,发送http数据包
            http数据包括什么呢?
            响应行
            响应头
            空行
            响应体
            '''
            # 响应体
            response_body = file_data

            # 接下来进行http数据的封装
            response = (response_line + response_header+'\r\n').encode("utf-8") + response_body
            # 封装好了就要发送给客户端浏览器
            new_socket.send(response)
        else:
            # 响应行
            response_line = 'HTTP/1.1 200 OK\r\n'
            # 响应头
            response_header = "Server: py/1.0\r\n"
            # 响应体
            response_body = file_data
            # 进行封装
            response = (response_line + response_header+'\r\n').encode("utf-8") + response_body
            new_socket.send(response)
        finally:
            new_socket.close()


if __name__ == '__main__':
    main()

总体来说,其实并不难,要是简单的进行通信,基本语法记住了就可以实现我们自己和自己玩了。
然后如果想动手尝试一下的话,我吧源代码进行了一个打包,就放在下面了

链接:https://pan.baidu.com/s/1U7ih4Jp5lgAQuQYMCHb7nw
提取码:2rrp
复制这段内容后打开百度网盘手机App,操作更方便哦

如果觉得我写的还可以的话,点赞评论关注,你的支持就是我坚持写下去的最大动力!!!

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 16
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值