文章目录
前言
我的上一篇博客:【NVIDIA JETSON AGX XAVIER】与个人笔记本(win11)建立TCP-IP连接传输数据(含源码)
博客中的代码只能实现从服务器端(个人笔记本(win11))传输数据到客户端(NVIDIA JETSON AGX XAVIER),且只能传输一次文件
本博客将进行优化,并实现双向传输数据。
一、个人笔记本(win11)传输数据到XAVIER(多次传输)
在前面代码的基础上添加循环机制,假如现在服务器ip地址是192.168.0.1
1.服务器端代码(个人笔记本win11)
代码如下(示例):
import socket
import os
def send_file(filename, conn):
if os.path.isfile(filename):
# 发送文件存在确认消息
conn.send(b'EXISTS ' + str(os.path.getsize(filename)).encode())
user_response = conn.recv(1024).decode()
if user_response[:2] == 'OK':
with open(filename, 'rb') as f:
bytes_to_send = f.read(1024)
conn.send(bytes_to_send)
while bytes_to_send:
bytes_to_send = f.read(1024)
conn.send(bytes_to_send)
else:
conn.send(b'ERR ')
def server_program():
host = socket.gethostname()
port = 5005
server_socket = socket.socket()
server_socket.bind((host, port))
server_socket.listen(5)
print("服务器启动,等待连接...")
conn, address = server_socket.accept()
print("连接来自: " + str(address))
while True:
data = conn.recv(1024).decode()
if not data:
# 如果没有接收到数据,继续等待新的文件请求
continue
send_file(data, conn)
conn.close()
if __name__ == '__main__':
server_program()
2.客户端代码(NVIDIA JETSON AGX XAVIER)
代码如下(示例):
import socket
def client_program():
host = socket.gethostname()
port = 5001
client_socket = socket.socket()
client_socket.connect(("192.168.0.1", port))
print("连接成功")
while True: # 添加外部循环以持续请求文件
file_name = input("输入要传输的文件名或输入'exit'退出: ")
if file_name.lower() == 'exit':
break
client_socket.send(file_name.encode())
data = client_socket.recv(1024).decode()
if data[:6] == 'EXISTS':
file_size = int(data[6:])
client_socket.send(b'OK')
f = open('new_' + file_name, 'wb')
data = client_socket.recv(1024)
total_recv = len(data)
f.write(data)
while total_recv < file_size:
data = client_socket.recv(1024)
total_recv += len(data)
f.write(data)
print("{0:.2f}".format((total_recv/float(file_size))*100)+ "% Done")
print("下载完成!")
f.close()
else:
print("文件不存在!")
client_socket.close()
if __name__ == '__main__':
client_program()
二、两端相互传输(以另一种形式解决上一篇博客的问题)
假如现在服务器ip地址是192.168.0.1
1.服务器端代码(个人笔记本win11)
在前面代码的基础上添加receive_file函数,处理接收的客户端的数据。
代码如下(示例):
import socket
import os
def send_file(filename, conn):
if os.path.isfile(filename):
# 发送文件存在确认消息
conn.send(b'EXISTS ' + str(os.path.getsize(filename)).encode())
user_response = conn.recv(1024).decode()
if user_response[:2] == 'OK':
with open(filename, 'rb') as f:
bytes_to_send = f.read(1024)
conn.send(bytes_to_send)
# while bytes_to_send != "":
while bytes_to_send:
bytes_to_send = f.read(1024)
conn.send(bytes_to_send)
else:
conn.send(b'ERR ')
def server_program():
# 获取主机名
host = socket.gethostname()
port = 5011 # 初始化端口号
server_socket = socket.socket() # 获取socket对象
server_socket.bind((host, port)) # 绑定地址到socket
server_socket.listen(5) # 监听连接,最多可接受5个连接
print("服务器启动,等待连接...")
conn, address = server_socket.accept() # 接受新连接
print("连接来自: " + str(address))
while True:
data = conn.recv(1024).decode()
if data.startswith('send'):
filename = data[5:]
receive_file(filename, conn)
else:
send_file(data, conn)
if not data:
# break
continue
conn.close() # 关闭连接
def receive_file(filename, conn):
conn.send(b'READY')
with open(filename, 'wb') as f:
while True:
bytes_read = conn.recv(1024)
if not bytes_read:
break
f.write(bytes_read)
if __name__ == '__main__':
server_program()
2.客户端代码(NVIDIA JETSON AGX XAVIER)
在前面代码的基础上添加send_file_to_server函数,判断发送给服务器的文件是否存在,修改主函数(client_program),添加"输入 ‘get’ 请求文件,或者 ‘send’ 发送文件,或输入’exit’退出三种模式选择,客户端(Xavier)可以选择收或发文件。
代码如下(示例):
import socket
import os
def client_program():
host = socket.gethostname()
port = 5011
client_socket = socket.socket()
client_socket.connect(("192.168.0.1", port))
print("连接成功")
while True: # 添加外部循环以持续请求文件
action = input("输入 'get' 请求文件,或者 'send' 发送文件,或输入'exit'退出:")
if action.lower() == 'exit':
break
elif action.lower() == 'get':
file_name = input("输入要传输的文件名: ")
client_socket.send(file_name.encode())
data = client_socket.recv(1024).decode()
if data[:6] == 'EXISTS':
file_size = int(data[6:])
client_socket.send(b'OK')
# f = open(r'' + file_name, 'wb')
f = open(r'new_' + file_name, 'wb')
data = client_socket.recv(1024)
total_recv = len(data)
f.write(data)
while total_recv < file_size:
data = client_socket.recv(1024)
total_recv += len(data)
f.write(data)
print("{0:.2f}".format((total_recv/float(file_size))*100)+ "% Done")
print("下载完成!")
f.close()
else:
print("文件不存在!")
client_socket.send(file_name.encode())
elif action.lower() == 'send':
file_name = input("输入要发送的文件名: ")
if os.path.isfile(file_name): # 在这里添加检查
send_file_to_server(file_name, client_socket)
print("成功发送:" + file_name)
else:
print("文件不存在,请检查文件名是否正确。")
client_socket.close()
def send_file_to_server(filename, client_socket):
if os.path.isfile(filename): # 检查文件是否存在
client_socket.send(('send ' + filename).encode())
response = client_socket.recv(1024).decode()
if response == 'READY':
with open(filename, 'rb') as f:
bytes_to_send = f.read(1024)
while bytes_to_send:
client_socket.send(bytes_to_send)
bytes_to_send = f.read(1024)
else:
print("文件不存在,请检查文件名是否正确。")
if __name__ == '__main__':
client_program()
三、传输数据中的缓存问题
运行上述程序出现的问题:客户端在选择进行两次send发送文件时,前一次send发送成功,且能够在服务器上看到传输的文件,但是文件大小为0,过一段时间后,文件才会恢复原本的大小。
且再一次的send,输入文件名回车后,程序将没有反应。
程序将没有反应。只能直接结束程序,报错如下:
1.查找资料,发现问题
问题可能与文件传输的同步性有关。当文件内容在传输后为空,但过一段时间后恢复,这可能意味着文件数据在传输过程中被缓存或延迟了。这种情况可能是由于网络延迟或者客户端和服务器之间的同步问题。
对于客户端在第一次发送文件后无法再次发送文件的问题,这可能是因为客户端或服务器的socket没有正确地处理连续的send操作。在某些情况下,如果发送缓冲区没有被及时清空,或者前一次的数据还没有完全发送完毕,再次尝试send可能会失败。
2.尝试解决
以下是一些可能的解决方法:
-
确认发送和接收程序的同步:确保发送方在发送完一个文件后,接收方已经完全接收并处理了该文件。可以通过在发送方和接收方之间实现一个简单的确认机制,例如发送方在发送完一个文件后等待接收方的确认消息,然后再进行下一个文件的发送。
-
检查网络状况:网络延迟或不稳定可能会导致文件传输中断或延迟。确保网络连接稳定,并考虑使用更可靠的网络连接。
-
使用流控制协议:如果您正在使用自定义的文件传输协议,考虑实现TCP-like的流控制机制,如滑动窗口协议,以确保数据的可靠传输。
-
调整socket选项:在某些情况下,调整socket的行为可以帮助解决问题。例如,设置socket为非阻塞模式,并使用select或epoll来监控socket的状态,这样可以更有效地管理发送缓冲区和避免发送阻塞。
-
使用现有的文件传输协议:如果可能,考虑使用现有的文件传输协议,如FTP或SFTP,这些协议提供了更完善的错误检查和恢复机制,适合传输大文件。
-
检查程序逻辑:仔细检查客户端和服务器程序的逻辑,确保在发送和接收文件时,程序能够正确处理连续的send操作。
尝试上述方法并未解决!判断可能是网络延迟问题
总结
本博客建立了 XAVIER与个人笔记本(win11)的TCP-IP连接并实现了相互传输数据,但传输过程中存在缓存问题,不能保证每次传输都能够成功,还需要优化程序!