pythonsocketsserver-side

How to make a fast continuous stream of data with socket on Python?


I am writing a code where an arduino reads data from an accelerometer, passes it to a python script and then that computer running python sends the data to another computer over a socket conneciton. I have written code which can send and recieve one message at a time, slowly, but as soon as I do it bascially as fast as I can (about 100Hz) then the server side only prints the first message, but no more.

Here is the code for my server side:

import socket


class server:

    def __init__(self, PORT=9077, MAX_CONNECTIONS=1000, BUFF_SIZE=1024):
        self.s = socket.socket()
        self.HOST = socket.gethostbyname(socket.gethostname())
        self.PORT = PORT
        self.MAX_CONNECTIONS = MAX_CONNECTIONS
        self.BUFF_SIZE = BUFF_SIZE
        self.s.bind((self.HOST, self.PORT))
        self.s.listen(self.MAX_CONNECTIONS)
        self.recievingData = False
        
        print("Starting a server")
        print("IP: " + str(self.HOST))
        print("Port: " + str(self.PORT))

    def recieveData(self):
        self.recievingData = True
        while self.recievingData:
            print("Waiting for data")
            c, addr = self.s.accept()
            print(addr)
            data = b''
            part = c.recv(self.BUFF_SIZE)
            data += part
            while len(part) > self.BUFF_SIZE:
                # print("looping")
                part = c.recv(self.BUFF_SIZE)
                print(len(part))
                data += part
            print(data)
            c.close()

    def stopRecieving(self):
        self.revievingData = False
            
    
    new_server = server()
    new_server.recieveData()

and the client side:

class client:
    
    def __init__(self, HOST="192.168.0.51", PORT=9077):
        self.s = socket.socket()
        self.HOST = HOST
        self.PORT = PORT
        self.s.connect((self.HOST, self.PORT))

    def send_message(self, message):
        message = message.encode()
        sent = self.s.sendall(message)
        print(sent)

and I basically just call send_message every time there is new data to send.

Is there a way to increase the speed at which the server can recieve messages from the same client? Do I need to create multiple threads for recieving data?


Solution

  • My solution to this was using UDP protocol, where you send messages without checking if the data has been recieved. This is achieved using socket.socket(type=SOCK_DGRAM) on the client and server side and using self.s.recvfrom(self.BUFF_SIZE) for recieving data from a client and self.s.sendto(str(message).encode(), (host, port)) for sending data. This way, there is no handshake between the client and the server and it runs much faster.

    You just need some error checking from your input data.

    For reference, this is my full updated code:

    import socket
    from socket import SOCK_DGRAM, SO_REUSEADDR
    import numpy as np
    import threading
    
    class client:
        
        def __init__(self, HOST="192.168.0.51", PORT=9077):
            self.s = socket.socket(type=SOCK_DGRAM)
            self.HOST = HOST
            self.PORT = PORT
    
        def send_message(self, message):
            self.s.sendto(str(message).encode(), (host, port))
    
    class server:
    
        def __init__(self, PORT=9077, BUFF_SIZE=1024):
            self.s = socket.socket(type=SOCK_DGRAM)
            self.HOST = socket.gethostbyname(socket.gethostname())
            self.PORT = PORT
            self.MAX_CONNECTIONS = MAX_CONNECTIONS
            self.BUFF_SIZE = BUFF_SIZE
            self.s.bind((self.HOST, self.PORT))
            # self.s.listen(self.MAX_CONNECTIONS)
            self.recievingData = False
            self.recievedData = np.zeros((1,4))
            
            self.thread = threading.Thread(target=self.recieveData)
            self.thread.start()
            # self.s.setblocking(0)
            self.startRecieving()
            
            print("Starting a server")
            print("IP: " + str(self.HOST))
            print("Port: " + str(self.PORT))
    
        def startRecieving(self):
            self.recievingData = True
            self.recievedData = np.zeros((1,4))
            self.thread = threading.Thread(target=self.recieveData)
            self.thread.start()
            print("Started reading data")
        
        def stopRecieving(self):
            self.recievingData = False
            self.thread.join()
            print("Stopped reading data")
    
    
        def recieveData(self):
            self.recievingData = True
            while self.recievingData:
                # print("Waiting for data")
                part, addr = self.s.recvfrom(self.BUFF_SIZE)
                # print(part, addr)
                data = b''
                data += part
                while len(part) > self.BUFF_SIZE:
                    # print("looping")
                    part = self.s.recvfrom(self.BUFF_SIZE)
                    # print(len(part))
                    data += part
                self.lastData = data
                print(data)
                as_float = np.array([[float(x.strip()) for x in data.decode().split(',')]])
                self.recievedData = np.vstack((self.recievedData, as_float))