0

I have created a web service using flask. Now, it turns out that I have to support some socket connections in the same app.

I tried using a specific url and then read from

request.stream

where request is

from flask import request

The data is there but I get code 400, message Bad request.

Is there anything I can do to fix that? or maybe ideas to do something else.

kechap
  • 2,077
  • 6
  • 28
  • 50
  • Are you running Flasks built-in webserver with debug=True? Might give you some debug output, because 400 is not very descriptive :). – Blubber May 23 '13 at 07:24
  • It's not entirely clear to me what you are trying to accomplish. You want to open a JS socket to your app? Or have the app open a socket to some other server? Or write some data to the socket that Flask has open to the http client? – Blubber May 23 '13 at 07:32
  • Are you trying to offer Websockets as transport medium? – Thomas Fenzl May 23 '13 at 07:32
  • No I don't want web sockets. I just want to make a view listen for incoming socket connections. – kechap May 23 '13 at 07:56

2 Answers2

1

As far as I can tell from your comment you want to listen to a socket? You should not use flask for that, it will attempt to parse HTTP headers and body (if applicable), which explains the 400 bad request.

You should take a look at the SocsketServer module.

Blubber
  • 2,214
  • 1
  • 17
  • 26
  • Ok. But can I use flask to map this server into a specific url? Example `@app.route('/socket')` and inside the view handle the socket? – kechap May 23 '13 at 09:03
  • Not unless you plan to use HTTP over that socket. That stream is not going to work for two-way communication anyway, because of wsgi and optional web-server in front of it. – Blubber May 23 '13 at 09:06
  • Now I understand why I didnt find anything like this all over the internet. – kechap May 23 '13 at 09:13
0

You can use flask-socketio: https://flask-socketio.readthedocs.io/en/latest/

from flask import Flask, render_template
from flask_socketio import SocketIO

app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
socketio = SocketIO(app)

if __name__ == '__main__':
    socketio.run(app)

It must serve a page to the client:

<script src="//cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js" integrity="sha256-yr4fRk/GU1ehYJPAs8P4JlTgu0Hdsp4ZKrx8bDEDC3I=" crossorigin="anonymous"></script>
<script type="text/javascript" charset="utf-8">
    var socket = io();
    socket.on('connect', function() {
        socket.emit('my event', {data: 'I\'m connected!'});
    });
</script>

Then handle the data via an event:

@socketio.on('my event')
def handle_my_custom_event(json):
    print('received json: ' + str(json))
    # send(json, json=True) # send data back to client
    # emit('my response', json) # another way to send data back to client
    # emit('my response', ('foo', 'bar', json)) # multiple arguments via tuple
    return 'one', 2 # yet another way to send data back to client

When defining your event, you can also receive plain string data, have arguments, etc.

@socketio.on('my_event')
def handle_my_custom_event(arg1, arg2, arg3):
    print('received args: ' + arg1 + arg2 + arg3)

If the server needs to broadcast a message without a precipitating request:

def some_function():
    socketio.emit('some event', {'data': 42})

You can also create rooms to group clients.

from flask_socketio import join_room, leave_room

@socketio.on('join')
def on_join(data):
    username = data['username']
    room = data['room']
    join_room(room)
    send(username + ' has entered the room.', room=room)

@socketio.on('leave')
def on_leave(data):
    username = data['username']
    room = data['room']
    leave_room(room)
    send(username + ' has left the room.', room=room)

And there are built-in connection events:

from flask_socketio import ConnectionRefusedError

@socketio.on('connect')
def test_connect():
    emit('my response', {'data': 'Connected'})

@socketio.on('disconnect')
def test_disconnect():
    print('Client disconnected')

@socketio.on('connect')
def connect():
    if not self.authenticate(request.args):
        raise ConnectionRefusedError('unauthorized!')

And logging/exception handling:

socketio = SocketIO(logger=True, engineio_logger=True)

@socketio.on_error()        # Handles the default namespace
def error_handler(e):
    pass

@socketio.on_error('/chat') # handles the '/chat' namespace
def error_handler_chat(e):
    pass

@socketio.on_error_default  # handles all namespaces without an explicit error handler
def default_error_handler(e):
    print(request.event["message"]) # "my error event"
    print(request.event["args"])    # (data,)
VoteCoffee
  • 4,692
  • 1
  • 41
  • 44