哔哩哔哩白羽黑月老师课程:socket的学习与感悟——在此作篇,以便以后翻阅

1.什么是socket?

引子: 

不管是传统计算机软件,还是手机软件,还是物联网嵌入系统软件,这些都要和其他网络系统进行通讯。

而当今网络世界 基本上 都是使用TCP/IP协议进行通讯的。

任何应用,比如 浏览网页、微信、支付宝、抖音 或者我们开发的 等等都是 通过TCP/IP协议进行通讯的。

TCP/IP 协议 就是一种传输 数据的 方案。

我们可以举个简单的例子:

例如:新疆的安夏想要给北京的girlfriend邮寄生日礼物

作为收件人:

girlfriend在接收快递时,不需要具体的细节的,只需要货到了,签收即可啦。

作为寄件人:

安夏也不需要去知道快递公司如何将快递发给girlfriend的,他只需要知道把快递交给快递公司,

快递公司就可以把快递送到girlfriend手中就行啦!

对应到软件开发上:

收发信息的 程序进程 就像 发件人 和 收件人

收发的 信息 就像 快递传输的 物品

具体信息的传输路径(中间经过哪些路由器)和传输的方法(使用什么协议)就像 快递公司的运输流程;

同样的,我们编写 发出信息的程序和接收信息的程序,并不需要知道 信息传输的所有细节,比如 中间经过哪些路由器,路由器之间又是如何传输的。

socket编程引入核心:

我们作为程序员,只要知道,我们的程序如何把 所要发送的信息 交给 快递公司取件人 , 如何从 快递公司送件人 手中获取信息。

那么 和我们的 应用程序 直接打交道的 快递公司取件人快递公司送件人 到底是什么? 就是操作系统 提供的 socket 编程接口

原理图:

通俗讲:操作系统提供的socket编程接口就相当于这个快递公司的指挥官啦!

(理解:

在python中他是一个第三方库,(也可以自己写,缺点是有些许麻烦),现在的我们站在巨人的肩

膀上,可以直接调用前人写的第三方Python库,只需要理解怎么调用第三方库中的函数即可。

)

发送信息的应用程序,通过 socket 编程接口 把信息给操作系统的TCP/IP协议栈通讯模块;

通讯模块一层层传递给 其他通讯模块(网卡驱动等),最后再通过网卡等硬件设备发送到网络上去;

经过 网络上路由器的一次次转发,最终到了 目的程序 所在的 计算机(或者手机等设备) , 再通过 其 操作系统的 TCP/IP协议栈通讯模块 一层层上传。

最后接收信息的程序,通过 socket 编程接口 接收到了 传输的信息。

我们可以根据上述原理图进行抽象理解。

2.TCP Socket编程

要进行socket编程,发送网络消息,我们可以使用 Python 内置的 socket 库 。

目前的socket编程,使用的最多的就是通过TCP协议进行网络通讯的。

TCP进行通讯的程序双方,分为服务端和客户端。

TCP 协议进行通讯的双方,是需要先建立一个虚拟连接的。然后双方程序才能发送业务数据信息。

建立TCP虚拟连接是通过著名的 三次握手 进行的。

具体三次握手的细节大家可以参考这篇文章 https://zhuanlan.zhihu.com/p/40499563

三次握手简单理解:

tcp的三次握手

1) 请求端(通常称为客户)发送一个 SYN 段指明客户打算连接的服务器的端口, 以及初 始序号(ISN,在这个例子中为1415531521)。这个SYN段为报文段1。

2) 服务器发回包含服务器的初始序号的 SYN报文段(报文段2)作为应答。同时,将确认 序号设置为客户的ISN加1以对客户的SYN报文段进行确认。一个SYN将占用一个序号。

3) 客户必须将确认序号设置为服务器的 ISN 加1以对服务器的 SYN 报文段进行确认(报文 段3)。 这三个报文段完成连接的建立。这个过程也称为三次握手( three-way handshake)。

摘自:https://zhuanlan.zhihu.com/p/40499563

三次握手个人理解总结:类似微信验证码填写:

你用一台新设备填写密码登录微信,就是你向服务器发送请求,这是第一次握手,(主动,你向服务器发送:我需要帮助)

服务器说,要再次验证身份,请让好友辅助验证,就是服务器做出的应答,这是第二次握手(被动,服务器来满足你的要求)

好友辅助验证成功,就是客户,也就是你让好友成功帮助你进行了辅助验证,让服务器确认了你的身份,这就是上述你对服务器进行的报文确认,也就是第三次握手(你向服务器验证了自己的身份,为啥子?这个时代嘛,防诈骗吖)

我们现在来看一个 TCP协议进行通讯的 socket 服务端程序和客户端程序。

下面是TCP 服务端程序 server.py

#  === TCP 服务端程序 server.py ===

# 导入socket 库
from socket import *

# 主机地址为空字符串,表示绑定本机所有网络接口ip地址
# 等待客户端来连接
IP = ''
# 放个空的箱子(这里不是引号嘛?所以是个装字符串的空箱子)存客户的IP
# 端口号
PORT = 50000
# 定义一次从socket缓冲区最多读入512个字节数据
BUFLEN = 512

# 实例化一个socket对象
# 参数 AF_INET 表示该socket网络层使用IP协议
# 参数 SOCK_STREAM 表示该socket传输层使用TCP协议
listenSocket = socket(AF_INET, SOCK_STREAM)

# socket绑定地址和端口
listenSocket.bind((IP, PORT))


# 使socket处于监听状态,等待客户端的连接请求
# 参数 8 表示 最多接受多少个等待连接的客户端
listenSocket.listen(8)
print(f'服务端启动成功,在{PORT}端口等待客户端连接...')  #屏幕提示语,报告成功了

dataSocket, addr = listenSocket.accept()
#  将客户端发送的信息,和客户的地址分别赋值给dataSocket,addr
print('接受一个客户端连接:', addr) #打印customer的地址

while True: #(循环,不断尝试去读取客户发送的消息)
    # 尝试读取对方发送的消息
    # BUFLEN 指定从接收缓冲里最多读取多少字节
    recved = dataSocket.recv(BUFLEN)
    # 上述我们定义了,一次最多可以读入512个字节

    # 如果返回空bytes,表示对方关闭了连接
    # 退出循环,结束消息收发
    if not recved:
        break
    # 拓:
    # decode:解码缩写,还是调用的python库,帮咱们翻译数据
    # encode:编码缩写,同理

    # 读取的字节数据是bytes类型,需要解码为字符串
    info = recved.decode() #将bytes类型的数据解码为字符串
    #bytes类型的咱不好读
    print(f'收到对方信息: {info}') #打印解码的字符串,以至于可以获取对方信息

    # 发送的数据类型必须是bytes,所以要编码
    dataSocket.send(f'服务端接收到了信息 {info}'.encode())
    # 咱们发送的数据有可能被五马分尸啦,把数据编码成bytes类型
    # 分批发送给客户

# 服务端也调用close()关闭socket
dataSocket.close() #客户数据收集集合关闭
listenSocket.close() #监听关闭,相当于古代负责传话的太监

下面是TCP 客户端程序 client.py

#  === TCP 客户端程序 client.py ===
# 和服务器基本一样

from socket import *

IP = '127.0.0.1'  # 设定客户的IP
SERVER_PORT = 50000 # 设定客户的端口
BUFLEN = 512 # 设定客户的每次最大接收字节数

# 实例化一个socket对象,指明协议
dataSocket = socket(AF_INET, SOCK_STREAM)

# 连接服务端socket
dataSocket.connect((IP, SERVER_PORT))

while True:
    # 从终端读入用户输入的字符串
    toSend = input('>>> ')
    if  toSend =='exit':
        break
    # 发送消息,也要编码为 bytes
    dataSocket.send(toSend.encode())

    # 等待接收服务端的消息
    recved = dataSocket.recv(BUFLEN)
    # 如果返回空bytes,表示对方关闭了连接
    if not recved:
        break
    # 打印读取的信息
    print(recved.decode())

dataSocket.close()

3.应用消息格式:

为什么要定义应用消息格式

为啥要使用bytes格式转换?

答:TCP协议要求,也就是游戏规则,你不遵循他不和你玩的。

上面的例子中,我们发送的消息就是要传递的内容。 比如字符串 你好,我是白月黑羽

实际上,我们在企业中开发的程序通讯,消息往往是有 格式定义 的。 消息的格式定义可以归入 OSI网络模型的 表示层

比如: 定义的消息包括 消息头 和 消息体。

消息头存放消息的格式数据, 比如 消息的长度、类型、状态等等, 而消息体存放具体的传送数据。

对于使用TCP协议传输信息的程序来说,格式定义一定要明确规定 消息的边界

因为 TCP协议传输的是 字节流(bytes stream), 如果消息中没有指定 边界 或者 长度,接收方就不知道一个完整的消息从字节流的 哪里开始,到 哪里结束。

指定消息的边界有两种方式:

  • 用特殊字节作为消息的结尾符号

可以用消息内容中不可能出现的字节串 (比如 FFFFFF) 作为消息的结尾字符。

  • 在消息开头某个位置,直接指定消息的长度

比如在一个消息的最前面用2个字节表示本消息的长度。

说人话就是:TCP的消息会一节一节的,UDP的消息确保完整好才会给你

TCP不需要确定消息的完整性,他收到多少就给你多少 ,那假如信息缺失了呢?

没关系,再补发一份不就行啦

优点:数据传输快,缺点:可能会丢数据

应用领域:短视频播放上,

为啥子?

你想哇,刷个短视频,客户要的是流畅度,数据传送快一些,可以避免视频卡

卡顿,如果采用UDP,视频卡成了PPT,那谁还追剧刷手机哇!

UDP:沉稳的大哥

接受到完整数据后,把完整数据交付给你

优点:数据传送完整,缺点:速度相交于TCP慢一些

用它刷视频,他直接给你卡成PPT

偷笑...

  • 31
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值