python之网络编程

python之网络编程

一、网络开发架构

1.1、C/S架构:

常见的:QQ、微信

  • 优点:

    • 可以离线使用/功能更完善/安全性更高
  • client 客户端

    • 我们需要安装的
  • server端

    • 在服务器

1.2、B/S架构:

  • 优点:
    • 不用安装就可以使用
    • 统一PC端用户的入口

常见的:百度、博客园、谷歌

  • B:browser 浏览器
  • S:server 服务端

1.3、C/S架构和B/S架构有什么关系?

B/S架构也是C/S架构中的一种

二、网络编程之socket(抽象层)

​ Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口。在设计模式中,Socket其实就是一个门面模式,它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说,一组简单的接口就是全部,让Socket去组织数据,以符合指定的协议。

三、什么是粘包

须知:只有TCP有粘包现象,UDP永远不会粘包,为何,且听我娓娓道来

首先需要掌握一个socket收发消息的原理(实际上是跟自己打交道,自己先去自己的缓存找数据)

  • 两种会出现粘包的原因

    • tcp是流式协议,数据像水流一样连在一起,没有分界
    • 收数据没收干净,有残留,就会跟下次结果混在一起
  • 解决的核心法则

    • 每次都收干净,别有残留

    • 1、拿到数据的总大小 total_size
      2、循环接受,每次接收一次,recv_size+=接收的长度
      3、直到recv_size=total_size,结束循环cpp
      

服务端代码:

import subprocess
import struct
import json
from socket import *

server = socket(AF_INET,SOCK_STREAM)
server.bind(('112.74.113.107',22))
server.listen()

#服务端做2件事
# 1、循环从半连接池取数据、且建立双向链接,拿到链接对象(conn)
while True:
    conn,client_addr = server.accept()
    # 2、拿到链接对象,与其通信循环
    while True:
        try:
            cmd = conn.recv(1024)
            if len(cmd) == 0:
                break
            obj = subprocess.Popen(cmd.decode('utf-8'),
                             shell=True,
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE
                             )
            stdout_res = obj.stdout.read()  #bash 类型
            stderr_res = obj.stderr.read()

            #数据总大小
            total_size = len(stdout_res) + len(stderr_res)

            # 1、制作头
            header_dic = {
                "filename":"a.txt",
                "total_size":total_size,
                "md5":"xxxxxxxx"
            }

            json_str = json.dumps(header_dic)
            json_str_bytes = json_str.encode("utf-8")

            # 2、先发固定长度的bbytes:对数据描述信息 pack打包 i --> 4个字节大小
            xxxx = struct.pack('i',len(json_str_bytes))
            conn.send(xxxx)

            # 3、发头信息
            conn.send(json_str_bytes)

            # 4、再发真实的数据
            conn.send(stdout_res)
            conn.send(stderr_res)

            #不建议这样写
            #conn.send(stdout_res+stderr_res)
            #文件的写法
            # with open("xx.mp4",mode='rb') as f:
            #     for line in f:
            #         conn.send(line)

            # print(cmd.decode('utf-8'))
            # print(client_addr)
        except Exception:
            break
    conn.close()

客户端代码:

import json
import struct
from socket import *

client = socket(AF_INET,SOCK_STREAM)
client.connect(('112.74.113.107',22))

while True:
    msg = input('请输入命令').strip()
    if len(msg) == 0:
        continue
    client.send(msg.encode('utf-8'))

    #解决粘包的问题思路:
    # 一、收固定长度的头:解析出数据的描述信息,拿到数据的总大小
        # 1、拿到头信息
    xxxx = client.recv(4)
    header_len = struct.unpack('i',xxxx)[0]
        # 2、接收头,且解析
    json_str_bytes = client.recv(header_len)
    json_str = json_str_bytes.decode('utf_8')
    header_dic = json.loads(json_str)
    print(header_dic)
    total_size = header_dic["total_size"]


    # 二、根据解析出的头描述信息,接受真实数据
        # 2、循环接受,每次接收一次,recv_size+=接收的长度
        # 3、直到recv_size=total_size,结束循环
    recv_size = 0
    while recv_size < total_size:
        recv_data = client.recv(1024)
        recv_size += len(recv_data)
        print(recv_data.decode('gbk'),end='')
    else:
        print()
    # cmd_res = client.recv(1024)
    # print(cmd_res.decode('gbk'))
posted @ 2020-10-06 16:02  taotaozh  阅读(179)  评论(0编辑  收藏  举报