Asynchronous web server framework work with sockets directly, supporting HTTP and WebSocket protocol.
Asynsrv is an asyncio-based asynchronous web server framework developed entirely using the python standard library with no dependencies. asynsrv currently supports both HTTP and WebSocket protocols, allowing for simpler code to control all the details of a web request. It was originally developed to support the Kancolle server emulation project for highly customizable response messages and integration of HTTP and WebSocket protocols.
- Simple code, easy to modify and deploy, suitable for lightweight tasks
- Supports highly customizable responses for HTTP and WebSocket
- Friendly data format, completely using dictionary as data transfer method
- Full use of asynchronous programming, maintaining multiple connections through a single thread
Server can be started with the following code
def fun(req, dict)
... ...
return msg, dict
s=asynsrv.server('localhost', 11456)
s.start(fun, dict)
-
asynsrv.server
: Used to initialize the server, including specifying the listening port and creating a new asynchronous event loop -
asynsrv.start(fun, dict)
: Used to start accepting connections, accept a function parameterfun
and an optional dictionary parameterdict
, defaults to an empty dictionary -
fun
: Function type, used to process requests and responses, accept two inputsreq
anddict
and return two dictionary type variablesmsg
anddict
-
dict
: Dictionary type, used to store information required by programs and frameworks. Can be updated viafun
as needed, such as adding shared data for multiple connections. If no updates,fun
should return the same dictionary as the input. In the following example, all uppercase keys are internal parameters of the framework and should not be modified, and lowercase keys are parameters required by the program.{ 'SVRIP': 'localhost', 'SVRPORT': 1080, 'WS': {}, ... ... 'param1': 1, 'param2': 2, }
-
req
: Dictionary type, containing request information, see below -
msg
: Dictionary type, containing the information that needs to be sent, see below
Asynsrv will pass the http request to fun
in the form of a dictionary with the parameter req
, which usually has the following structure
req = {
'addr': ('127.0.0.1', 33342),
'method': 'GET',
'target': '/',
'version': 'HTTP/1.1',
'Host': 'localhost:1080',
'Connection': 'keep-alive',
'Content-Length': 0,
'Accept': 'image/avif,image/webp',
'body': '',
}
addr
represents the client address, method
, target
and version
are originally the status line of request, body
is the message body in request, and the rest of the keys are request headers.
For key Connection
, if value is keep-alive
and not modified in response (see below), asynsrv will treat this address as a persistent connection and sets a timeout exercise limit of 5 seconds.
Asynsrv generates and sends messages through msg
returned by func. msg
usually has the following structure
{
'version': 'HTTP/1.1',
'code': '200',
'text': 'OK',
'body': b'',
}
Status line is generated by version
, code
and text
, response header is generated by all key-value pairs except key body
, and message body is generated by body
, asynsrv will automatically calculate the length of message body and add Content-Length
in response header.
msg
does not need to contain the complete information of response. The simplest msg
can be an empty dictionary. Asynsrv will complete the values โโof key version
, code
and text
with default value 'HTTP/1.1'
, '200'
, 'OK'
. In addition, if msg
does not specify key Connection
, asynsrv will use key Connection
in the request header to complete, and if there is no key Connection
in request header, close
will be used as the value.
If request is WebSocket handshake request, body
in msg
will be ignored, if you want to block the websocket connection, you can include the key AUTH
in the msg, see below.
Generally, asynsrv will format all key-value pairs in msg
and send it out, except for some special keys. For example, making msg
contain 'AUTH': 0
can prevent response from being sent, and asynsrv will send a 404 error response. The default value of AUTH
is 1, which means response is sent normally. The key AUTH
itself will not be sent as response header.
There are also some key-value pairs related to websocket that will not be sent, see below for details.
After the handshake through http protocol, asynsrv will add a key-value pair addr: conn
to key WS
in dict
, where addr
is the websocket client address and conn
is a socket object.
The dictionary req
passed into fun
in websocket contains the information sent by the client, usually with the following structure
{
'addr': ('127.0.0.1', 33342),
'FIN': 1,
'RSV': 0,
'opcode': 1,
'MASK': 1,
'length': 0,
'KEY': b'\xce\xc5\xc2\x86',
'body': '',
}
FIN
identifies whether the message ends, 1 indicates the end of the message, 0 indicates there is follow-up data. RSV
is the decimal representation of RSV1
, RSV2
, and RSV3
in the websocket protocol, which is used for expansion, and OPCODE
is a four-digit binary decimal representation, which is used to indicate the message reception type. MASK
is used to identify whether the data is masked or not. KEY
is the mask, body
is the decoded message body.
Asyncsrv generates and sends websocket messages via the msg
returned by func
. A simplest msg
has the following structure
{
'body': 'message',
}
Required parameters that are not specified will be automatically filled in. The default value is
{
'FIN': 1,
'RSV': 1,
'opcode':1,
'body': b'',
}
The websocket connection will be closed if msg
is empty. If the received websocket message is a ping request, it will respond directly without passing in func
.
Asyncsrv supports two ways to push messages from the server, one is polling, by including key PUSH
in msg
, the value of PUSH
is the polling interval. After each specified time, the previous msg
will be passed to func
to get the new msg
. msg
returned after each poll should contain PUSH
to keep polling, polling will be closed if there is no key PUSH
.
Another way is to push the websocket message at the same time when sending the http response, which is achieved by including key WSPUSH
in msg
. The value of WSPUSH
should be a dictionary with the following structure
{
'localhost:5000': {'body':'message'},
'localhost:5001': {'body':'message'},
}
demo.py
is a server based on Asyncsrv, the default listening address is localhost:6655
, localhost:6655/
is a Hello World page, localhost:6655/ws
contains a websocket client, server will return all the messages entered by the user in this page. The server will return the current time every five seconds if the user enters Time 5
. If user visits 'localhost:6655/' while maintaining the websocket connection, server will push the helloworld
message to all online websocket clients