实现简单的ssh服务端
客户端输入 命令行命令,服务器端返回数据传送到客户端1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34# Author: Diedline
import socket
client = socket.socket()
client.connect(("localhost",6969))
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.decode().encode("utf-8"))
client.send("准备好接收了".encode("utf-8"))
"""
通过客户端回传数据,来防止粘包
"""
res_size = 0
while res_size <int(cmd_res_size.decode()):
cmd_res = client.recv(1024) #接受服务器的数据
res_size += len(cmd_res)
# print(cmd_res.decode()) #输出服务器返回的数据
print(res_size)
print(cmd_res.decode())
"""
每次收到的数据可能少于1024,所以需要len来判断
"""
else:
print("cmd res receive done....",res_size)
"""
在windows 上接受和发送的数据大小不匹配是因为中文判断len()测算方法有问题,
server 没有encode直接判断字符长度中文长度就是1,而客户端encode了
导致接收的比需要发送的多(问题已修正)
"""
服务器端接受客户端数据,发送对应的命令行中的指令1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35# Author: Diedline
import socket
import os
server = socket.socket() #1.定义网络协议
server.bind(("localhost",6969)) #2.给地址和连接的端口号
server.listen(6) #3.给定最大监听数量
while True: #4.为真继续
conn, addr = server.accept() #5.得到的 socket object传给coon
print("new conn:",addr) #address info传给addr
while True: #为真继续
data = conn.recv(1024) #给定一次最大传输大小
"""
当一次传输的数据大于1024时,多余的数据会存贮在buf即缓冲区
当你输入下一条指令的时候会优先输出缓冲区的数据
再执行下一条指令 所以信息会乱 解决方法:判断长度输出
"""
if not data: # 当data 为空时自动break进入上层while重新开始
print("客户端已断开")
break
print("执行指令",data)
cmd_res = os.popen(data.decode()).read() # 接受字符串执行结果也是字符串
"""
os.popen 相当于在cmd里输命令
"""
if len(cmd_res) ==0:
cmd_res = "cmd has no output"
conn.send( str(len(cmd_res.encode())).encode("utf-8")) #先发大小给客户端
# 错误原因 这里判断len()之前没有encode()
client_ack = conn.recv(1024)
"""
这里等待客户端确认 防止粘包
"""
conn.send(cmd_res.encode("utf-8"))
粘包:当两次数据一起发送时(即两个send时)缓冲区会把两次数据合并成一条 把两次操作强制成一次
可以通过time模块sleep导致它强制超时,这样做的话太慢了。(太low了)
所以可以在客户端加上一条 send指令,服务端加上一条接受客户端确认的指令recv,可以有效 防止粘包并提高效率。
ftp server
1.读取文件名
2.检测文件是否存在
3.打开文件
4.检测文件大小
5.发送文件大小给客户端
6.等客户端确认(防止粘包)
7.开始边读边发数据
8.发送 Md5值
客户端 输入put 加服务器当前路径下的文件名可以
将服务器端的文件传输到客户端,通过MD5值的比较
可以判断传送文件是否出错 .1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41# Author: Diedline
import socket
import hashlib
client = socket.socket()
client.connect(("localhost",6969))
while True:
cmd = input(">>:").strip()
if len(cmd) == 0: continue
if cmd.startswith("get"): #输入get xxx文件自动发送到服务器端
client.send(cmd.encode())
server_response = client.recv(1024)
print("server response is ",server_response)
client.send(b"ready to recv file")
file_total_size = int (server_response.decode())
received_size = 0
file_name = cmd.split()[1]
f = open(file_name+ ".new","wb") #发送的文件后面加了一个.new
m = hashlib.md5()
while received_size <file_total_size:
if file_total_size - received_size>1024: #要收不止一次
size =1024
else:
size = file_total_size-received_size
print("最后一次接收:",size)
"""
通过判断最后一次是否是等于1024来防止粘包
"""
data = client.recv(size)
received_size +=len(data)
m.update(data)
f.write(data)
# print(file_total_size,received_size) #打印看发送效果
else:
new_file_md5 = m.hexdigest()
print("file is receive done",received_size,file_total_size)
f.close()
server_file_md5 = client.recv(1024)
print("server file md5 :",server_file_md5.decode())
print("client file md5 :",new_file_md5)
client.close()
服务器端1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51# Author: Diedline
import hashlib
import socket ,os,time
server = socket.socket() #1.定义网络协议
server.bind(("localhost",6969)) #2.给地址和连接的端口号
server.listen(6) #3.给定最大监听数量
while True: #4.为真继续
conn, addr = server.accept() #5.得到的 socket object传给coon
print("new conn:",addr)
while True:
print("等待新指令")
data = conn.recv(1024)
if not data:
print("客户端已断开")
break
cmd, filename = data.decode().split()
print(filename)
if os.path.isfile(filename):
f = open(filename,"rb")
m = hashlib.md5()
file_size = os.stat(filename).st_size
conn.send(str(file_size).encode()) #发送文件大小
conn.recv(1024) #wait for ack
for line in f:
m.update(line)
conn.send(line)
print("file md5", m.hexdigest())
f.close()
conn.send(m.hexdigest().encode())
print("send done")
server.close()
client.send(cmd.encode())
server_response = client.recv(1024)
print("server response is ",server_response)
client.send(b"ready to recv file")
file_total_size = int (server_response.decode())
received_size = 0
file_name = cmd.split()[1]
f = open(file_name+ ".new","wb") #发送的文件后面加了一个.new
while received_size <file_total_size:
data = client.recv(1024)
received_size +=len(data)
f.write(data)
# print(file_total_size,received_size) #打印看发送效果
else:
print("file is receive done",received_size,file_total_size)
f.close()
client.close()