python学习----9.3---基于tcp通信协议的套接字(通信循环,链接循环)、粘包

服务端必须满足至少三点:

  1.绑定一个固定的ip和port

  2.一直对外提供服务,稳定运行

  3.能够支持并发

通信循环

from socket import *

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

conn, client_addr = server.accept()
print(client_addr)

# 通信循环
while True:
    try:
        data = conn.recv(1024)
        if len(data) == 0:break # 针对linux系统
        print('-->收到客户端的消息: ',data)
        conn.send(data.upper())
    except ConnectionResetError:
        break

conn.close()
server.close()
服务端
from socket import *

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8080))

# 通信循环
while True:
    msg=input('>>: ').strip()
    client.send(msg.encode('utf-8'))
    data=client.recv(1024)
    print(data)

client.close()
客户端

链接循环

from socket import *


server=socket(AF_INET,SOCK_STREAM)
server.bind(('127.0.0.1',8081))
server.listen(5)


#链接循环
while True:
    conn,client_addr=server.accept()
    print((client_addr))

    #通信循环
    while True:
        try:
            data=conn.recv(1024)
            if len(data)==0:break #针对linux系统
            print('--->收到客户端消息:',data)
            conn.send(data.upper())
        except ConnectionResetError:
            break
    conn.close()

server.close()
服务端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect(('127.0.0.1',8081))


#通信循环
while True:
    msg=input('>>:').strip()
    if len(msg)==0:continue
    client.send(msg.encode(('utf-8')))
    data=client.recv(1024)
    print(data)
client.close()
客户端

模拟ssh实现远程执行命令

from socket import *
import subprocess

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

# 链接循环
while True:
    conn, client_addr = server.accept()
    print(client_addr)

    # 通信循环
    while True:
        try:
            cmd = conn.recv(1024)
            if len(cmd) == 0: break  # 针对linux系统
            obj = subprocess.Popen(cmd.decode('utf-8'),
                                   shell=True,
                                   stdout=subprocess.PIPE,
                                   stderr=subprocess.PIPE
                                   )
            stdout = obj.stdout.read()
            stderr = obj.stderr.read()
            print(len(stdout) + len(stderr))
            conn.send(stdout + stderr)
        except ConnectionResetError:
            break
    conn.close()

server.close()
服务端
from socket import *

client=socket(AF_INET,SOCK_STREAM)
client.connect('127.0..0.1',8081)

while True:
    cmd=input('--->:').strip()
    if len(cmd)==0:continue
    client.send(cmd.encode('utf-8'))
    data=client.recv(1024000)
    print(data.decode('gbk'))

client.close()
客户端

Struct模块

  该模块可以把一个类型,如数字转换成bytes类型

import struct

# obj1=struct.pack('i',13321111111)
# print(obj1,len(obj1))

# res1=struct.unpack('i',obj1)
# print(res1[0])

obj1=struct.pack('q',1332111111111)
print(obj1,len(obj1))
View Code

模拟ssh实现远程执行命令(解决粘包问题终极版)

from socket import *
import struct
import json
import subprocess

server = socket(AF_INET, SOCK_STREAM)
server.bind(('127.0.0.1', 8081))
server.listen(5)

while True:
    conn, client_addr = server.accept()
    print(client_addr)

    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 = obj.stdout.read()
            stderr = obj.stderr.read()
            # 1.先制作报头
            header_dic = {
                'filename': 'a.txt',
                'md5': 'sadsdadsasd12312321',
                'total_size': len(stdout) + len(stderr)
            }
            header_json = json.dumps(header_dic)
            header_bytes = header_json.encode(('utf-8'))

            # 2.先发送4个bytes(包含报头的长度)
            conn.send(struct.pack(('i'), len(header_bytes)))
            # 3.再发送报头
            conn.send(header_bytes)
            # 4.最后发送真实的数据
            conn.send(stdout)
            conn.send(stderr)
        except ConnectionResetError:
            break
    conn.close()

server.close()
服务端
from socket import *
import json
import struct

client = socket(AF_INET, SOCK_STREAM)
client.connect(('127.0.0.1', 8081))

while True:
    cmd = input('--->:').strip()
    if len(cmd) == 0: continue
    client.send(cmd.encode('utf-8'))
    # 1.先收4bytes,解出报头长度
    header_size = struct.unpack('i', client.recv(4))[0]

    # 2.再接受报头,拿到header_dic
    header_bytes = client.recv(header_size)
    header_json = header_bytes.decode('utf-8')
    header_dic = json.loads(header_json)
    print(header_dic)
    total_size = header_dic['total_size']

    # 3.接收真正的数据
    cmd_res = b''
    recv_size = 0
    while recv_size < total_size:
        data = client.recv(1024)
        recv_size += len(data)
        cmd_res += data

    print(cmd_res.decode('gbk'))

client.close()
客户端

两种情况下会发生粘包现象

  1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包)

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
from socket import *
ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)


conn,addr=tcp_socket_server.accept()


data1=conn.recv(10)
data2=conn.recv(10)

print('----->',data1.decode('utf-8'))
print('----->',data2.decode('utf-8'))

conn.close()
服务端
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
BUFSIZE=1024
ip_port=('127.0.0.1',8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)


s.send('hello'.encode('utf-8'))
s.send('feng'.encode('utf-8'))
客户端

  2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包) 

#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
from socket import *
ip_port=('127.0.0.1',8080)

tcp_socket_server=socket(AF_INET,SOCK_STREAM)
tcp_socket_server.bind(ip_port)
tcp_socket_server.listen(5)


conn,addr=tcp_socket_server.accept()


data1=conn.recv(2) #一次没有收完整
data2=conn.recv(10)#下次收的时候,会先取旧的数据,然后取新的

print('----->',data1.decode('utf-8'))
print('----->',data2.decode('utf-8'))

conn.close()
服务端
#_*_coding:utf-8_*_
__author__ = 'Linhaifeng'
import socket
BUFSIZE=1024
ip_port=('127.0.0.1',8080)

s=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
res=s.connect_ex(ip_port)


s.send('hello feng'.encode('utf-8'))
客户端
原文地址:https://www.cnblogs.com/Liu-guang-hui/p/9580257.html