2016-11-04 100 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