Python之旅.第八章.网络编程

一、上节课复习

1 TCP(建立的是一个双向连接)三次握手建连接,四次挥手断连接

三次握手:

   c----syn=1 seq=x--->s

   s----ack=1+x syn=1 seq=y--->c

   c----ack=1+y------->s

   四次挥手:

   s------fin=1---------->c

   c------>ack=1--------->s

   c------>fin=1--------->s

   s------>ack=1--------->c

   

127.0.0.1: 本地回环地址

无论收发(sendreceive)都是和自己的操作系统直接交互,由操作系统接着调硬件将信息传到对方的操作系统。

也是基于以上原因,收发不是一一对应的。

 

2socket

   socket是位于应用层与传输层之间的一个抽象层,专门把传输层以下的协议封装成接口提供给应用层使用。应用只需要调用socket的接口或者说按照socket的标准编写程序,写出的程序自然是遵循tcp/ip协议。

 

二、粘包问题

TCP又称流式协议,有两个特性:

a 像流水一样源源不断

b 优化传输机制,用NAGLE算法,将时间间隔短的数据量少的数据攒成一波

以上两个特性导致了粘包问题

 

解决粘包问题的思路是知道发多少,然后收多少

注:如果用time.sleep解决,把这一端解决了,有可能在另一端发生粘包

 

三、解决粘包问题(基本板)

a struct模块

1)把整型数字转成bytes类型

2)转成的bytes是固定长度的

 

import struct

res=struct.pack('i',20332)   # ‘i’ --integer

print(res,len(res)) 

res2=struct.unpack('i',res)

print(res2[0])

 

b 服务端

from socket import *

import subprocess

import struct

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8080))

server.listen(5)

 

while True:

    conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)

    print(client_addr)

    while True:

        try:

            cmd=conn.recv(1024)

            obj=subprocess.Popen(cmd.decode('utf-8'),

                                 shell=True,

                                 stdout=subprocess.PIPE,

                                 stderr=subprocess.PIPE

                                 )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            # 1、制作固定长度的报头

            total_size=len(stdout) + len(stderr)

            header=struct.pack('i',total_size)

 

            # 2、发送报头

            conn.send(header)

 

            #3、发送真实的数据

            conn.send(stdout)

            conn.send(stderr)

        except ConnectionResetError:

            break

 

    conn.close()

server.close()

 

c 客服端

from socket import *

import struct

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8080))

# print(client)

 

while True:

    cmd=input('>>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

    #1、先收固定长度的报头

    header=client.recv(4)

    #2、解析报头

    total_size=struct.unpack('i',header)[0]

    print(total_size) #1025

    #3、根据报头内的信息,收取真实的数据

 

    recv_size=0

    res=b''

    while recv_size < total_size:

        recv_data=client.recv(1024)

        res+=recv_data

        recv_size+=len(recv_data)

 

    print(res.decode('gbk'))

client.close()

 

四、解决粘包问题(终极版)

a struct模块

import struct

import json

 

header_dic = {

    'total_size': 3122222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222121,

    'md5': '123svsaef123sdfasdf',

    'filename': 'a.txt'

}

 

header_json=json.dumps(header_dic)

# print(header_json,type(header_json))

header_bytes=header_json.encode('utf-8')

header_size=len(header_bytes)

 

print(header_size)

obj=struct.pack('i',header_size)

print(obj,len(obj))

 

b 服务端

from socket import *

import subprocess

import struct

import json

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8080))

server.listen(5)

 

while True:

    conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)

    print(client_addr)

    while True:

        try:

            cmd=conn.recv(1024)

            obj=subprocess.Popen(cmd.decode('utf-8'),

                                 shell=True,

                                 stdout=subprocess.PIPE,

                                 stderr=subprocess.PIPE

                                 )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            # 1、制作报头

            header_dic={

                'total_size':len(stdout) + len(stderr),

                'md5':'123svsaef123sdfasdf',

                'filename':'a.txt'

            }

            header_json = json.dumps(header_dic)

            header_bytes = header_json.encode('utf-8')

 

            # 2、先发送报头的长度

            header_size=len(header_bytes)

            conn.send(struct.pack('i',header_size))

 

            # 3、发送报头

            conn.send(header_bytes)

 

            # 4、发送真实的数据

            conn.send(stdout)

            conn.send(stderr)

        except ConnectionResetError:

            break

 

    conn.close()

server.close()

 

c 客户端

from socket import *

import struct

import json

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8080))

# print(client)

 

while True:

    cmd=input('>>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

    #1、先收报头的长度

    header_size=struct.unpack('i',client.recv(4))[0]

 

    #2、接收报头

    header_bytes=client.recv(header_size)

 

    #3、解析报头

    header_json=header_bytes.decode('utf-8')

    header_dic=json.loads(header_json)

    print(header_dic)

 

    total_size=header_dic[ 'total_size']

    # print(total_size) #1025

    #4、根据报头内的信息,收取真实的数据

 

    recv_size=0

    res=b''

    while recv_size < total_size:

        recv_data=client.recv(1024)

        res+=recv_data

        recv_size+=len(recv_data)

 

    print(res.decode('gbk'))

client.close()

 

五、远程执行命令的程序

a 客户端

from socket import *

 

client=socket(AF_INET,SOCK_STREAM)

client.connect(('127.0.0.1',8080))

# print(client)

 

while True:

    cmd=input('>>>: ').strip()

    if not cmd:continue

    client.send(cmd.encode('utf-8'))

    # print('has send')

    res=client.recv(14744)

    # print('has recv')

    print(len(res))

    print(res.decode('gbk'))

 

client.close()

 

b 服务端

from socket import *

import subprocess

 

server=socket(AF_INET,SOCK_STREAM)

server.bind(('127.0.0.1',8080))

server.listen(5)

 

while True:

    conn,client_addr=server.accept() #(连接对象,客户端的ip和端口)

    print(client_addr)

    while True:

        try:

            cmd=conn.recv(1024)

            obj=subprocess.Popen(cmd.decode('utf-8'),

                                 shell=True,

                                 stdout=subprocess.PIPE,

                                 stderr=subprocess.PIPE

                                 )

            stdout=obj.stdout.read()

            stderr=obj.stderr.read()

 

            # 先发送数据的长度

            total_size=len(stdout) + len(stderr)

            conn.send(total_size)

 

            # 发送真实的数据

            conn.send(stdout)

            conn.send(stderr)

        except ConnectionResetError:

            break

 

    conn.close()

server.close()

 

#交互式命令或是cd。。一般要在一台机器上,不推荐远程调控。如若强行要求,不要直接执行,而是要模拟执行,并将模拟结果发回。

 

猜你喜欢

转载自www.cnblogs.com/yangli0504/p/8930948.html