2、第七 - 网络编程基础 - Socket编程调用系统命令简单的ssh实现

编写socket调用类似于ssh远程调用系统命令

Socket编程类似ssh调用系统命令

Socket实现简单的ssh,并实现大于1024字节数据的传输。  

1、示例(在MAC上操作的):

服务端:

import socket,os

server = socket.socket()
server.bind(('localhost',3617))
server.listen()

while True:
    conn,addr = server.accept()
    print("new conn:",addr)
    while True:
        print ("等待新指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break
        print("执行命令:",data)
        cmd_res = os.popen(data.decode()).read() #接受字符串,执行结果也是字符串
        print("before send:",len(cmd_res))
        if len(cmd_res) == 0:
            cmd_res = "cmd_res has no output..."

        conn.send(str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端
        conn.send(cmd_res.encode("utf-8")) #再发内容大小
        print("send done")
server.close()

 客户端:

import socket

client = socket.socket()
client.connect(("localhost",3617))

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0: continue
    client.send(cmd.encode("utf-8"))
    cmd_res_size = client.recv(1024) #接受命令结果的长度
    print("命令结果大小:",cmd_res_size)
    received_size = 0
    received_data = b''

    while received_size < int(cmd_res_size.decode()):
        data = client.recv(1024)
        received_size += len(data) #每次收到的有可能小于1024,所以必须用len判断
        received_data += data
    else:
        print("cmd res receive done...",received_size)
        print(received_data.decode())
client.close()

 检查客户端与服务端的命令行输出:

服务端返回:
new conn: ('127.0.0.1', 60434)
等待新指令
执行命令: b'pwd'
before send: 48
send done
等待新指令
执行命令: b'top -l 2'
before send: 177758
send done
等待新指令

客户端返回:
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/mac/PycharmProjects/untitled2/51CTO/6day/socket_client_test.py
>>:pwd     #输入系统命令
命令结果大小: b'48'
cmd res receive done... 48
/Users/mac/PycharmProjects/untitled2/51CTO/6day
>>:top -l 2
命令结果大小: b'177758'
cmd res receive done... 177758
Processes: 313 total, 2 running, 311 sleeping, 1244 threads 
2018/03/27 15:27:17
Load Avg: 2.66, 2.52, 2.62 
CPU usage: 6.66% user, 23.33% sys, 70.0% idle 
SharedLibs: 172M resident, 43M data, 22M linkedit.
MemRegions: 60372 total, 2838M resident, 100M private, 935M shared.
PhysMem: 8091M used (1810M wired), 100M unused.
VM: 845G vsize, 621M framework vsize, 0(0) swapins, 0(0) swapouts.
Networks: packets: 874801/908M in, 760986/107M out.
Disks: 1097544/23G read, 811488/12G written.

2、Mac调用liunx 服务端上的server...注意: 客户端与服务端的Python版本要一致。

示例如下:

服务端:部署在 liunx 服务器上,注意监听的IP为 全网端,如下

import socket,os

server = socket.socket()
server.bind(('0.0.0.0',3617)) #监听全网端,同时注意Iptables的开放
server.listen()

while True:
    conn,addr = server.accept()
    print("new conn:",addr)
    while True:
        print ("等待新指令")
        data = conn.recv(1024)
        if not data:
            print("客户端已断开")
            break
        print("执行命令:",data)
        cmd_res = os.popen(data.decode()).read()
        print("before send:",len(cmd_res))
        if len(cmd_res) == 0:
            cmd_res = "cmd_res has no output..."

        conn.send(str(len(cmd_res.encode())).encode("utf-8"))
        conn.send(cmd_res.encode("utf-8"))
        print("send done")
server.close()

 客户端:运行在Mac PyCharm 上,如下:

import socket

client = socket.socket()
client.connect(("201.66.5.250",3617)) #监听服务端IP,注意服务器上的防火墙配置

while True:
    cmd = input(">>:").strip()
    if len(cmd) == 0: continue
    client.send(cmd.encode("utf-8"))
    cmd_res_size = client.recv(1024)
    print("命令结果大小:",cmd_res_size)
    received_size = 0
    received_data = b''

    while received_size < int(cmd_res_size.decode()):
        data = client.recv(1024)
        received_size += len(data)
        received_data += data
    else:
        print("cmd res receive done...",received_size)
        print(received_data.decode())
client.close()

 测试,输出结果如下:

客户端操作;
/Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /Users/mac/PycharmProjects/untitled2/51CTO/6day/socket_client_test.py
>>:pwd #输入命令
命令结果大小: b'5'
cmd res receive done... 5
/www

>>:ls #输入命令
命令结果大小: b'485'
cmd res receive done... 485
167log.csv
94log.csv
api167_host.php_20180103.log
API167_php-fpm_slow.log20180103.bak

服务端,日志打印输出:
new conn: ('99.38.28.116', 1470)
等待新指令
执行命令: b'pwd'
before send: 5
send done
等待新指令
执行命令: b'ls'
before send: 485
send done
等待新指

 

参考示例,解决“粘包”的问题,就是客户端接收到服务器端发送的信息时,本来是分开的信息,结果是没有隔行,一起输出打印。

#_*_coding:utf-8_*_
__author__ = 'Alex Li'


import socket
import os,subprocess


server = socket.socket() #获得socket实例
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

server.bind(("localhost",9999)) #绑定ip port
server.listen()  #开始监听

while True: #第一层loop
    print("等待客户端的连接...")
    conn,addr = server.accept() #接受并建立与客户端的连接,程序在此处开始阻塞,只到有客户端连接进来...
    print("新连接:",addr )
    while True:

        data = conn.recv(1024)
        if not data:
            print("客户端断开了...")
            break #这里断开就会再次回到第一次外层的loop
        print("收到命令:",data)
        #res = os.popen(data.decode()).read() #py3 里socket发送的只有bytes,os.popen又只能接受str,所以要decode一下
        res = subprocess.Popen(data,shell=True,stdout=subprocess.PIPE).stdout.read() #跟上面那条命令的效果是一样的
        if len(res) == 0:
            res = "cmd exec success,has not output!".encode("utf-8")
        conn.send(str(len(res)).encode("utf-8")) #发送数据之前,先告诉客户端要发多少数据给它
        print("等待客户ack应答...")
        client_final_ack = conn.recv(1024) #等待客户端响应
        print("客户应答:",client_final_ack.decode())
        print(type(res))
        conn.sendall(res) #发送端也有最大数据量限制,所以这里用sendall,相当于重复循环调用conn.send,直至数据发送完毕

server.close()
server端
#_*_coding:utf-8_*_
__author__ = 'Alex Li'

import socket
import sys

client = socket.socket()

client.connect(("localhost",9999))

while True:
    msg = input(">>:").strip()
    if len(msg) == 0:continue
    client.send( msg.encode("utf-8") )

    res_return_size  = client.recv(1024) #接收这条命令执行结果的大小
    print("getting cmd result , ", res_return_size)
    total_rece_size = int(res_return_size)
    print("total size:",res_return_size)
    client.send("准备好接收了,发吧loser".encode("utf-8"))
    received_size = 0 #已接收到的数据
    cmd_res = b''
    f = open("test_copy.html","wb")#把接收到的结果存下来,一会看看收到的数据 对不对
    while received_size != total_rece_size: #代表还没收完
        data = client.recv(1024)
        received_size += len(data) #为什么不是直接1024,还判断len干嘛,注意,实际收到的data有可能比1024少
        cmd_res += data
    else:
        print("数据收完了",received_size)
        #print(cmd_res.decode())
        f.write(cmd_res) #把接收到的结果存下来,一会看看收到的数据 对不对
    #print(data.decode()) #命令执行结果

client.close()
client端

备注:可添加 time.sleep(0.5) 阻断分开,不过不是最终的办法。

posted on 2018-03-28 16:08  C.Q&CHEN  阅读(220)  评论(0编辑  收藏  举报

导航