【发布时间】:2017-07-10 10:14:10
【问题描述】:
我想用 Python 中的套接字编写一个简单的 TCP 服务器。服务器应将图像发送到连接的客户端。客户端应该会收到图像。但是,现在,客户端只收到图像的一部分,我什至无法打开它。
服务器是使用 select 的多客户端,但这不是问题所在。我认为问题在于发送图像。
我希望这里的“协议”非常简单。
SERVER CLIENT
GET
<----------------
IMAGE
----------------->
END OF COMMUNICATION
所以客户端只能向服务器发送“GET”消息,而服务器在得到“GET”字符串后,应该立即将整个图像发送给客户端。至此,通讯结束。
server.py
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
image = 'image.png'
HOST = '127.0.0.1'
PORT = 6666
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
bytes = open(image).read()
if data:
sock.send(bytes)
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
server_socket.close()
client.py
#!/usr/bin/env python
import socket
import sys
HOST = '127.0.0.1'
PORT = 6666
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (HOST, PORT)
sock.connect(server_address)
try:
sock.sendall("GET")
while True:
myfile = open('imagefromserv.png', 'w')
while True:
data = sock.recv(4096)
if not data:
break
myfile.write(data)
myfile.close()
finally:
sock.close()
我在最新的 Ubuntu 上使用 Python 2.7。
------------------------------------------ -------------------------------------------------- -------------------------------------- 编辑 ----------------------------------------------- -------------------------------------------------- ----------------------------------
根据 cmets 中一位用户的建议,我尝试实现一个简单的协议:
CLIENT SERVER
GET\r\n
----------------------------------->
OK\r\n
<-----------------------------------
GET_SIZE\r\n
----------------------------------->
SIZE 1024\r\n
<-----------------------------------
GET_IMG\r\n
----------------------------------->
IMG_DATA\r\r
<-----------------------------------
一切似乎都正常,但在图像传输之后,我的 CPU 100% 忙,正如top 所说。还有....
服务器的输出:
--GET--
--GET_SIZE--
--24518--
--GET_IMG--
客户的输出:
--OK--
--SIZE 24518--
--24518--
4096
8192
12288
16384
20480
24523
Image received successfully
表示客户端成功接收到图片。现在好吗?我的意思是,我从服务器获得了图像,但我不知道我是否正确实现了协议。也许这里可以改进一些东西?
client.py:
#!/usr/bin/env python
import socket
import sys
HOST = '127.0.0.1'
PORT = 6666
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = (HOST, PORT)
sock.connect(server_address)
fname = 'fromserver.png'
try:
sock.sendall("GET\r\n")
data = sock.recv(4096)
if data:
txt = data.strip()
print '--%s--' % txt
if txt == 'OK':
sock.sendall("GET_SIZE\r\n")
data = sock.recv(4096)
if data:
txt = data.strip()
print '--%s--' % txt
if txt.startswith('SIZE'):
tmp = txt.split()
size = int(tmp[1])
print '--%s--' % size
sock.sendall("GET_IMG\r\n")
myfile = open(fname, 'wb')
amount_received = 0
while amount_received < size:
data = sock.recv(4096)
if not data :
break
amount_received += len(data)
print amount_received
txt = data.strip('\r\n')
if 'EOF' in str(txt) :
print 'Image received successfully'
myfile.write(data)
myfile.close()
else :
myfile.write(data)
finally:
sock.close()
server.py:
#!/usr/bin/env python
import random
import socket, select
from time import gmtime, strftime
image = 'tux.png'
HOST = '127.0.0.1'
PORT = 6666
connected_clients_sockets = []
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
connected_clients_sockets.append(server_socket)
while True:
read_sockets, write_sockets, error_sockets = select.select(connected_clients_sockets, [], [])
for sock in read_sockets:
if sock == server_socket:
sockfd, client_address = server_socket.accept()
connected_clients_sockets.append(sockfd)
else:
try:
data = sock.recv(4096)
if data :
txt = data.strip()
print '--%s--'%txt
if txt == 'GET' :
sock.sendall('OK\r\n')
elif txt == 'GET_SIZE' :
with open ('tux.png','rb') as f1:
file_size = len(f1.read())
f1.seek(0)
print '--%s--'%file_size
file_size = '%s' % file_size
sock.sendall('SIZE %s\r\n' % file_size)
elif txt == 'GET_IMG' :
with open(image, 'rb') as fp:
image_data = fp.read()
msg = '%sEOF\r\r' % image_data
sock.sendall(msg)
print msg
except:
sock.close()
connected_clients_sockets.remove(sock)
continue
server_socket.close()
或者我应该这样做:
sock.sendall(image_data)
sock.sendall('EOF\r\n')
代替:
msg = '%sEOF\r\n' % image_data
sock.sendall(msg)
在客户端?
【问题讨论】:
-
您在 TCP 之上使用什么协议来发送和接收文件?如果您没有记录它,则需要 - 否则,几乎不可能判断客户端和服务器是否在做正确的事情。
-
@DavidSchwartz:我只想使用 TCP 套接字发送和接收图像 - 仅此而已,无需其他协议。
-
那么你的客户端有一个严重的错误,它发送的字符串“GET”不是任何图像的一部分。 (老实说,我可以根据多年的经验告诉你——你确实需要准确地记录你的协议。请求是如何分隔的?服务器如何标记数据的结尾?客户端如何识别它?)跨度>
-
在服务器代码中,使用
sock.sendall(bytes)而不是sock.send(bytes)- 这应该递归地发送整个图像文件 -
很可能是额外的外部
while True:。打开文件,接收数据,关闭文件,然后重新开始。文件再次打开并被截断,recv() 被调用但没有更多数据,文件被关闭。它应该是一个无限循环,或者只是挂起......这取决于服务器是否调用shutdown()来指示没有更多数据。