ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python socket套接字编程

2022-01-12 21:31:07  阅读:195  来源: 互联网

标签:socket Python recv client 报头 import 接字 data


Python socket套接字编程

  • socket套接字编程
  • 简易代码
  • 通信循环及代码优化
  • 黏包现象
  • struct模块
  • 建议版本报头
  • 上传文件数据
  • 扩展知识

 

一、socket套接字编程

  要求:我们自己想写一款可以数据交互的程序

  只要涉及到远程数据交互必须要操作OSI七层,所以有现成的模块直接实现

  socket模块

  架构启动要先启动服务端再启动客户端

 

二、简易代码

import socket
"""
导入模块的两种方式
    import句式
    from...import...句式
第三方模块下载
    pip3 install 模块名==版本号 -i 仓库地址
"""
server = socket.socket()  # 默认就是基于网络的TCP传输协议   买手机
server.bind(('127.0.0.1', 8080))  # 绑定ip和port         插电话卡
server.listen(5)  # 半连接池            开机(过渡)
sock, address = server.accept()  # 监听   三次握手的listen态
print(address)  # 客户端地址
data = sock.recv(1024)  # 接收客户端发送的消息  听别人说话
print(data)
sock.send(b'hello my big baby~~~')  # 给别人回话
sock.close()  # 挂电话
server.close()  # 关机


import socket
client = socket.socket()  # 买手机
client.connect(('127.0.0.1', 8080))  # 拨号
# 说话
client.send(b'hello big DSB DSB DSB!')
# 听他说
data = client.recv(1024)
print(data)
client.close()

 

三、通信循环及代码优化

  1.客户端校验信息不能为空

  2.服务端添加兼容性代码(mac linux)

  3.服务端重启频繁报端口占用错误

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

  4.客户端异常关闭,服务端报错的问题

    异常捕获

  5.服务端链接循环

  6.半连接池

    设置可以等待的客户端数量

 

四、黏包现象

  数据管道的数据没有被完全取出

  TCP协议有一个特性

    当数据量比较小且时间间隔比较短的多次数据

    TCP会自动打包成一个数据包发送

  报头

    能够标识即将到来的数据具体信息

      eg:数据量大

    报头的长度必须是固定的

 

五、struct模块

import struct
import json


d = {
    'file_name': '很好看.mv',
    'file_size': 1231283912839123123424234234234234234324324912,
    'file_desc': '拍摄的很有心 真的很好看!!!',
    'file_desc2': '拍摄的很有心 真的很好看!!!'
}
d = json.dumps(d)
res = struct.pack('i',len(d))
print(len(res))
res1 = struct.unpack('i',res)[0]
print(res1)

 

六、简易版本报头

import socket
import subprocess
import json
import struct

server = socket.socket()
server.bind(('127.0.0.1', 8080))
server.listen(5)

while True:
    sock, address = server.accept()
    while True:
        data = sock.recv(1024)  # 接收cmd命令
        command_cmd = data.decode('utf8')
        sub = subprocess.Popen(command_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        res = sub.stdout.read() + sub.stderr.read()  # 结果可能很大
        # 1.制作报头
        data_first = struct.pack('i', len(res))
        # 2.发送报头
        sock.send(data_first)
        # 3.发送真实数据
        sock.send(res)
     
import socket
import struct

client = socket.socket()  # 买手机
client.connect(('127.0.0.1', 8080))  # 拨号

while True:
    msg = input('请输入cmd命令>>>:').strip()
    if len(msg) == 0:
        continue
    client.send(msg.encode('utf8'))
    # 1.先接收固定长度为4的报头数据
    recv_first = client.recv(4)
    # 2.解析报头
    real_length = struct.unpack('i',recv_first)[0]
    # 3.接收真实数据
    real_data = client.recv(real_length)
    print(real_data.decode('gbk'))

 

七、上传文件数据

import json
import socket
import struct
import os

client = socket.socket()  # 买手机
client.connect(('127.0.0.1', 8080))  # 拨号

while True:
    data_path = r'D:\金牌班级相关资料\网络并发day01\视频'
    # print(os.listdir(data_path))  # [文件名称1 文件名称2 ]
    movie_name_list = os.listdir(data_path)
    for i, j in enumerate(movie_name_list, 1):
        print(i, j)
    choice = input('请选择您想要上传的电影编号>>>:').strip()
    if choice.isdigit():
        choice = int(choice)
        if choice in range(1, len(movie_name_list) + 1):
            # 获取文件名称
            movie_name = movie_name_list[choice - 1]
            # 拼接文件绝对路径
            movie_path = os.path.join(data_path, movie_name)
            # 1.定义一个字典数据
            data_dict = {
                'file_name': 'XXX老师合集.mp4',
                'desc': '这是非常重要的数据',
                'size': os.path.getsize(movie_path),
                'info': '下午挺困的,可以提神醒脑'
            }
            data_json = json.dumps(data_dict)
            # 2.制作字典报头
            data_first = struct.pack('i', len(data_json))
            # 3.发送字典报头
            client.send(data_first)
            # 4.发送字典
            client.send(data_json.encode('utf8'))
            # 5.发送真实数据
            with open(movie_path,'rb') as f:
                for line in f:
                    client.send(line)
                    
                    
# 1.先接收固定长度为4的字典报头数据
        recv_first = sock.recv(4)
        # 2.解析字典报头
        dict_length = struct.unpack('i', recv_first)[0]
        # 3.接收字典数据
        real_data = sock.recv(dict_length)
        # 4.解析字典(json格式的bytes数据 loads方法会自动先解码 后反序列化)
        real_dict = json.loads(real_data)
        # 5.获取字典中的各项数据
        data_length = real_dict.get('size')
        file_name = real_dict.get("file_name")

        recv_size = 0
        with open(file_name,'wb') as f:
            while recv_size < data_length:
                data = sock.recv(1024)
                recv_size += len(data)
                f.write(data)

 

八、扩展知识

在阅读源码的时候
    1.变量名后面跟冒号 表示的意思是该变量名需要指代的数据类型
    2.函数后更横杆加大于号表示的意思是该函数的返回值类型

 

标签:socket,Python,recv,client,报头,import,接字,data
来源: https://www.cnblogs.com/balzac/p/15795400.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有