Summary of websocket implemented by python -- wspy
Previously, we had a websocket package for php. For more information, see Websocket-php practice. Recently, we used python to perform some functions and needed websocket operations. Therefore, refer to the previous implementation, this python version is implemented. For the source code, see https://github.com/oshynsong/wspy.
To achieve the overall implementation, you need to establish a socket listening port, which requires the socket standard library module; then, you need to operate on the network byte stream. In this regard, python has the struct standard library module, this is very easy to use. In addition, it involves encryption and decryption, as well as hashlib and sha modules. In particular, the main purpose is
1Memo
2.Conclusion and consideration
1 socket operation 1 Local Socket Creation
General process for establishing a TCP Server:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)sock.bind((addr,port))sock.listen(10)
Establish a local socket and bind the address and port to listen.
2. Concurrent connection Policy
Then, you need to use different policies to deal with the problem of multiple client connections. The most common solution is to directly use accept to block connections, so that the server can only process one client connection at a time. Then, the python Standard Library provides the select module, which contains the processing policies for different concurrent connections such as select, poll, and epoll. Poll and epoll can only be used in linux, and epoll can only be used in Versions later than linux 2.6. Of course, for the concurrent processing effect, epoll has better performance than poll, and poll has better performance than select. However, the select statement can be used on multiple platforms. to be compatible with the Windows system, the select policy is used in this implementation. The details are as follows:
... # Connect to the above socket Establishment Code while True: rs, ws, es = select. select ([sock], [], []) for r in rs: if r is sock: # r is the server socket cliSock, addr = r. accept () r. connect (cliSock) # established on the client to connect else: try: data = r. recv (bufferLen )... # process the data sent by the client connection...
The poll method is also a method in the select module, which is easier to use than the select method. First, use poll to create a poll object, and then use its register method to register a file descriptor. The unregister method can remove the registered object. You can call the poll method to obtain a list of (fd, event) formats. fd is a file descriptor and event represents an event. Event is a bitmask. You can use constants of the select module to perform bitwise operations.
The constant of the polling event in the select module:
Event name |
Description |
POLLIN |
Read data from file descriptors |
POLLPRI |
Read emergency data from file descriptors |
POLLOUT |
File descriptor data is ready and can be written without blocking |
POLLERR |
File descriptor-related errors |
POLLHUP |
Suspended, lost connection |
POLLNVAL |
Invalid request, connection not opened |
The following is the sample code for using a poll policy:
... # Connect to the above socket to establish the code fdmap = {sock. fileno (): s} p = select. poll () p. register (sock) while True: events = p. poll () for fd, event in events: if fd in fdmap: # local socket c, addr = sock. accept () print 'connectedfrom', addr p. register (c) fdmap [c. fileno ()] = c elif event & select. POLLIN: data = fdmap [fd]. recv (buffer )... # data operation elif event & select. POLLERR: # Disconnect p. unregister (fd) del fdmap [fd] ......
2 Struct processing byte data
This standard library module is used to convert the interaction between python data values and C-style data types, especially binary files and network bytes. Main Methods:
Struct. pack (fmt, v1, v2 ...)
Struct. pack_into (fmt, buffer, offset, v1, v2 ...) (Pack v1 and v2 values to the position after the buffer string starts with offset in fmt Format)
Struct. unpack (fmt, string)
Struct. unpack_from (fmt, buffer [, offset = 0])
Struct. calcsize (fmt) (calculate the length of fmt)
The above is mainly the method of directly using the struct module, each fmt needs to be performed independently, if you need to reuse, you can use the struct class provided by Struct, after using fmt to instantiate the Struct object, similar methods can be called for reuse. In this way, object calling has better performance and is more efficient than directly using the preceding method.
Pack (v1, v2 ...)
Pack_into (buffer, offset, v1, v2 ...)
Unpack (string)
Unpack_from (buffer, offset = 0)
Format: returns the fmt string used to instantiate the Struct object.
Size: returns the length of the fmt string.
Use of the most critical format string.
The first is the byte order:
Character |
Byte order |
Size |
Alignment |
@ |
Native |
Native |
Native |
= |
Native |
Standard |
None |
< |
Little-endian |
Standard |
None |
> |
Big-endian |
Standard |
None |
! |
Network (= big-endian) |
Standard |
None |
Then, the format uses special characters, as shown in the following table:
Format |
C Type |
Python type |
Standard size |
X |
Pad byte |
No value |
|
C |
Char |
String of length 1 |
1 |
B |
Signed char |
Integer |
1 |
B |
Unsigned char |
Integer |
1 |
? |
_ Bool |
Bool |
1 |
H |
Short |
Integer |
2 |
H |
Unsigned short |
Integer |
2 |
I |
Int |
Integer |
4 |
I |
Unsigned int |
Integer |
4 |
L |
Long |
Integer |
4 |
L |
Unsigned long |
Integer |
4 |
Q |
Long |
Integer |
8 |
Q |
Unsigned long |
Integer |
8 |
F |
Float |
Float |
4 |
D |
Double |
Float |
8 |
S |
Char [] |
String |
|
P |
Char [] |
String |
|
P |
Void * |
Integer |
|
3. encryption and decryption
The hashlib standard library module provides all common encryption and decryption hash methods, using:
Hashlib. update (arg): update the hash object using the arg string. Multiple calls are equivalent to connecting all arg strings together.
Hashlib. digest (): returns the hash value of the string uploaded to the update method.
Hashlib. hexdigest (): returns the hexadecimal string representation of the hash value.
Hashlib. copy (): returns a copy of the hash value.
In the handshake phase of websocket, You need to obtain the client key, then use sha1 and base64 for encryption, and then send it to the client for handshake.
sha1Encrypt = sha1(key + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11').digest() acceptKey = base64.b64encode(sha1Encrypt)
In general, it is very convenient to use python to implement these operations, which is more concise than php, highlighting the essence of the concise python language!