python中的屏幕共享
嗨,我被卡住了,我在网上找不到任何有用的东西。 我正在尝试用python制作一个屏幕共享程序。 问题是我不能以至少24 fps的速度发送屏幕,因为当我用PIL(ImageGrab)截图时,有些东西会延迟。 我的客户将从服务器获取图片(屏幕截图)并“blit”到 屏幕使用pygame 服务器:python中的屏幕共享,python,sockets,pygame,screenshot,screensharing,Python,Sockets,Pygame,Screenshot,Screensharing,嗨,我被卡住了,我在网上找不到任何有用的东西。 我正在尝试用python制作一个屏幕共享程序。 问题是我不能以至少24 fps的速度发送屏幕,因为当我用PIL(ImageGrab)截图时,有些东西会延迟。 我的客户将从服务器获取图片(屏幕截图)并“blit”到 屏幕使用pygame 服务器: # -*- coding: utf-8 -*- import socket import os import threading from PIL import ImageGrab def RetrFi
# -*- 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()
#-*-编码:utf-8-*-
导入套接字
导入操作系统
导入线程
从PIL导入ImageGrab
def RetrFile(名称、sock):
而1:
img=ImageGrab.grab()
图像保存(“路径到图片”)
filename=“路径到图片”
send(str(os.path.getsize(文件名)))
以open('PATH_TO_PIC','rb')作为f:
bytesToSend=f.read(1024)
sock.send(bytesToSend)
而bytesToSend!="":
bytesToSend=f.read(1024)
sock.send(bytesToSend)
def Main():
主机='0.0.0.0'
端口=5000
s=socket.socket()
s、 绑定((主机、端口))
s、 听(5)
打印“服务器已启动”
尽管如此:
c、 addr=s.accept()
打印“客户端连接的ip:”
线程(target=RetrFile,args=(“retrThread”,c))
t、 开始()
s、 关闭()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
Main()
客户:
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()
导入套接字
导入pygame作为pg
def Main():
主机='127.0.0.1'
端口=5000
第init页()
显示屏幕=pg.display.set_模式((1900,1000))
时钟=pg.time.clock()
s=socket.socket()
s、 连接((主机、端口))
filename=“路径到图片”
isExit=False
虽然不是isExit:
对于pg.event.get()中的事件:
如果event.type==pg.QUIT:
isExit=True
数据=s.recv(1024)
打印数据
filesize=long(数据)
f=打开(文件名“wb”)
数据=s.recv(1024)
totalRecv=len(数据)
f、 写入(数据)
totalRecv<文件大小:
数据=s.recv(1024)
totalRecv+=len(数据)
f、 写入(数据)
showImg=pg.image.load('PATH\u TO\u PIC')
显示屏幕blit(显示(0,0))
pg.display.flip()
时钟滴答(60)
s、 关闭()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
Main()
基本上,我的问题是:如何在两台计算机之间共享一个屏幕,我不知道使用PIL发送大量图片的方式是否有效和正确。
有没有更有效的方法?这会投射1号计算机的屏幕,并在2号计算机上显示它?我刚刚尝试过,它似乎运行得很好(Python 3)。如果您认为这可以接受,请告诉我,我正在使用MSS模块来防止I/O server.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()
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()
client.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()
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()
从套接字导入套接字
从zlib导入解压缩
导入pygame
宽度=1900
高度=1000
def recvall(连接,长度):
“”“检索所有像素。”“”
buf=b''
而len(buf)<长度:
数据=conn.recv(长度-长度(buf))
如果没有数据:
返回数据
buf+=数据
返回buf
def干管(主机=127.0.0.1',端口=5000):
pygame.init()
screen=pygame.display.set_模式((宽度、高度))
clock=pygame.time.clock()
观看=真实
sock=socket()
sock.connect((主机、端口))
尝试:
观看时:
对于pygame.event.get()中的事件:
如果event.type==pygame.QUIT:
监视=错误
打破
#检索像素长度、像素长度和像素的大小
size\u len=int.from\u字节(sock.recv(1),byteorder='big')
size=int.from_字节(sock.recv(size_len),byteorder='big')
像素=解压缩(recvall(sock,size))
#从原始像素创建曲面
img=pygame.image.fromstring(像素,(宽度,高度),'RGB')
#显示图片
屏幕blit(img,(0,0))
pygame.display.flip()
时钟滴答(60)
最后:
sock.close()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
您可以通过使用另一种压缩算法(如LZ4)进行改进,该算法具有Python实现。您需要尝试:)对@Tiger-222的代码进行以下更改
size\u len=int.from\u字节(sock.recv(1),byteorder='big')
size=int.from_字节(recvall(sock,size_len),byteorder='big')
我制作了一个反向屏幕广播(一个测试工具),
服务器(受害者)将数据发送到客户端(攻击者)的位置
攻击者
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='192.168.1.208', port=6969):
''' machine lhost'''
sock = socket.socket()
sock.bind((host, port))
print("Listening ....")
sock.listen(5)
conn, addr = sock.accept()
print("Accepted ....", addr)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
watching = True
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(conn.recv(1), byteorder='big')
size = int.from_bytes(conn.recv(size_len), byteorder='big')
pixels = decompress(recvall(conn, 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:
print("PIXELS: ", pixels)
sock.close()
if __name__ == "__main__":
main()
对于服务器:
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='0.0.0.0', port=6969):
''' machine lhost'''
sock = socket.socket()
sock.bind((host, port))
print("Listening ....")
sock.listen(5)
conn, addr = sock.accept()
print("Accepted ....", addr)
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
clock = pygame.time.Clock()
watching = True
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(conn.recv(1), byteorder='big')
size = int.from_bytes(conn.recv(size_len), byteorder='big')
pixels = decompress(recvall(conn, 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:
print("PIXELS: ", pixels)
sock.close()
if __name__ == "__main__":
main()
我对基于python的屏幕共享脚本集很感兴趣。我不想编写低级套接字代码。我最近发现了一个有趣的消息代理/服务器,名为mosquitto()。简而言之,您可以连接到服务器并订阅主题。当代理收到关于您订阅的主题的消息时,它将向您发送该消息 下面是两个连接到mosquitto代理的脚本。一个脚本侦听屏幕抓取请求。另一个脚本请求屏幕抓取并显示它们 这些脚本依靠图像处理模块来完成繁重的工作 过程是
import paho.mqtt.client as mqtt
import time
import uuid
import cv2
import mss
from mss.tools import zlib
import numpy
import base64
import io
import pickle
monitor = 0 # all monitors
quit = False
capture = False
def on_connect(client, userdata, flags, rc):
print("Connected flags " + str(flags) + " ,result code=" + str(rc))
def on_disconnect(client, userdata, flags, rc):
print("Disconnected flags " + str(flags) + " ,result code=" + str(rc))
def on_message(client, userdata, message):
global quit
global capture
global last_image
if message.topic == "server/size":
with mss.mss() as sct:
sct_img = sct.grab(sct.monitors[monitor])
size = sct_img.size
client.publish("client/size", str(size.width) + "|" + str(size.height))
if message.topic == "server/update/first":
with mss.mss() as sct:
b64img = BuildPayload(False)
client.publish("client/update/first", b64img)
if message.topic == "server/update/next":
with mss.mss() as sct:
b64img = BuildPayload()
client.publish("client/update/next", b64img)
if message.topic == "server/quit":
quit = True
def BuildPayload(NextFrame = True):
global last_image
with mss.mss() as sct:
sct_img = sct.grab(sct.monitors[monitor])
image = numpy.array(sct_img)
if NextFrame == True:
# subsequent image - delta that brings much better compression ratio as unchanged RGBA quads will XOR to 0,0,0,0
xor_image = image ^ last_image
b64img = base64.b64encode(zlib.compress(pickle.dumps(xor_image), 9))
else:
# first image - less compression than delta
b64img = base64.b64encode(zlib.compress(pickle.dumps(image), 9))
print("Source Image Size=" + str(len(sct_img.rgb)))
last_image = image
print("Compressed Image Size=" + str(len(b64img)) + " bytes")
return b64img
myid = str(uuid.uuid4()) + str(time.time())
print("Client Id = " + myid)
client = mqtt.Client(myid, False)
client.on_connect = on_connect
client.on_disconnect = on_disconnect
client.on_message = on_message
try:
client.connect("127.0.0.1")
client.loop_start()
client.subscribe("server/size")
client.subscribe("server/update/first")
client.subscribe("server/update/next")
client.subscribe("server/quit")
while not quit:
time.sleep(5)
continue
client.publish("client/quit")
time.sleep(5)
client.loop_stop()
client.disconnect()
except:
print("Could not connect to the Mosquito server")
import paho.mqtt.client as mqtt
import time
import uuid
import cv2
import mss
from mss.tools import zlib
import numpy
import base64
import io
import pickle
quit = False
size = False
capture = False
width = 0
height = 0
last_image = None
first = False
def on_connect(client, userdata, flags, rc):
print("Connected flags " + str(flags) + " ,result code=" + str(rc))
def on_message(client, userdata, message):
global quit
global size
global capture
global width
global height
global last_image
global first
if message.topic == "client/size":
if width == 0 and height == 0:
strsize = message.payload.decode("utf-8")
strlist = strsize.split("|")
width = int(strlist[0])
height = int(strlist[1])
size = True
if message.topic == "client/update/first":
# stay synchronized with other connected clients
if size == True:
DecodeAndShowPayload(message, False)
first = True
if message.topic == "client/update/next":
# stay synchronized with other connected clients
if size == True and first == True:
DecodeAndShowPayload(message)
if message.topic == "client/quit":
quit = True
def DecodeAndShowPayload(message, NextFrame = True):
global last_image
global capture
global quit
if NextFrame == True:
# subsequent image - delta that brings much better compression ratio as unchanged RGBA quads will XOR to 0,0,0,0
xor_image = pickle.loads(zlib.decompress(base64.b64decode(message.payload.decode("utf-8")), 15, 65535))
image = last_image ^ xor_image
else:
# first image - less compression than delta
image = pickle.loads(zlib.decompress(base64.b64decode(message.payload.decode("utf-8")), 15, 65535))
last_image = image
cv2.imshow("Server", image)
if cv2.waitKeyEx(25) == 113:
quit = True
capture = False
myid = str(uuid.uuid4()) + str(time.time())
print("Client Id = " + myid)
client = mqtt.Client(myid, False)
client.on_connect = on_connect
client.on_message = on_message
try:
client.connect("127.0.0.1")
client.loop_start()
client.subscribe("client/size")
client.subscribe("client/update/first")
client.subscribe("client/update/next")
client.subscribe("client/quit")
# ask once and retain in case client starts before server
asksize = False
while not size:
if not asksize:
client.publish("server/size", "1", 0, True)
asksize = True
time.sleep(1)
first_image = True
while not quit:
if capture == False:
capture = True
if first_image:
client.publish("server/update/first")
first_image = False
else:
client.publish("server/update/next")
time.sleep(.1)
cv2.destroyAllWindows()
client.loop_stop()
client.disconnect()
except:
print("Could not connect to the Mosquito server")