Python通过Socket向Android传输摄像头Base64视频流仅一帧后冻结问题
问题原因
- Android端在循环内每次接收一帧就重新创建Socket连接,未复用已建立的TCP连接。旧连接断开后Python端仍持续向失效连接发送数据,TCP发送缓冲区被占满后
send操作进入永久阻塞,直接导致Python程序冻结。同时Android端每次新建连接只会拉取一帧数据,因此仅能显示首帧画面。 - Python端错误将UDP专用的
sendto方法用于TCP套接字,且未处理客户端断开连接的异常,连接失效后无法退出内层循环回到监听状态。 - 未校验摄像头读取结果:
vid.read()可能读取失败返回空帧,后续resize操作会直接触发崩溃。
修复方案
Python端修改
替换原有main函数逻辑,核心修改点:异常捕获处理断开的连接、替换sendto为send、校验帧有效性、连接断开后主动关闭客户端套接字。
def main(): server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 开启端口复用,避免重启程序时端口占用 server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) vid = cv2.VideoCapture(0) host_ip = "192.168.100.20" print('IP DEL HOST:', host_ip) port = 9999 socket_address = (host_ip, port) server_socket.bind(socket_address) server_socket.listen(5) print("LUGAR DE ESCUCHA: ", socket_address) try: while True: client_socket, addr = server_socket.accept() print('CONEXIÓN ENTRANTE:', addr) WIDTH = 400 try: while True: ret, img = vid.read() # 校验帧读取是否成功 if not ret: break frame = imutils.resize(img,width=WIDTH) cv2.imshow("Android_cam", frame) encoded,buffer = cv2.imencode('.jpeg',frame,[cv2.IMWRITE_JPEG_QUALITY,50]) message = base64.b64encode(buffer) size = len(message) # TCP直接用send发送,不需要sendto client_socket.send((str(size) + "\n").encode('utf-8')) client_socket.send(message) client_socket.send(("\nhappy face\n").encode('utf-8')) if cv2.waitKey(1) == 27: break except (BrokenPipeError, ConnectionResetError): # 客户端断开连接,正常退出内层循环 print(f"客户端{addr}断开连接") finally: # 主动关闭客户端套接字 client_socket.close() cv2.destroyAllWindows() except KeyboardInterrupt: print('Finalizado') finally: server_socket.close() vid.release() cv2.destroyAllWindows()
Android端修改
核心修改点:将Socket创建移到循环外复用连接、异常时主动关闭资源。
public class actualizar extends AsyncTask<String, Bitmap, String> { @RequiresApi(api = Build.VERSION_CODES.O) @Override protected String doInBackground(String... params) { Log.i("hola","Running"); Socket socket = null; BufferedReader mBufferIn = null; try { // 仅创建一次Socket,复用连接 socket = new Socket(IP_HOST,PORT); mBufferIn = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)); boolean XD = true; while(XD){ String sizeStr = mBufferIn.readLine(); if (sizeStr == null) break; int size = Integer.parseInt(sizeStr); String base64Str = mBufferIn.readLine(); if (base64Str == null) break; // 按实际长度截取有效base64内容 String validBase64 = base64Str.substring(0,size); byte[] decodedString = Base64.decode(validBase64, Base64.DEFAULT); Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length); this.publishProgress(decodedByte); // 读取分隔符 String happyFace = mBufferIn.readLine(); if (happyFace == null || !happyFace.equals("happy face")) { break; } } } catch (IOException e) { e.printStackTrace(); } finally { // 主动关闭资源 try { if (mBufferIn != null) mBufferIn.close(); if (socket != null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } @Override protected void onProgressUpdate(Bitmap... values) { super.onProgressUpdate(values); imgShow.setImageBitmap(values[0]); } }
内容的提问来源于stack exchange,提问作者Javier Muñoz Martín del Campo
相关产品推荐
相关产品推荐

