网络编程扩展

Day38网络编程扩展

1、传输层

PORT协议

TCP协议 与UDP协议
规定了数据传输所遵循的规则
数据传输能够遵循的协议有很多 TCP和UDP只是比较常见的两个

1.1、TCP协议

三次握手:建立双向通道
洪水攻击:就是同时让大量的客户端朝服务端发送建立TCP连接请求

在这里插入图片描述

四次挥手:断开双向通道,中间两部不能合并(需要检查的时间停顿,检查是否还有数据没有发送完)

在这里插入图片描述

基于TCP传输非常安全 因为有双向通道

  • 基于TCP传输数据,数据容易丢失!,不容易丢失的原因在于二次确认机制
  • 每次发送数据都需要返回确认消息 否则在一定时间就会反复发送

TCP类似于打电话:你一句 我一句 有来有往
UDP 类似于发短信:只要发送了 不管别人看没看到也不管回不回复

2、应用层

主要取决于程序员自己采用什么策略与协议
常见的协议有:HTTP HTTPS FTP

3、socket 套接字

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

  • 套接字家族的名字:AF_UNIX

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

  • 套接字家族的名字:AF_INET

服务端

import socket

# 创建一个socket 对象
server = socket.socket()
# 绑定一个固定的地址(ip\port)
# 127.0.0.1 为本地回环地址(只允许自己的机器访问)
server.bind(('127.0.0.1', 8080))
# 半连接池(暂且忽略)
server.listen(5)
# 准备就绪 等待客户端 来访问(开业,等待接客)
sock, address = server.accept()
# sock 是双向通道 address是客户端地址
print(sock, address)
# 数据交互
# 朝客户端发送数据
sock.send(b'hell big sb')
# 接收 客户端发送的数据 1024bytes
data = sock.recv(1024)

print(data)
#
# 断开连接
sock.close()

客户端

import socket
# 产生一个socke对象
client = socket.socket()
#连接服务器 (拼接服务端的IP和port)
client.connect(('127.0.0.1',8080))
#数据交互
#接收服务端 发送的数据
data = client.recv(1024)
#打印
print(data)
# 朝服务端发送数据
client.send(b'hello small sb')
# 关闭
client.close()

3.1、代码优化

消息自定义
利用 input 接收用户数据

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

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

服务端能够持续提高服务
不会因为客户端 断开连接而报错
异常捕获 一旦客户端断开连接 服务端结束通信循环 遇到连接处等待

服务端

import socket
import json

# 创建一个socket 对象
server = socket.socket()
# 绑定一个固定的地址(ip\port)
# 127.0.0.1 为本地回环地址(只允许自己的机器访问)
server.bind(('127.0.0.1', 8080))
# 半连接池(暂且忽略)
server.listen(5)
# 准备就绪 等待客户端 来访问(开业,等待接客)
#添加循环 让服务端 每次结束客户端连接接触都能回归为等待访问的状态
while True :
    sock, address = server.accept()
    # sock 是双向通道 address是客户端地址
    print(sock, address)
    # 数据交互
    # 朝客户端发送数据
    # 添加循环 让服务端 能够自定义返回的数据
    while True:
        try:
            sent_data=input('请输入发送的数据>>>').strip()
            if len(sent_data)==0:
                print('消息不能为空')
                continue
            sent_data=bytes(sent_data,'utf')
            sock.send(sent_data)
            # 接收 客户端发送的数据 1024bytes
            data = sock.recv(1024)
            data=str(data,'utf')
            print(data)
        #当客户端断开过后 捕获异常
        except Exception:
            break
#
# 断开连接
sock.close()

客户端

import socket
# 产生一个socke对象
client = socket.socket()
#连接服务器 (拼接服务端的IP和port)
client.connect(('127.0.0.1',8080))
#数据交互
#接收服务端 发送的数据
#添加循环 能够让客户端 重复的发送数据
while True:
    data = client.recv(1024)
    #打印
    data=str(data,'utf')
    print(data)
    # 朝服务端发送数据
    sent_data=input('请输入要传入的数据>>>').strip()
    sent_data=bytes(sent_data,'utf')
    client.send(sent_data)

# 关闭
client.close()

3.2、半连接池

server.listen(5) #参数 5 表示 等待访问的客户端 数 超过这个数 那么就会使那个客户端报错
主要为了做缓冲 避免太多无效等待

3.3、黏包问题

TCP特性
流逝协议:所有的数据类似于水流 连接在一起的
数据量很小 并且时间间隔很多 那么就会自动组织到一起

recv
我们不知道即将要接收的数据量很大 如果 知道的话 不会产生也不会产生黏包

通过struct

import struct

info = '你好啊 大帅比'
print(len(info))
# 将数据原本的长度打包
res = struct.pack('i', len(info))
# 打包之后的长度为4
print(len(res))
# 将打包之后 固定长度为 4的数据拆包
ret = struct.unpack('i', res)
# 又得到了原本数据的长度
print(ret[0])

struct模块 无论数据长度 是多少 都可以帮你打包成固定长度
然后基于该长度 还可以反向解析出真实长度

3.4、实操

服务端

import socket
import json

# 创建一个socket 对象
import struct

server = socket.socket()
# 绑定一个固定的地址(ip\port)
# 127.0.0.1 为本地回环地址(只允许自己的机器访问)
server.bind(('127.0.0.1', 8080))
# 半连接池(暂且忽略)
server.listen(5)
# 准备就绪 等待客户端 来访问(开业,等待接客)
# 添加循环 让服务端 每次结束客户端连接接触都能回归为等待访问的状态
while True:
    sock, address = server.accept()
    # sock 是双向通道 address是客户端地址
    print(sock, address)
    # 数据交互
    # 朝客户端发送数据
    # 添加循环 让服务端 能够自定义返回的数据
    while True:
        try:
            sent_data = input('请输入发送的数据>>>').strip()
            if len(sent_data) == 0:
                print('消息不能为空')
                continue
            # 将获取的数据 转为bytes类型
            sent_data = bytes(sent_data, 'utf')
            # 计算字节个数
            res_w = len(sent_data)
            # 然后进行打包
            res_w = struct.pack('i', res_w)
            # 将打包后的数据发送过去
            sock.send(res_w)
            # 再将真正的数据发送过去
            sock.send(sent_data)
            # 接收 客户端发送的数据
            #首先获取 打包后的 数据
            data = sock.recv(4)
            # 将打包后的数据解包获取真实数据字节数
            data = struct.unpack('i', data)[0]
            #获取真实数据
            b_data = sock.recv(data)
            #解码
            data = str(b_data, 'utf')
            # 打印
            print(data)
        # 当客户端断开过后 捕获异常
        except Exception:
            break
#
# 断开连接
sock.close()

客户端

import socket
import struct

# 产生一个socke对象
client = socket.socket()
# 连接服务器 (拼接服务端的IP和port)
client.connect(('127.0.0.1', 8080))
# 数据交互
# 接收服务端 发送的数据
# 添加循环 能够让客户端 重复的发送数据
while True:
    #获取真实数据长度打包后的数据
    res = client.recv(4)
    #数据解包获取真实的数据长度
    res_r = struct.unpack('i', res)[0]
    # 通过真实数据长度 获取真实数
    data = client.recv(res_r)
    # 打印
    #解码
    data = str(data, 'utf')
    print(data)
    # 朝服务端发送数据
    sent_data = input('请输入要传入的数据>>>').strip()
    #编码计算 数据长度
    sent_data = bytes(sent_data, 'utf')
    res_w = len(sent_data)
    #将数据长度打包
    res_w = struct.pack('i', res_w)
    # sent_res = bytes(res_w, 'utf')
    # 发送 输出长度打包后的数据
    client.send(res_w)
    #发送真实数据
    client.send(sent_data)

# 关闭
client.close()

作业

服务器

import socket
import struct
import json
import os

# 创建一个socket 对象
import struct

server = socket.socket()

# 绑定一个固定的地址 本地回环地址(ip/port)
server.bind(('127.0.0.1', 8080))
# 半连接池
server.listen(5)

while True:
    # 准备就绪 等待客户端访问阶段
    sock, address = server.accept()
    # 是双向通道 address是客户端地址
    print(sock, address)
    # 数据交互
    while True:
        try:
            picture_address = r'C:\Users\82576\Desktop\jason.mp4'
            jason_dict = {'address': picture_address,
                          'png_number': os.path.getsize(picture_address)}
            json_dict = json.dumps(jason_dict)
            b_dict = bytes(json_dict, 'utf')
            dict_bytes_number = len(b_dict)
            res_w = struct.pack('i', dict_bytes_number)
            # 发送字典报头
            sock.send(res_w)
            # 发送字典
            sock.send(b_dict)
            #发送真实数据
            with open(r'%s'%picture_address,'rb')as p_w:
                sock.send(p_w.read())

        except Exception:
            break

客户端

import socket
import struct
import json

# 产生一个socket对象
client = socket.socket()
# 连接服务器 (拼接服务端ip和port)
client.connect(('127.0.0.1', 8080))

# 获取字典的抱头
res_dict = client.recv(4)
# 解包字典报头
new_res_dict = struct.unpack('i', res_dict)[0]
# 获取真实的字典
b_jason_dict = client.recv(new_res_dict)
# 反序列化 解码
jason_dict = json.loads(b_jason_dict)
# 获取真实数据的报头
png_res = jason_dict.get('png_number')
# 获取真实数据
jason_png = client.recv(png_res)
with open('jason.mp4', 'wb')as jason_w:
    jason_w.write(jason_png)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值