CSIC_716_20191203【 socket网络编程,以及沾包问题的高级解决方式】

  • AF_UNIX(本机通信)
  • AF_INET(TCP/IP – IPv4)
  • AF_INET6(TCP/IP – IPv6)
  • SOCK_STREAM(TCP流)
  • SOCK_DGRAM(UDP数据报)

远程操作服务端的命令行。

解决沾包问题的方法:   以远程连接服务端的命令行为例子。

server服务端

# _*_ coding: gbk _*_
# @Author: Wonder
import socket
import json
import subprocess
import struct  # 将数字类型变成固定长度,
from socket import SOL_SOCKET, SO_REUSEADDR

sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sk.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)  # 重用地址

sk.bind(('127.0.0.1', 9900))  # 绑定地址和端口号   ,这里ip和端口组成一个元组
sk.listen(5)  # 启动监听,允许最大连接数量为3
while True:
    sock, addr = sk.accept()  # 三次握手建立的管道,支持多个客户端client进行连接
    while True:
        try:
            bin_cmd = sock.recv(1024)  # 二进制, 接收二进制的cmd
            cmd = bin_cmd.decode('utf-8')  # 转成真是的cmd
            sub_obj = subprocess.Popen(cmd, shell=True,
                                       stdout=subprocess.PIPE,
                                       stderr=subprocess.PIPE)  # 操作本机cmd
            stdout = sub_obj.stdout.read()  # 系统生成的二进制,windows环境下是gbk编码格式,Linux下是utf-8格式。
            stderr = sub_obj.stderr.read()
            '''
            高级版本在于改造报头
            '''
            head_content = {
                'filename': 'kazami.txt',
                'secreatkey': 123456,
                'header': len(stdout) + len(stderr)
            }
            head_text = json.dumps(head_content).encode('utf-8')  # 序列化之后进行编码

            sock.send(struct.pack('i', len(head_text)))  # 发报头长度
            sock.send(head_text)  # 发报头

            sock.send(stdout)
            sock.send(stderr)
            # sock.send(str2.encode('utf-8'))
        except ConnectionResetError:  # 当判断client断开连接后,跳出循环
            break

    sock.close()

sk.close()

  

client  客户端

# _*_ coding: gbk _*_
# @Author: Wonder
import socket
import struct
import json

sk = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 和 Internet中的通信,流格式。
sk.connect(('127.0.0.1', 9900))  # 连接到服务端的绑定地址
while True:
    cmd = input('>>>').strip()
    if not cmd:
        continue
    sk.send(cmd.encode('utf-8'))  # 必须要发送二进制的数据。
    res1 = sk.recv(4)  #取报头长度
    text_text_len = struct.unpack('i', res1)[0]  # 获取报头的真实长度
    bin_head_text = sk.recv(text_text_len)  # 读取报头内容
    head_text =json.loads(bin_head_text.decode('utf-8'))

    print(head_text)

    data_size = head_text.get('header')  # 真实内容长度

    res_byt = b''
    real_size = 0
    while real_size < data_size:    #当真实拼接的长度小于数据长度时,不断拼接,直到完整数据拼出来。
        res = sk.recv(4444)     # 最大为缓存,过大没有意义。
        res_byt += res
        real_size += len(res)
    print(res_byt.decode('gbk'))
    print(real_size)
sk.close()

  

原文地址:https://www.cnblogs.com/csic716/p/11980443.html