Knowledge related to python-socket and websocket protocols

Socket, websocket communication protocol concepts

socket communication

Socket communication is based on the TCP/IP protocol and is suitable for transmitting large amounts of data and reliable connections. It is widely used in network programming, but it is not suitable for scenarios with high real-time requirements. In Python, socket and socketserver are two libraries used for network programming. The socket library provides basic network communication functions, including creating sockets, binding addresses, monitoring connections, etc. It is mainly used to implement client-side or server-side network communication. When using the socket library, you need to manually handle the sending and receiving of data, as well as error handling, etc. The socketserver library is an extension library based on the socket library. It provides more advanced network communication functions, such as multi-threading, asynchronous I/O, etc. It is mainly used to implement high-performance network servers. When using the socketserver library, it is easier to handle multiple client connections, concurrent requests, etc.

  • If you only need to implement basic client-side or server-side network communication, you can use the socket library. However, if you need to handle multiple client connections or a high-performance network server, it is recommended to use the socketserver library.

websocket protocol communication

The WebSocket protocol is a TCP-based network communication protocol that allows full-duplex communication between clients and servers. The handshake process of the WebSocket protocol requires an HTTP handshake. In Python, websocket and websockets are two libraries used to implement the WebSocket protocol. They provide bidirectional communication between client and server.

  • The websocket library is synchronous, while the websockets library is asynchronous. If you need to handle a large number of concurrent connections, the websockets library may be more suitable since it does not block the main thread.
  • The websockets library provides a cleaner API, making it easier to write WebSocket servers. However, if more control and flexibility are required, a websocket library may be more suitable.

Code example

socket case

server side

1. Create the server through the socket module

Steps:

1. Create a socket object, s=socket.socket()

2. Bind ip/port address, s.bind((ip,port)) #The parameter is a tuple

3. Listening port, s.listen()

4. Start the loop, accept the client connection (s.accept), and enable multi-thread processing of information.

import socket
import threading
import time
importsys


def socket_service():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        # s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('127.0.0.1', 6668))
        s.listen(10)
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print('Waiting connection...')

    while True:
        conn, addr = s.accept()
        t = threading.Thread(target=deal_data, args=(conn, addr))
        t.start()


def deal_data(conn, addr):
    print('Accept new connection from {0}'.format(addr))
    conn.send(('Hi, Welcome to the server!').encode())
    while 1:
        data = conn.recv(1024)
        print('{0} client send data is {1}'.format(addr,
                                                   data.decode())) # b'\xe8\xbf\x99\xe6\xac\xa1\xe5\x8f\xaf\xe4\xbb\xa5\xe4 \xba\x86'
        time.sleep(1)
        if data.decode() == 'exit' or not data:
            print('{0} connection close'.format(addr))
            conn.send(bytes('Connection closed!'), 'UTF-8')
            break
        conn.send(bytes('Hello, {0}'.format(data), "UTF-8")) # TypeError: a bytes-like object is required, not 'str'
    conn.close()


if __name__ == '__main__':
    socket_service()
2. Create the server through the socketserver module

The socketserver module is a module in the Python standard library. It provides a simple interface to easily create TCP and UDP servers, and supports multi-threading to handle client connections.

import socketserver
import threading


#Create a TCP server
class MyTCPHandler(socketserver.BaseRequestHandler):
    def handle(self):
        #Receive client data
        recv_data = self.request.recv(1024).strip()
        print(recv_data.decode())

        #Send data to client
        send_data = 'hello'
        self.request.sendall(send_data.encode())


if __name__ == '__main__':
    with socketserver.ThreadingTCPServer(('127.0.0.1', 6668), MyTCPHandler) as server:
        server_thread = threading.Thread(target=server.serve_forever)
        server_thread.start()

client

Steps:

1. Create a socket object s=socket.socket()

2. Connect to the server s.connect((ip,port)) #The parameter is a tuple

3. Send/receive messages s.send s.recv

import socket
importsys


def socket_client():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.connect(('127.0.0.1', 6668))
    except socket.error as msg:
        print(msg)
        sys.exit(1)
    print(s.recv(1024)) #The purpose is to accept
    while 1:
        data = input('please input work: ').encode()
        s.send(data)
        print('aa', s.recv(1024).decode())
        if data == 'exit':
            break
    s.close()


if __name__ == '__main__':
    socket_client()

websocket case

server side

Create the server side through the websockets module

import asyncio
import websockets
from websockets.legacy.server import WebSocketServerProtocol


async def ws_handle(websocket: WebSocketServerProtocol, path: str):
    async for message in websocket:
        print(f"The message sent by the client is: {message}")
        await websocket.send(message)
        # print("send over")

async def main():
    async with websockets.serve(ws_handle, "localhost", 8080):
        await asyncio.Future() # run forever

if __name__ == "__main__":
    asyncio.run(main())

client

1. Create a client through the websockets module:
import asyncio
import websockets


async def main():
    async with websockets.connect("ws://localhost:8080") as websocket:
        # websocket: <class 'websockets.legacy.client.WebSocketClientProtocol'>
        await websocket.send("Hello World")
        msg = await websocket.recv()
        print(msg)


asyncio.run(main())
2. Create a client through the websocket module:
import threading
import websocket

url = "ws://localhost:8080/websocket/546"

class WsClient(object):
    url = None
    ws = None

    def __init__(self, url):
        self.url = url

    def on_open(self,ws):
        print("WebSocket connection established")
        # Start receiving keyboard input through the thread and send
        t = threading.Thread(self.run())
        t.start()

    def on_message(self, ws, message):
        print("Received message from server: %s" % message)

    def on_error(self, ws, error):
        print("WebSocket connection error: %s" % error)

    def on_close(self, ws):
        print("WebSocket connection closed")

    def run(self):
        print("start run - open the thread to accept keyboard input")
        while True:
            send_msg = input("Me:")
            # print(f"The information is: {send_msg}")
            self.ws.send(send_msg)

    def start(self):
        # websocket.enableTrace(True)
        # self.ws = websocket.WebSocketApp(self.url)
        # self.ws.on_open = self.on_open
        # self.ws.on_error = self.on_error
        self.ws = websocket.WebSocketApp(self.url,
                                         on_open=self.on_open,
                                         on_message=self.on_message,
                                         on_close=self.on_close,
                                         on_error=self.on_error)
        self.ws.run_forever()


if __name__ == "__main__":
    ws = WsClient(url)
    ws.start()