如何将文件客户端发送到客户端 python 3.



我重新搜索了这个话题,但没有结果。我已经在python中创建了一个客户端到客户端的通信,但是我需要知道如何通过在控制台中插入文件路径来将文件从一个发送到另一个。

def send_file(path):
file = open(path, "r")
msg = file.readline()
while msg:
signature = signing_key.sign(msg.encode(), encoding="hex")
msg = msg + "~" + signature.decode()
client_socket.send(bytes(msg, "utf8"))
msg = file.readline()
file.close()
def receive_file(msg):
file = open("new.txt", "w")
file.write(msg)
file.close()

编辑: 1.服务器

#!/usr/bin/env python3
"""Server for multithreaded (asynchronous) chat application."""
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread

def accept_incoming_connections():
"""Sets up handling for incoming clients."""
while True:
client, client_address = SERVER.accept()
print("%s:%s has connected." % client_address)
client.send(bytes("Greetings from the cave!", "utf8"))
addresses[client] = client_address
Thread(target=handle_client, args=(client,)).start()

def handle_client(client):  # Takes client socket as argument.
"""Handles a single client connection."""
name = client.recv(BUFSIZ).decode("utf8")
welcome = 'Welcome %s! If you ever want to quit, type {quit} to exit.' % name
client.send(bytes(welcome, "utf8"))
msg = "%s has joined the chat!" % name
broadcast(bytes(msg, "utf8"))
clients[client] = name
while True:
msg = client.recv(BUFSIZ)
if msg != bytes("{quit}", "utf8"):
broadcast(msg, name + ": ")
else:
client.send(bytes("{quit}", "utf8"))
client.close()
del clients[client]
broadcast(bytes("%s has left the chat." % name, "utf8"))
break

def broadcast(msg, prefix=""):  # prefix is for name identification.
"""Broadcasts a message to all the clients."""
print(msg)
for sock in clients:
sock.send(bytes(prefix, "utf8") + msg)

clients = {}
addresses = {}
HOST = '127.0.0.1'
PORT = 33000
BUFSIZ = 1024
ADDR = (HOST, PORT)
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)
if __name__ == "__main__":
SERVER.listen(5)
print("Waiting for connection...")
ACCEPT_THREAD = Thread(target=accept_incoming_connections)
ACCEPT_THREAD.start()
ACCEPT_THREAD.join()
SERVER.close()

2:这是我们可以运行多个客户端实例的客户端,因此连接将是使用服务器作为中间件的客户端到客户端

#!/usr/bin/env python3
"""Script for Tkinter GUI chat client."""
from socket import AF_INET, socket, SOCK_STREAM
from threading import Thread
import tkinter

def receive():
"""Handles receiving of messages."""
while True:
try:
msg = client_socket.recv(BUFSIZ).decode("utf8")
msg_list.insert(tkinter.END, msg)
except OSError:  # Possibly client has left the chat.
break

def send(event=None):  # event is passed by binders.
"""Handles sending of messages."""
msg = my_msg.get()
my_msg.set("")  # Clears input field.
client_socket.send(bytes(msg, "utf8"))
if "/" in msg:
send_file(msg)
if msg == "{quit}":
client_socket.close()
top.quit()

def on_closing(event=None):
"""This function is to be called when the window is closed."""
my_msg.set("{quit}")
send()

def send_file(path):
file = open('file.txt', "r")
msg = file.readline()
while msg:
client_socket.send(bytes(msg, "utf8"))
msg = file.readline()
file.close()

def receive_file(msg):
file = open("new.txt", "w")
file.write(msg)
file.close()

top = tkinter.Tk()
top.title("Chatter")
messages_frame = tkinter.Frame(top)
my_msg = tkinter.StringVar()  # For the messages to be sent.
scrollbar = tkinter.Scrollbar(messages_frame)  # To navigate through past messages.
# Following will contain the messages.
msg_list = tkinter.Listbox(messages_frame, height=15, width=50, yscrollcommand=scrollbar.set)
scrollbar.pack(side=tkinter.RIGHT, fill=tkinter.Y)
msg_list.pack(side=tkinter.LEFT, fill=tkinter.BOTH)
msg_list.pack()
messages_frame.pack()
entry_field = tkinter.Entry(top, textvariable=my_msg)
entry_field.bind("<Return>", send)
entry_field.pack()
send_button = tkinter.Button(top, text="Send", command=send)
send_button.pack()
top.protocol("WM_DELETE_WINDOW", on_closing)
#----Now comes the sockets part----
HOST = input('Enter host: ')
PORT = input('Enter port: ')
if not PORT:
PORT = 33000
else:
PORT = int(PORT)
BUFSIZ = 1024
ADDR = (HOST, PORT)
client_socket = socket(AF_INET, SOCK_STREAM)
client_socket.connect(ADDR)
receive_thread = Thread(target=receive)
receive_thread.start()
tkinter.mainloop()  # Starts GUI execution.

真的很难说你的问题在哪里。我认为receive_file函数中的msg不是完整的文件,而只是其中的一部分。其背后的原因是socket.recv方法与read()不同,它不返回"所有"数据,而只返回在调用之前收到的部分数据(并且有一些缓冲区限制,这并不重要。 atm)。因此,您需要首先接收所有数据,然后写入文件。

为此,您必须知道如何做到这一点。第一个只是将所有传入的数据保存到内存中,直到连接关闭。第二个首先发送发送方发送多大的文件信息,然后读取数据,直到传输完成。第二种方法的优点是可以对多个文件使用相同的连接。

以下是完整的服务器-客户端实现(实现第二种方式):

#send_recv.py
import struct
import sys
import socket
def send_file(path, sock):
with open(path, "rb") as file:
# First read file into memory
content = file.read()
# Now calculate size and convert it into 8-byte long bytes sequence
size = struct.pack("<Q", len(content))
# Send the file size
sock.send(size)
# Send the file
sock.send(content)

def recv_file(path, sock):
with open(path, "wb") as file:
# Receive size of file
received = sock.recv(8)
# Convert the 8-byte long sequence into integer
size, = struct.unpack("<Q", received)
# Start receiving data until the whole file is received
received = 0
while received < size:
data = sock.recv(4096)
file.write(data)
received += len(data)

if __name__ == "__main__":
with socket.socket() as s:
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
if sys.argv[1] == "-s":
s.bind(("localhost", 55000))
s.listen(1)
conn, addr = s.accept()
with conn:
print("Sending file {}".format(sys.argv[2]))
send_file(sys.argv[2], conn)
elif sys.argv[1] == "-c":
s.connect(("localhost", 55000))
print("Receiving into file {}".format(sys.argv[2]))
recv_file(sys.argv[2], s)

用法:

  • python3 send_recv.py -s some_file- 启动服务器发送文件
  • python3 send_recv.py -c some_file- 启动客户端接收文件

注意:使用 Python 3.6 进行测试

此外,您还应该添加一些错误检查。

最新更新