我目前正在尝试创建一个客户端服务器应用程序,其中客户端可以使用TCP协议将多个文件发送到服务器。服务器最终将创建一个哈希算法并将其发送回客户端,但是我遇到了从客户端向服务器发送多个文件的问题。按照当前格式,第一个文件可以正确发送,但是遇到错误后将信息合并在一起,因此文件正确发送。 IE的文件大小被列为第二个文件的名称。我是一名JavaScript专家,并且是python的新手,因此非常感谢您提供有关如何实现此目标的解释。我相信线程是答案,但是由于我对python的了解有限,所以我不知道该如何做。目前,我一次只能发送一个文件,并且服务器保持打开状态。但是,我想从当前目录输入几个文件名并进行处理。我最终会将整个客户端转换为C,但是我正在努力使服务器在python中正常工作。任何建议将不胜感激!
Server.py
import socket
import hashlib
import threading
import struct
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
conn, addr = s.accept()
print("Got a connection from ", addr)
while True:
hash_type = conn.recv(1024)
print('hash type: ', hash_type)
if not hash_type:
break
file_name = conn.recv(1024)
print('file name: ', file_name)
file_size = conn.recv(1024)
file_size = int(file_size, 2)
print('file size: ', file_size )
f = open(file_name, 'wb')
chunk_size = 4096
while file_size > 0:
if file_size < chunk_size:
chuk_size = file_size
data = conn.recv(chunk_size)
f.write(data)
file_size -= len(data)
f.close()
print('File received successfully')
s.close()
Client.py
import socket
import threading
import os
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
hash_type = input('Enter hash type: ')
files = input('Enter file(s) to send: ')
files_to_send = files.split()
for file_name in files_to_send:
s.send(hash_type.encode())
print(file_name)
s.send(file_name.encode())
file_size = os.path.getsize(file_name)
file_size = bin(file_size)
print(file_size)
s.send(file_size.encode())
f = open(file_name, 'rb')
l = f.read()
while(l):
s.send(l)
l = f.read()
f.close()
print('File Sent')
s.close()
答案 0 :(得分:0)
1。
file_size = conn.recv(1024)
在服务器代码中,您读取的1024字节为file_size,file_size只有4或8个字节长
2。
file_name = conn.recv(1024)
您的服务器不知道文件名/哈希类型有多长时间。
->将long用作两个大小,并仅从流中读取sizeof(long)个字节。
您可以使用https://docs.python.org/2/library/struct.html打包/编码这些数字
->或者只是简单的方法,并使用https://docs.python.org/3/library/pickle.html进行序列化
答案 1 :(得分:0)
处理您正在做的事情的一种方法是缓冲套接字数据。下面是一个类,用于缓冲数据,并且知道如何发送和接收以null终止,UTF-8编码的字符串以及原始字节块:
buffer.py:
class Buffer:
def __init__(self,s):
'''Buffer a pre-created socket.
'''
self.sock = s
self.buffer = b''
def get_bytes(self,n):
'''Read exactly n bytes from the buffered socket.
Return remaining buffer if <n bytes remain and socket closes.
'''
while len(self.buffer) < n:
data = self.sock.recv(1024)
if not data:
data = self.buffer
self.buffer = b''
return data
self.buffer += data
# split off the message bytes from the buffer.
data,self.buffer = self.buffer[:n],self.buffer[n:]
return data
def put_bytes(self,data):
self.sock.sendall(data)
def get_utf8(self):
'''Read a null-terminated UTF8 data string and decode it.
Return an empty string if the socket closes before receiving a null.
'''
while b'\x00' not in self.buffer:
data = self.sock.recv(1024)
if not data:
return ''
self.buffer += data
# split off the string from the buffer.
data,_,self.buffer = self.buffer.partition(b'\x00')
return data.decode()
def put_utf8(self,s):
if '\x00' in s:
raise ValueError('string contains delimiter(null)')
self.sock.sendall(s.encode() + b'\x00')
使用此类,您的客户端和服务器将变为:
client.py:
import socket
import threading
import os
import buffer
HOST = '127.0.0.1'
PORT = 2345
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
with s:
sbuf = buffer.Buffer(s)
hash_type = input('Enter hash type: ')
files = input('Enter file(s) to send: ')
files_to_send = files.split()
for file_name in files_to_send:
print(file_name)
sbuf.put_utf8(hash_type)
sbuf.put_utf8(file_name)
file_size = os.path.getsize(file_name)
sbuf.put_utf8(str(file_size))
with open(file_name, 'rb') as f:
sbuf.put_bytes(f.read())
print('File Sent')
server.py:
import socket
import os
import buffer
HOST = ''
PORT = 2345
# If server and client run in same local directory,
# need a separate place to store the uploads.
try:
os.mkdir('uploads')
except FileExistsError:
pass
s = socket.socket()
s.bind((HOST, PORT))
s.listen(10)
print("Waiting for a connection.....")
while True:
conn, addr = s.accept()
print("Got a connection from ", addr)
connbuf = buffer.Buffer(conn)
while True:
hash_type = connbuf.get_utf8()
if not hash_type:
break
print('hash type: ', hash_type)
file_name = connbuf.get_utf8()
if not file_name:
break
file_name = os.path.join('uploads',file_name)
print('file name: ', file_name)
file_size = int(connbuf.get_utf8())
print('file size: ', file_size )
with open(file_name, 'wb') as f:
remaining = file_size
while remaining:
chunk_size = 4096 if remaining >= 4096 else remaining
chunk = connbuf.get_bytes(chunk_size)
if not chunk: break
f.write(chunk)
remaining -= len(chunk)
if remaining:
print('File incomplete. Missing',remaining,'bytes.')
else:
print('File received successfully.')
print('Connection closed.')
conn.close()
演示
客户端:
Enter hash type: abc
Enter file(s) to send: demo1.dat demo2.dat
demo1.dat
File Sent
demo2.dat
File Sent
服务器:
Waiting for a connection.....
Got a connection from ('127.0.0.1', 22126)
hash type: abc
file name: uploads\demo1.dat
file size: 488892
File received successfully.
hash type: abc
file name: uploads\demo2.dat
file size: 212992
File received successfully.
Connection closed.