我正在通過以太網將一些實時資料從相機傳輸到客戶端,在那里我使用 python 套接字和 opencv 傳輸影像。它作業正常,我可以在客戶端閱讀視頻。
問題是,當我啟動偵聽需要提要的用戶的服務器并啟動套接字流時,然后在我關閉客戶端的連接后,服務器端繼續傳輸資料。此外,關閉客戶端連接后,我只能通過重新啟動服務器來重新連接。
我已經通過從客戶端向服務器發送一條訊息來實作一種心跳協議,我收到的每 100 張影像告訴我仍在收聽 - 如果沒有收到,則回傳回圈以收聽新連接。唯一的問題是 recvfrom 是非阻塞的,因此直接實作 while 回圈可能不起作用。
我怎樣才能檢測到一個/客戶端不再讀取資料?
這是我的服務器端:
import cv2, imutils, socket
import numpy as np
import time
import base64
BUFF_SIZE = 65536
server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFF_SIZE)
host_name = socket.gethostname()
host_ip = 'xxx.xxx.xxx.xxx'
port = 4001
socket_address = (host_ip, port)
server_socket.bind(socket_address)
print("listening at", socket_address)
vid = cv2.VideoCapture(0)
WIDTH=480
while True:
msg,client_addr = server_socket.recvfrom(BUFF_SIZE)
print(client_addr)
while (vid.isOpened()):
print("sending img")
_,frame = vid.read()
frame = imutils.resize(frame,width=WIDTH)
encoded,buffer = cv2.imencode(".jpg",frame,[cv2.IMWRITE_JPEG_QUALITY,80])
message = base64.b64encode(buffer)
print(len(message))
server_socket.sendto(message,client_addr)
key = cv2.waitKey(1) & 0xFF
if key == ord('q'):
server_socket.close()
這是我的客戶端:
def video_socket_stream_client():
BUFF_SIZE = 65536
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, BUFF_SIZE)
host_name = socket.gethostname()
host_ip = 'xxx.xxx.xxx.xxx'
port = 4001
client_socket.sendto("connect".encode(),(host_ip, port)) # send signal
while True:
packet,_ = client_socket.recvfrom(BUFF_SIZE)
data = base64.b64decode(packet,' /')
npdata = np.frombuffer(data,dtype=np.uint8)
frame = cv2.imdecode(npdata,1)
time.sleep(0.016)
yield(b'--frame\r\n'b'Content-Type: image/jpeg\r\n\r\n' data b'\r\n')
uj5u.com熱心網友回復:
這是 UDP 與 TCP 的權衡之一。使用 UDP,沒有長期連接。發件人只是爆破資料并希望有人在聽。聽眾只是拿起電話,希望有人在說話。沒有持久狀態。如果發送者停止發送,則聽者將聽不到任何聲音。如果需要保持連接,那么就需要使用TCP。
您永遠不必重新啟動服務器。雙方都不知道對方在做什么。我想知道您是否因為不使用 SO_REUSEADDR 而受到影響。
uj5u.com熱心網友回復:
服務器的運行狀態可以通過getattr(socket,'_closed')的回傳值來判斷,True 為關閉狀態,False 為運行狀態。
例如
import socket
ip = 'localhost'
port = 5003
ws = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
ws.bind((ip, port))
ws.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
ws.listen()
# 關閉服務
# ws.close()
print("The status is as follows:")
if(getattr(ws, '_closed') == False):
print("Running")
elif(getattr(ws, '_closed') == True):
print("closed")
你可以試試。
uj5u.com熱心網友回復:
您可以讓客戶端在客戶端退出之前向服務器發送一個“再見”型別的資料包,讓服務器知道客戶端正在離開,但當然您不能依賴該資料包實際到達服務器(資料包可能會被丟棄,或者客戶端可能會崩潰或與網路物理斷開或以其他方式以不受控制的方式消失),因此最終您需要實作某種心跳協議。
為了同時發送 () 和接收 (),您可以使用非阻塞 I/O 和select(),或者您可以使用多個執行緒。我更喜歡這種select()方法,但任何一種方法都可以奏效。您還可以考慮升級服務器的邏輯以同時支持多個客戶端,而不是一次只支持一個客戶端;即使您實際上不需要一次發送到多個客戶端,這也將允許您的服務器處理用戶退出客戶端然后啟動一個新客戶端的情況(即服務器將能夠開始將資料包發送到新客戶端甚至在舊/死客戶端超時之前)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/399320.html
下一篇:PHP用URL替換字串中的模式
