2016-11-04 103 views
0

我想通过套接字发送PyGame图像与Python 3.5,我总是有一个错误。Python3.5通过套接字发送对象(Pygame凸轮图像)

我得到的图像,我把它,然后我发送它。

在客户端,我收到它,我unpickle它,我展示它。

,但我得到了一个错误:

fenetre.blit(img, (20, 30)) pygame.error: display Surface quit

这里是我的服务器代码(在一个至极发送图像):

pygame.init() 
pygame.camera.init() 
cam = pygame.camera.Camera("/dev/video0", (680, 480)) 
cam.start() 
class Streaming(Thread): 


    def __init__(self): 
     Thread.__init__(self) 
    def run(self): 

     s = socket.socket() 
     s.bind(('192.168.1.158', 12801)) 
     s.listen(1) 
     while True: 
      sc, info = s.accept() 
      print("Video client connected : "+str(info)) 
      try: 
       while True: 
        image = cam.get_image() 
        str_img = pickle.dumps(image) 
        sc.send(str_img) 
        print(str_img) 
        print("Sending Image") 
        time.sleep(0.005) 
      except Exception as e: 
       print(str(e)) 

以及客户端的代码:

fenetre = pygame.display.set_mode((900, 900)) 
class Receiving(Thread): 


    def __init__(self): 
     Thread.__init__(self) 

     self.clock = pygame.time.Clock() 

    def run(self): 
     global fenetre 
     si = socket.socket() 
     si.connect(("192.168.1.158", 12801)) 
     while True: 
      img = si.recv(4096) 
      img = pickle.loads(img) 
      fenetre.blit(img, (20, 30)) 
      pygame.display.flip() 
      self.clock.tick(60) 

预先感谢!

+0

您发送'680x480' ='326400'字节(或者甚至'326400 * 3'如果像素使用3个字节)但你只收到'4096'。在使用'pickle'和'blit'之前,您必须收到所有数据。 – furas

+0

谢谢。但现在,问题是我无法在单个“recv”否接收大量数据?我该怎么做326500字节? – Minege

+0

你必须使用循环多次接收'4096'字节。如果你知道有多少字节将被发送,那么你知道你需要多少次接收'4096'字节。 – furas

回答

0

我做了用当前时间发送表面的例子。

(Pygame无法使用我的相机)。

它使用struc.pack()在发送图像之前始终将图像大小发送为4个字节。所以客户端首先接收4个字节并且具有图像大小。然后它可以使用这些信息来接收图像。

两者都使用循环发送/接收所有的时间。

server.py

#!/usr/bin/env python 

import pygame 
from threading import Thread 
import socket 
import struct # to send `int` as `4 bytes` 
import time # for test 

# --- constants --- 

ADDRESS = ("localhost", 12801) 

SURFACE_SIZE = (640, 480) 

WHITE = (255, 255, 255) 
BLACK = ( 0, 0, 0) 
GREEN = ( 0, 255, 0) 

# --- classes --- 

class Streaming(Thread): 

    def __init__(self): 
     Thread.__init__(self) 

     pygame.init() 

     #pygame.camera.init() 
     #self.cam = pygame.camera.Camera("/dev/video0", SURFACE_SIZE) 
     #self.cam.start() 

     # create surface to imitate camera image 
     self.image = pygame.Surface(SURFACE_SIZE) 
     self.image_rect = self.image.get_rect() 

     # create font to display text on surface 
     self.font = pygame.font.Font(None, 50) 

    def get_image(self): 
     # emulate cam.get_image() 

     # get current time as string 
     current_time = time.strftime('%H:%M:%S.%s') 

     # render surface with text (and center it) 
     text = self.font.render(current_time, True, BLACK, GREEN) 
     text_rect = text.get_rect(center=self.image_rect.center) 

     # clear image and put new text 
     self.image.fill(WHITE) 
     self.image.blit(text, text_rect) 

     return self.image 

    def run(self): 

     s = socket.socket() 

     # solution for: "socket.error: [Errno 98] Address already in use" 
     s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 

     s.bind(ADDRESS) 
     s.listen(1) 

     print("Wait for connection") 

     try: 
      sc, info = s.accept() 
      print("Video client connected:", info) 

      while True: 
       # get image surface 

       #image = self.cam.get_image() 
       image = self.get_image() 

       # convert surface to string 

       img_str = pygame.image.tostring(image, 'RGB') 

       print('len:', len(img_str)) 

       # send string size 

       len_str = struct.pack('!i', len(img_str)) 
       sc.send(len_str) 

       # send string image 

       sc.send(img_str) 

       # wait 

       time.sleep(0.5) 

     except Exception as e: 
      print(e) 
     finally: 
      # exit 
      print("Closing socket and exit") 
      sc.close() 
      s.close() 
      pygame.quit() 

# --- main --- 

Streaming().run() 

client.py

#!/usr/bin/env python 

import pygame 
from threading import Thread 
import socket 
import struct 

# --- constants --- 

ADDRESS = ("localhost", 12801) 

SURFACE_SIZE = (640, 480) 

# --- classes --- 

class Receiving(Thread): 

    def __init__(self): 
     Thread.__init__(self) 

     pygame.init() 

     self.screen = pygame.display.set_mode((800, 600)) 
     self.screen_rect = self.screen.get_rect() 

     self.clock = pygame.time.Clock() 

    def run(self): 
     s = socket.socket() 
     s.connect(ADDRESS) 

     try: 
      running = True 
      while running: 
       # receive size 

       len_str = s.recv(4) 
       size = struct.unpack('!i', len_str)[0] 

       print('size:', size) 

       # receive string 

       img_str = b'' 

       while size > 0: 
        if size >= 4096: 
         data = s.recv(4096) 
        else: 
         data = s.recv(size) 

        if not data: 
         break 

        size -= len(data) 
        img_str += data 

       print('len:', len(img_str)) 

       # convert string to surface 

       image = pygame.image.fromstring(img_str, SURFACE_SIZE, 'RGB') 
       image_rect = image.get_rect(center=self.screen_rect.center) 

       # blit 

       self.screen.blit(image, image_rect) 
       pygame.display.flip() 

       #self.clock.tick(30) 

       # wait for ESC or close window 

       for event in pygame.event.get(): 
        if event.type == pygame.QUIT: 
         running = False 
        elif event.type == pygame.KEYDOWN: 
         if event.key == pygame.K_ESCAPE: 
          running = False 

     except Exception as e: 
      print(e) 
     finally: 
      # exit 
      print("Closing socket and exit") 
      s.close() 
      pygame.quit() 

# --- main --- 

Receiving().run() 
+0

谢谢。 我已经尝试过了,它看起来像一个很好的解决方案,但是在接收循环中,它很好地接收,但是在最后一次,它在无限的等待中。因为它是recv(4096),但服务器在正常情况下完成发送 – Minege

+0

,当服务器close()套接字,然后recv()停止等待。我不记得是否有一些'EOF'字符(文件结束)来通知它是数据的结束。但是你可以首先发送多少数据将被发送的信息,然后你知道有多少次使用'recv()'。我尝试做例子。 – furas

+0

我把新的代码放在答案中。现在它使用循环来始终发送/接收图像。它用当前时间发送图像。在发送图像之前,服务器总是发送4个字节的图像大小,客户机在开始接收图像之前总是接收4个字节 - 因此它知道必须接收多少个字节。 – furas