Pygame无法与套接字配合使用
我用pygame、imageGrab和sockets写了一个程序,但它不工作。这个程序应该是用ImageGrab截取服务器的屏幕,然后把这个截图转换成字符串,发送给客户端。然而,客户端在接收到信息并转换成图片时出现了错误:
image = pygame.image.frombuffer(img, (800,600), "RGB")
ValueError: Buffer length does not equal format and resolution size
服务器的代码
import sys, os, socket, pygame
from PIL import ImageGrab
from pygame.locals import *
print "streaming sever 0.1"
try:
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print "Error creating socket"
sys.exit(1)
host = "127.0.0.1"
port = raw_input("Port:")
socket.bind((host, int(port)))
socket.listen(2)
socket2,client = socket.accept()
print "Client conectado: " + str(client[0]) + "\nPorta usada: " + str(client[1])
#Capture and send
while True:
img=ImageGrab.grab().resize((800,600))
img.tostring()
socket2.sendall(img)
socket2.close()
客户端的代码
import sys, os, socket, pygame
from PIL import ImageGrab
from pygame.locals import *
print "streaming client 0.1"
pygame.init()
try:
s_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
print "streaming protocol started"
except socket.error:
print "Error creating socket"
sys.exit(1)
host = "127.0.0.1"
porta = raw_input("Port:")
q_bytes = raw_input("Enter the number of MBs to transfer: ")
t_bytes = 1024*1024*int(q_bytes)
try:
s_client.connect((host,int(porta)))
except socket.error:
print "Error connecting to: " + host
sys.exit(1)
print "Conectado!"
size = width, height = 800, 600
screen = pygame.display.set_mode(size)
num = 0
while True:
img = s_client.recv(t_bytes)
image = pygame.image.frombuffer(img, (800,600), "RGB")
screen.blit(image,(0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
os._exit(1)
#recebimento
s_client.close()
1 个回答
2
关于套接字(socket),如果你打算继续使用同一个连接,你必须准确知道你要接收的消息有多长。你在代码中用 q_bytes = raw_input("Enter the number of MBs to transfer: ")
这行代码似乎有点意识到这一点,但我们需要的是确切的长度,而不是大约多少MB。有时候,这个信息会在数据的开头部分发送过来,这样我们可以先读取它,然后就知道什么时候该停止读取了。
不过,如果我们不再需要这个连接,只想要一张图片,那就没问题,可以随便请求数据,最后会收到一个空字符串,表示没有更多数据了。
至于recv函数中的max_bytes参数,这只是一个最大值,实际上还有一个依赖于硬件的最大限制。在我的测试中,这个限制是1MB。
下面的代码会不断请求数据,直到收到一个空字符串为止,这表示没有更多数据了,然后把所有收集到的数据合并成一个完整的字符串。
虽然可以构建很多抽象层来简化这些复杂性,但下面的代码就是你的代码,正常工作,只是去掉了一些不相关的部分。
Client.py
import sys, os, socket, pygame
from pygame.locals import *
pygame.init()
s_client = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
host = "127.0.0.1"
porta = 12350
t_bytes = 1024*1024*1
s_client.connect((host,int(porta)))
print "Conectado!"
size = width, height = 300, 500
screen = pygame.display.set_mode(size)
message = []
while True:
s = s_client.recv(t_bytes)
if not s:
break
else:
message.append(s)
full_s = "".join(message)
print 'string received size', len(full_s)
image = pygame.image.frombuffer(full_s, size, "RGB")
#image = pygame.image.fromstring(s, size, "RGB")
screen.blit(image,(0,0))
pygame.display.flip()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
os._exit(1)
raw_input()
s_client.close()
Server.py
import sys, os, socket, pygame
from pygame.locals import *
socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "127.0.0.1"
port = 12350
socket.bind((host, int(port)))
socket.listen(2)
socket2,client = socket.accept()
print "Client conectado: " + str(client[0]) + "\nPorta usada: " + str(client
img = Image.open('tiny.jpg').resize((300, 500))
s = img.tostring()
print 'size of string', len(s)
socket2.sendall(s)
socket2.close()
补充说明:根据Mark的更正,之前的len()调用实际上是 __sizeof__()
方法的调用。__sizeof__
返回的是Python对象的字节大小,而不是字符串中的字节或字符数量。