I am using web sockets to connect the client & server for video transferring. I encountered the following error
client.py :
import cv2
import utils.utils as utils
import cv2
import websocket
import _thread
import socket
# initialize the camera
cap = cv2.VideoCapture(0)
def on_message(ws, message):
print(f"Message: {message}")
def on_error(ws, error):
print(f"Error: {error}")
def on_close(ws):
print("Connection closed.")
def on_open(ws, client_ip):
print("Connection opened.")
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
if not ret:
print("Could not read the frame from the camera.")
break
# encode the frame in JPEG format
_, jpg_image = cv2.imencode('.jpg', frame)
# send the IP address and the frame to the server
message = client_ip + jpg_image.tobytes()
ws.send(message, opcode=websocket.ABNF.OPCODE_BINARY)
if __name__ == '__main__':
websocket.enableTrace(True)
network = utils.config_parse(utils.current_path(), 'NETWORK')
ip = network['server_ip']
port = network['server_port']
url = f"ws://{ip}:{port}/video_feed"
print("URL", url)
ws = websocket.WebSocketApp(url,
on_message=on_message,
on_error=on_error,
on_close=on_close)
client_ip = socket.gethostbyname(socket.gethostname())
ws.on_open = lambda ws: on_open(ws, client_ip)
_thread.start_new_thread(ws.run_forever, ())
server.py:
from flask_sockets import Sockets
from flask import Flask, request
import cv2
import numpy as np
app = Flask(__name__)
sockets = Sockets(app)
connected_cameras = {}
#sockets.route('/video_feed')
def video_feed(ws):
# store the IP address of the client in a dictionary
print("hello")
client_ip = request.remote_addr
connected_cameras[client_ip] = ws
while True:
message = ws.receive()
if message is None:
break
# display the message (frame) using cv2
frame = cv2.imdecode(np.frombuffer(message, np.uint8), cv2.IMREAD_COLOR)
cv2.imshow('frame', frame)
cv2.waitKey(1)
if __name__ == '__main__':
from gevent.pywsgi import WSGIServer
from geventwebsocket.handler import WebSocketHandler
server = WSGIServer(('', 5000), app, handler_class=WebSocketHandler)
server.serve_forever()
Server Started Successfully, And when i run client.py file i am getting the output as :
URL ws://127.0.0.1:5000/video_feed
--- request header ---
GET /video_feed HTTP/1.1
Upgrade: websocket
Host: 127.0.0.1:5000
Origin: http://127.0.0.1:5000
Sec-WebSocket-Key: qFGzaooYmrXF3FZbj08XHA==
Sec-WebSocket-Version: 13
Connection: Upgrade
-----------------------
--- response header ---
& in the server side :
[2023-02-14 02:43:10 +0530] [97197] [INFO] Starting gunicorn 20.1.0
[2023-02-14 02:43:10 +0530] [97197] [INFO] Listening at: http://0.0.0.0:5000 (97197)
[2023-02-14 02:43:10 +0530] [97197] [INFO] Using worker: sync
[2023-02-14 02:43:10 +0530] [97208] [INFO] Booting worker with pid: 97208
[2023-02-14 02:43:19 +0530] [97208] [ERROR] Error handling request /video_feed
Traceback (most recent call last):
File "/home/mnk/python3/envs/pytorch/lib/python3.10/site-packages/gunicorn/workers/sync.py", line 136, in handle
self.handle_request(listener, req, client, addr)
File "/home/mnk/python3/envs/pytorch/lib/python3.10/site-packages/gunicorn/workers/sync.py", line 179, in handle_request
respiter = self.wsgi(environ, resp.start_response)
File "/home/mnk/python3/envs/pytorch/lib/python3.10/site-packages/flask/app.py", line 2548, in __call__
return self.wsgi_app(environ, start_response)
File "/home/mnk/python3/envs/pytorch/lib/python3.10/site-packages/flask_sockets.py", line 40, in __call__
handler, values = adapter.match()
File "/home/mnk/.local/lib/python3.10/site-packages/werkzeug/routing/map.py", line 622, in match
raise WebsocketMismatch() from None
werkzeug.routing.exceptions.WebsocketMismatch: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
It would be helpful if anyone helps me solve this in production env using "gunicorn" or suggest me any other methods for same use case
Related
I made such a minimal example that completely repeats the behavior of my code. I make requests from firefox and chrome. I noticed that after making a request from chrome, firefox ceases to receive answers. After some research, I realized that the server response with error on localhost:8000/favicon.ico path request. After receiving error 404 once, chrome after each response from server creates another connection to the server, but does not send data, which causes a lock on the recv function.
File "/usr/lib/python3.7/socket.py", line 589, in readinto
return self._sock.recv_into(b)
I found that I can set the connection timeout for the handler class, it is taken into account in the StreamRequestHandler:r:
if self.timeout is not None:
self.connection.settimeout(self.timeout)
But I am embarrassed that there is no information about this in the documentation
https://docs.python.org/3/library/socketserver.html#socketserver.BaseRequestHandler.handle
import logging
import json
import http.server
from http import HTTPStatus
from typing import Optional
from urllib.parse import urlparse, parse_qs
import socketserver
from threading import Thread
import traceback
from functools import wraps
import sys, os
project_dir = os.path.abspath(os.curdir)
sys.path.append(project_dir)
logging.getLogger().setLevel("DEBUG")
class RESTHandler(http.server.BaseHTTPRequestHandler):
"""
Rest router for api methods
"""
def __init__(self, *args, **kwargs):
logging.info(f"Creating RESTHandler obj. Args: {args}, kwargs: {kwargs}")
super().__init__(*args, **kwargs)
def end_headers(self) -> None:
self.send_header('Access-Control-Allow-Origin', '*')
http.server.BaseHTTPRequestHandler.end_headers(self)
# noinspection PyPep8Naming
def do_GET(self):
logging.info(self.path)
url = urlparse(self.path)
if "favicon.ico" in url.path:
self.send_error(HTTPStatus.NOT_FOUND, message='Unknown api path.')
return
self.send_response(HTTPStatus.OK)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"resp":"I am OK", "int": 5}, ensure_ascii=False).encode('utf-8'))
class ApiService():
DEFAULT_API_PORT = 8000
DEFAULT_API_HOST = ''
def __init__(self, ui_service = None, host: Optional[str] = None, port: Optional[int] = None):
self.ui_service = ui_service
self.host = host or self.DEFAULT_API_HOST
self.port = port or self.DEFAULT_API_PORT
def _run(self):
while True:
try:
with socketserver.TCPServer((self.host, self.port), RESTHandler, bind_and_activate=False) as httpd:
logging.info("Starting server....")
httpd.allow_reuse_address = True
httpd.server_bind()
httpd.server_activate()
logging.info(f"Serving API at {self.host}:{self.port}")
httpd.serve_forever()
break
except Exception as e:
tb_list = traceback.format_exception( type(e), e, tb=e.__traceback__)
tb_list = [ s.replace("\n", "") for s in tb_list ]
tb_str = "; ".join(tb_list)
logging.error(f"Unexpected exception while http-server was working: {tb_str}")
def run(self, in_thread=True):
if in_thread:
t = Thread(target=self._run)
t.start()
else:
self._run()
if __name__ == '__main__':
ApiService().run(in_thread=False)
I guess, Chrome uses web browsers pre-opening sockets, on which TCPServer would wait indefinitely in my case. But I am still interesting why only after 404 and what about legitimacy of using timeout of request handler.
In file transfer server-client program I want to access my server from html webpage and for that I'm using flask. But I can't connect flask with file transfer server to send and receive data. So what are the ways to access my file transfer server from flask server?
I tried to use TCP sockets for connection between flask and file transfer server but it ended up having error in connection
#FLASK SERVER
from flask import Flask, flash, redirect, render_template, request, session, abort
import sqlite3
import socket
app = Flask(__name__)
#app.route('/list',methods = ['POST', 'GET'])
def list():
socket_create()
socket_connect()
db_conn = sqlite3.connect('Backup_File.db')
if request.method == 'POST':
cursor = db_conn.execute('SELECT id, Mac_address, port_number from Client_List')
rows = cursor.fetchall()
for row in rows:
print("ID:",row[0])
print("Mac Address:",row[1])
print("Port number:",row[2])
return render_template('list.html',rows = rows)
#app.route('/clientAccess',methods = ['POST', 'GET'])
def clientAccess():
if request.method == 'POST':
return render_template('clientAccess.html')
#Connect to a server
# Create a socket
def socket_create():
try:
global host
global port
global source_port
global s
host = '192.168.0.30'
port = 9993
source_port = 9000
s = socket.socket()
except socket.error as msg:
print("Socket creation error: " + str(msg))
# Connect to a remote socket
def socket_connect():
try:
global host
global port
global source_port
global s
os.system("freeport 9000")
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('0.0.0.0', 9000))
s.connect((host, 9993))
except socket.error as msg:
print("Socket connection error: " + str(msg))
if __name__ == '__main__':
app.debug = True
app.run(host = '0.0.0.0',port=5005)
I expect the output that sending 'list' from flask server, the file transfer server should receive 'list' as string
I am trying to learn some Http Server in an udacity online academy. The thing is that the folllowing code is triggering the error Message: Unsupported method ('POST'). Error 501 Python:
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import parse_qs
class MessageHandler(BaseHTTPRequestHandler):
def do_POST(self):
# 1. How long was the message?
length = int(self.headers.get('Content-length', 0))
# 2. Read the correct amount of data from the request.
data = self.rfile.read(length).decode()
# 3. Extract the "message" field from the request data.
message = parse_qs(data)["message"][0]
# Send the "message" field back as the response.
self.send_response(200)
self.send_header('Content-type', 'text/plain; charset=utf-8')
self.end_headers()
self.wfile.write(message.encode())
if __name__ == '__main__':
server_address = ('', 8000)
httpd = HTTPServer(server_address, MessageHandler)
httpd.serve_forever()
Which Python? Your code is correct. Tested it right now, it sends the response.
The only modification I've made is
#message = parse_qs(data)["message"][0]
message = 'hello'
Client code:
import requests
res = requests.post('http://localhost:8000/abc', data = {'key':'value'})
print(res)
Client gets 200 response
I was trying to create a simple http server in python.
The following is the code that I wrote:
from http.server import BaseHTTPRequestHandler, HTTPServer
from os import curdir, sep
PORT_NUMBER = 8080
class MyHandler(BaseHTTPRequestHandler):
def do_Get(self):
print(self.path)
value = ''
send_reply = False
if self.path.endswith(".html"):
send_reply = True
value = "text/html"
if send_reply:
f = open(curdir + sep + self.path)
self.send_response(200)
self.send_header('Content type', value)
self.end_headers()
self.wfile.write(f.read())
f.close()
else:
self.send_error(404, "File not Found")
return
try:
server = HTTPServer(('', PORT_NUMBER), MyHandler)
print("Server started")
server.serve_forever()
except Exception as e:
print(e)
server.socket.close()
When I try to run the above python file and go to http://localhost/hello.html, I get the following message:
code 501, message Unsupported method ('GET')
"GET /favicon.ico HTTP/1.1" 501 -
What am I doing wrong?
I was able to find the issue. The method inside my class should be do_GET instead of do_get
I'm want to POST a file from a python3 client to cherrypy. I'm using the requests library.
My client code:
import requests
url = 'http://127.0.0.1:8080/upload'
files = {'file.zip': open('file.zip', 'rb')}
r = requests.post(url, files=files)
My server code:
import os
import tempfile
import shutil
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8,
'server.max_request_body_size' : 0,
'server.socket_timeout' : 60
}
}
class App:
#cherrypy.config(**{'response.timeout': 3600})
#cherrypy.expose()
def upload(self):
'''Handle non-multipart upload'''
destination = os.path.join('/home/uvv/upload')
with open(destination, 'wb') as f:
shutil.copyfileobj(cherrypy.request.body, f)
return 'Okay'
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
The server returns an error:
127.0.0.1 - - [17/Aug/2016:11:38:49] "POST /upload HTTP/1.1" 400 2083 "" "python-requests/2.10.0"
It's usefull to get information from response. When you send a request, you receive a response. From this response you can get information about HTTP code where 200 means OK and 400 means bad request. That's the text you can see in your cherrypy log: POST /upload HTTP/1.1" 400. To get more information, print the response text using print(r.text)
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import requests
url = 'http://127.0.0.1:9090/upload'
files = {'ufile': open('file.txt', 'rb')}
r = requests.post(url, files=files)
print(r)
print(r.text)
If you use the code above with the code bellow, it's working example of uploading file to cherrypy server.
#!/usr/bin/env python
# -*- coding: UTF-8 -*-
import os
import cherrypy
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 9090,
'server.thread_pool' : 8,
'server.max_request_body_size' : 0,
'server.socket_timeout' : 60
}
}
class App:
#cherrypy.expose
def upload(self, ufile):
upload_path = os.path.normpath('/path/to/project/data/')
upload_file = os.path.join(upload_path, ufile.filename)
size = 0
with open(upload_file, 'wb') as out:
while True:
data = ufile.file.read(8192)
if not data:
break
out.write(data)
size += len(data)
out = '''
length: {}
filename: {}
mime-type: {}
''' .format(size, ufile.filename, ufile.content_type, data)
return out
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
Replace the path /path/to/project/data/ to path that fits your project.