Python Journey. Chapter 8. Network Programming

1. Review of the previous lesson

1. TCP ( a two-way connection is established) three-way handshake to establish a connection, and four waves to disconnect

Three-way handshake:

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

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

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

   Four waves:

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

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

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

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

   

127.0.0.1: local loopback address

Regardless of sending and receiving ( send , receive ), it is directly interacting with its own operating system, and the operating system then transfers the hardware to transmit the information to the other party's operating system.

Also based on the above reasons, there is no one-to-one correspondence between sending and receiving.

 

2socket

   Socket is an abstraction layer between the application layer and the transport layer, which specifically encapsulates the protocol below the transport layer into an interface for the application layer to use. The application only needs to call the socket interface or write the program according to the socket standard, and the written program naturally follows the tcp/ip protocol.

 

Second, the sticky package problem

TCP , also known as streaming protocol, has two characteristics:

a , like a steady stream of water

b . Optimize the transmission mechanism, use the NAGLE algorithm to save data with a short time interval and a small amount of data into a wave

The above two characteristics lead to the sticky package problem

 

The idea of ​​​​solving the problem of sticky packets is to know how much to send, and then how much to receive

Note: If you use time.sleep to solve, solve this end, there may be sticky packets on the other end

 

3. Solve the problem of sticky package (basic board)

a , struct module

1 ) Convert the integer number to the bytes type

2 ) The converted bytes are of fixed length

 

import struct

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

print (res, len (res)) 

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

print(res2[0])

 

b . Server

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() #( connection object, client's ip and port )

    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。。一般要在一台机器上,不推荐远程调控。如若强行要求,不要直接执行,而是要模拟执行,并将模拟结果发回。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324766912&siteId=291194637