python中的屏幕共享

CSc*_*f x 10 python sockets pygame screenshot screensharing

嗨,我被困住了,我在互联网上没有找到任何有用的东西。我正在尝试用 python 制作一个屏幕共享程序。问题是我无法以至少 24 fps 的速度发送屏幕,因为当我使用 PIL (ImageGrab) 截取屏幕截图时,会出现延迟。我的客户端将从服务器获取图片(屏幕截图)并使用 pygame 将其“blit”到屏幕上。

服务器:

# -*- coding: utf-8 -*-


import socket
import os
import threading
from PIL import ImageGrab
def RetrFile(name, sock):

    while 1:
        img = ImageGrab.grab()
        img.save("PATH_TO_PIC")

        filename = "PATH_TO_PIC"
        sock.send(str(os.path.getsize(filename)))
        with open('PATH_TO_PIC', 'rb') as f:
            bytesToSend = f.read(1024)
            sock.send(bytesToSend)
            while bytesToSend != "":
                bytesToSend = f.read(1024)
                sock.send(bytesToSend)

def Main():
   host = '0.0.0.0'
   port = 5000

   s = socket.socket()
   s.bind((host,port))

   s.listen(5)
   print "Server Started."

   while True:
       c, addr = s.accept()
       print "Client connected ip: <"+ str(addr) + ">"
       t = threading.Thread(target = RetrFile, args = ("retrThread", c))
       t.start()
   s.close()

if __name__ == '__main__':
    Main()
Run Code Online (Sandbox Code Playgroud)

客户:

import socket
import pygame as pg
def Main():
    host = '127.0.0.1'
    port = 5000


    pg.init()
    display_screen = pg.display.set_mode((1900, 1000))



    clock = pg.time.Clock()

    s = socket.socket()
    s.connect((host,port))
    filename =  "PATH_TO_PIC"
    isExit = False
    while not isExit:

        for event in pg.event.get():
            if event.type == pg.QUIT:
                isExit = True
        data = s.recv(1024)
        print data
        filesize = long(data)

        f = open(filename, 'wb')
        data = s.recv(1024)
        totalRecv  =  len(data)
        f.write(data)
        while totalRecv < filesize:
            data = s.recv(1024)
            totalRecv += len(data)
            f.write(data)
        showImg = pg.image.load('PATH_TO_PIC')
        display_screen.blit(showImg, (0,0))
        pg.display.flip()
        clock.tick(60)
    s.close()

if __name__ == '__main__':
    Main()
Run Code Online (Sandbox Code Playgroud)

基本上我的问题是:如何在2台电脑之间共享一个屏幕,我不知道使用PIL发送大量图片的方式是否高效正确。有没有更有效的方法?投射1号计算机的屏幕并在2号计算机上显示它?

Tig*_*222 11

我刚刚尝试过,它似乎工作得很好(Python 3)。如果您认为这可以接受,请告诉我,我正在使用 MSS 模块来防止 I/O。

服务器.py

from socket import socket
from threading import Thread
from zlib import compress

from mss import mss


WIDTH = 1900
HEIGHT = 1000


def retreive_screenshot(conn):
    with mss() as sct:
        # The region to capture
        rect = {'top': 0, 'left': 0, 'width': WIDTH, 'height': HEIGHT}

        while 'recording':
            # Capture the screen
            img = sct.grab(rect)
            # Tweak the compression level here (0-9)
            pixels = compress(img.rgb, 6)

            # Send the size of the pixels length
            size = len(pixels)
            size_len = (size.bit_length() + 7) // 8
            conn.send(bytes([size_len]))

            # Send the actual pixels length
            size_bytes = size.to_bytes(size_len, 'big')
            conn.send(size_bytes)

            # Send pixels
            conn.sendall(pixels)


def main(host='0.0.0.0', port=5000):
    sock = socket()
    sock.connect((host, port))
    try:
        sock.listen(5)
        print('Server started.')

        while 'connected':
            conn, addr = sock.accept()
            print('Client connected IP:', addr)
            thread = Thread(target=retreive_screenshot, args=(conn,))
            thread.start()
    finally:
        sock.close()


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

客户端.py

from socket import socket
from zlib import decompress

import pygame

WIDTH = 1900
HEIGHT = 1000


def recvall(conn, length):
    """ Retreive all pixels. """

    buf = b''
    while len(buf) < length:
        data = conn.recv(length - len(buf))
        if not data:
            return data
        buf += data
    return buf


def main(host='127.0.0.1', port=5000):
    pygame.init()
    screen = pygame.display.set_mode((WIDTH, HEIGHT))
    clock = pygame.time.Clock()
    watching = True    

    sock = socket()
    sock.connect((host, port))
    try:
        while watching:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    watching = False
                    break

            # Retreive the size of the pixels length, the pixels length and pixels
            size_len = int.from_bytes(sock.recv(1), byteorder='big')
            size = int.from_bytes(sock.recv(size_len), byteorder='big')
            pixels = decompress(recvall(sock, size))

            # Create the Surface from raw pixels
            img = pygame.image.fromstring(pixels, (WIDTH, HEIGHT), 'RGB')

            # Display the picture
            screen.blit(img, (0, 0))
            pygame.display.flip()
            clock.tick(60)
    finally:
        sock.close()


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

您可以使用另一种压缩算法(如 LZ4)进行改进,该算法具有 Python 实现。您需要尝试一下:)

  • 您需要将服务器中的`connect()`更改为`bind()` (2认同)