传输层/应用层/scoket套接字


目录

传输层

一、PORT协议

二、TCP协议与UDP协议

​ 规定了数据传输所遵循的规则

​ ps:数据传输能够遵循的协议有很多 TCP和UDP是较为常见的两个

1.TCP协议

三次握手:

​ 建立双向通道

​ ps:洪水攻击:同时让大量客户端朝服务端发生建立TCP连接的请求

image

四次挥手:

​ 断开双向通道

​ 中间两步不能合并(需要检查时间)

image

基于TCP传输数据非常安全,有为有双向通道

基于TCP传输数据,数据不容易丢失!!!原因是:有二次确认机制

每次发送数据都需要返回确认消息,否则在一定时间内会反复发送

2.UDP协议

​ 基于UDP协议发送数据,没有任何的通道也没有任何的限制

​ UDP发送数据没有TCP安全(没有二次确认机制)

三、TCP和UDP的区别

协议 TCP UDP
特点 类似于打电话,有来有往,有二次确认机制,很安全,不易丢失数据 类似于发短信,只发不管是否接受到,也不管有无回复,没有二次确认机制,容易丢失数据

应用层

取决于程序员自己采用什么策略和协议

常见协议有:HTTP、HTTPS、FTP…

scoket套接字

一、套接字家族

1.基于文件类型的套接字家族

名字:AF_UNIX

2.基于网络类型的套接字家族

名字:AF_INEF

二、代码演示

1.服务端

import socket

# 1.创建一个socket对象
sever = socket.socket()
# 括号里什么都不写,默认是基于网络的TCP套接字

# 2.绑定一个固定的地址
sever.bind(('127.0.0.1', 8800))
# 127.0.0.1本地回环地址(只允许自己的机器访问)

# 3.半连接池
sever.listen(5)

# 4.开业 等待客户
sock, addr = sever.accept()
print(sock, addr)
# sock是双向通道,addr是客户端地址

# 5.数据交互
sock.send(b'aaa')  # 朝客户端发送数据
data = sock.recv(1024)  # 接收客户端发送的数据 1024bytes
print(data)

# 6.断开连接
sock.close()  # 断链接
sever.close()  # 关机

2.客户端

import socket

# 1.产生一个socket对象
client = socket.socket()

# 2.连接服务器(拼接服务端的IP和port)
client.connect(('127.0.0.1', 8800))

# 3.数据交互
data = client.recv(1024)  # 接收服务端发送的数据
print(data)
client.send(b'ssss')  # 朝服务端发送数据

# 4.关闭
client.close()

三、代码优化

1.send 和 recv

​ 客户端不能同时执行同一个

​ 有一个收,另外一个就是发

​ 不能同时收和同时发!!

2.信息自定义

input获取用户数据(需要编码解码)

3.循环通信

给数据交互环节添加循环即可

4.服务端能够持续提供服务

需求:不会因为客户端断开连接而报错

方法:异常捕获 一旦客户断开连接,服务端结束通信循环,调到连接处等待

5.消息不能为空

判断是否为空 如果是则重新输入(主要针对客户端)

6.服务端频繁重启可能会报错:端口被占用(主要针对mac电脑)

解决方法:

from socket import SOL_SOCKET,SO_REUSEADDR
server.aetsockopt(SOL_SOCKET,SO_REUSEADDR,1)
# 加在bind前面

7.客户端异常退出会发送空消息(针对mac、Linux)

针对接收的信息加判断处理即可

四、半连接池

sever.listen(5)
# 主要为了做缓冲,避免太多的无效等待

五、粘包问题

1.服务端代码
	sock.revc(1024)
	sock.revc(1024)
	sock.revc(1024)
2.客户端代码
	client.send(b'jason')
    client.send(b'kevin')
    client.send(b'toney')

1.TCP特性

流式协议:所有的数据类似于流水,连接在一起

ps:数据量很小,并且时间间隔很多,那么就会自动组织到一起

2.recv

我们不知道即将要接受的数据量多大,如果知道的话就不会产生粘包

3.struct打包和解压

import struct

info = 'something to send'
print(len(info))  # 17 数据原本的长度
res = struct.pack('i', len(info))  # 将数据原本的长度打包
print(len(res))  # 打包之后的长度是4
ret = struct.unpack('i', res)  # 将打包之后固定长度为4的数据拆包
print(ret[0])  # 13 又得到了原本数据的长度

特点:

struct模块无论数据长度是多少,都可以打包成固定长度。

‘i’模式:固定长度4

然后基于该固定长度,还可以反向解压出真实长度

struct模块针对数据量特别大的数字没法打包

思路:

发送:
	1.先将真实数据的长度制作成固定长度 4
	2.先发送固定长度的报头
	3.在发送真实数据
接收:
	1.现接受固定长度的报头
	2.再根据报头解压出真实长度
	3.根据真实长度接收
关于数据量:
	可以分行传输

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/279108.html

(0)
上一篇 2022年8月5日
下一篇 2022年8月5日

相关推荐

发表回复

登录后才能评论