网络编程 --ftp01上传
这是一个模拟的ftp上传功能,客户端输入命令之后,在客户端执行一个命令,把输入都上传到服务端在返回,前面是一个类似练习的例子
客户端
***** 服务端的conn指的是客户端的sockt套接字的对象*****
#小试牛刀 # import socket # kt=socket.socket() #创建socket对象 # info=("127.0.0.1",8800) # kt.connect(info) # while True: # import subprocess # res = subprocess.Popen("ipconfig", #实例化Popen类 #并且接受的值是byte类型 # shell=True, # stderr=subprocess.PIPE, # stdout=subprocess.PIPE) # # print(len(res.stdout.read().decode("gbk"))) # 实例res通过stdout.read()方法读取数据 # # print(">>>hello") # 这个地方不能写print # kt.send(res.stdout.read()) ########################################################################### # use=input("用户名:") # pwd=input("密码:") # val=("%s|%s"%(use,pwd)).encode("utf8") #把多个变量同时传过去 ############################################################################ import socket kt=socket.socket() #创建socket对象 info=("127.0.0.1",8800) kt.connect(info) while True: import subprocess cmd=input(">>>请输入命令") res = subprocess.Popen(cmd, #实例化Popen类 #并且接受的值是byte类型 shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE) # print(len(res.stdout.read().decode("gbk"))) # 实例res通过stdout.read()方法读取数据 # print(">>>hello") # 这个地方不能写print # out=res.stdout.read().decode("gbk") #写两个变量不让冲突,都在res上操作后面会出问题 # print(len(out)) # kt.send(res.stdout.read()) out = res.stdout.read() err = res.stderr.read() print("out长度",len(out)) print("err长度", len(err)) #构建包头 import struct # header_pack = struct.pack("i", len(out)) #把数据的长度打包成包头,和数据一起粘包发送过去,在服务端在解包 #要发送的包头内容 header_pack = struct.pack("i",len(out)) #i模式只能打包压缩整型类,打包的结果就是4个字节,可以直接发送 #发送包头, kt.send(header_pack) #发送内容 kt.send(out) #包头和内容会作为粘包一起传过去,在对方一起解开 #时间间隔特别短,两次发的就会当成一个包发过去
服务端
#小试牛刀 # import socket # sock=socket.socket() #创建socket对象,后面的操作都是对这个对象进行操作 # # info=("127.0.0.1",8800) # sock.bind(info) # sock.listen(5) # while True: # conn,addr=sock.accept() #开始阻塞 # # print("接收成功!") # data=conn.recv(1024) #recv的参数是固定长度 # print(data.decode("gbk")) # print("接收成功!") ########################################################################################### #conn是谁? import socket import struct sock=socket.socket() #创建socket对象,后面的操作都是对这个对象进行操作 info=("127.0.0.1",8800) sock.bind(info) sock.listen(5) while True: conn,addr=sock.accept() #开始阻塞 # print("接收成功!") data=conn.recv(4) #recv的参数是固定长度 data_length=struct.unpack("i",data)[0] #对方传过来是4长度的字节,解包以后是数字表示的长度,默认在元组中,用索引取出 print(data) print(data_length) print("接收成功!") recv_data_length=0 recv_data=b"" while recv_data_length<data_length: #data_length的长度是对方传过来的,这个是最大的 data=conn.recv(1024) recv_data_length+=len(data) recv_data+=data print(">>>>>>>%s"%type(recv_data)) print(recv_data.decode("gbk")) # data_length=int(conn.recv(1024).decode("utf8"))
其中用到的一些知识点:
struct模块
subprocess模块
下面是一个比较正式的的ftp上传的例子,客户端和服务端都有,有些知识点上面已经讲过了,
server端
import socket
import struct
sock=socket.socket() #创建socket对象,后面的操作都是对这个对象进行操作
info=("127.0.0.1",8900)
sock.bind(info) #里面是一个元组
sock.listen(5)
while True:
conn,addr=sock.accept() #开始阻塞
# print("接收成功!")
data=conn.recv(4) #recv的参数是固定长度
data_length = struct.unpack("i", data)[0]
# print(data.decode("utf8"))
recv_data_length = 0
recv_data = b""
while recv_data_length<data_length:
data=conn.recv(1024)
recv_data_length+=len(data)
recv_data+=data
print(">>>>>>>%s"%type(recv_data))
print(recv_data.decode("utf8"))
# data_length=int(conn.recv(1024).decode("utf8"))
client端
import socket
import os
import struct
sock=socket.socket()
info=("127.0.0.1",8900)
file_path=input(">>>请输入文件名,如不再当前目录请输入绝对路径:")
sock.connect(info) #里面是一个元组
#文件内容
data=b""
with open(file_path,mode="rb") as f1:
for line in f1:
data+=line
#构造包头
head_packge=struct.pack("i",len(data)) #构造后的结果直接是4位的字节
#发送包头
sock.send(head_packge)
#发送文件内容
sock.send(data)
# print("真实长度:",len(data))
# print("压包后的四位字节:" ,struct.pack("i",len(data)))
底层对粘包的启发
底层数据报文有包头,地址,数据内容等,都是一次发送的,这个就类似python中的粘包,一层发送过去再进行固定长度的解包