Simple data exchange between client and server over IP.

The data is stored in a Struct and then packed to be sent as binary data. fmt is the description of the struct content. In the client-server example below fmt = '!I30sd': the ! refers to the byte-order convenction (big-endian for nework in this case), I stands for unsigned-int (4 bytes), 30s stands for 30 char (1 byte each) and d stands for a double (8 bytes).

Line can be initialized both as a client and as a server. The server application must be launched before the client. When data is sent, the listener application runs the function action with the data received as first argument. actionargs can be used to share variables (in the example below it is used for a queue object).

import socket
import struct

class Line(object):
    def __init__(self, fmt='!I2sd', server=True, action=None, actionargs=[], ip='localhost', port=10000):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.server_address = (ip, port)
        self.s = struct.Struct(fmt)
        self.action = action
        self.actionargs = actionargs
        if not((type(self.actionargs) is list) or (type(self.actionargs) is tuple)):
            self.actionargs = (self.actionargs,)

        if server:
            self.sock.bind(self.server_address)
            self.sock.listen(1)
            self.connection, client_address = self.sock.accept()
        else:
            CONNECTION_ATTEMPTS = 5
            for i in range(CONNECTION_ATTEMPTS):
                try:
                    self.sock.connect(self.server_address)
                    print("Connected with server.")
                    break
                except:
                    import time
                    print("Connection attempt "+str(i+1)+" of 5 failed.")
                    SLEEP_BETWEEN_CONNECTION_ATTEMPTS = 1
                    time.sleep(SLEEP_BETWEEN_CONNECTION_ATTEMPTS)
            self.connection = self.sock

        if self.action:
            import threading
            listener_thread = threading.Thread(target=self.listener)
            listener_thread.start()

    def listener(self): 
        while True:
            dataByte = self.connection.recv(self.s.size)
            if dataByte:
                self.action(self.s.unpack(dataByte), *self.actionargs)              

    def send(self, message):
        self.connection.sendall(self.s.pack(*message))

    def __exit__(self):
        self.sock.close()

Server:

import queue
import threading
import time
import ipcomm

def c_fun(data, jobs):
    jobs.put(data)
jobs = queue.Queue()

def process_job(q):
    while True:
        a,b,c = q.get()
        for i in range(a):
            print(str(i)+": "+b.decode('utf-8'))
            time.sleep(c)

fmt='!I30sd'
myServer = ipcomm.Line(fmt=fmt, server=True, action=c_fun, actionargs=jobs)
pj = threading.Thread(target=process_job, args=(jobs,))
pj.setDaemon(True)
pj.start()

Client:

import ipcomm

fmt='!I30sd'

myClient = ipcomm.Line(fmt=fmt, server=False)
while(True):
    a = int(input("\nNumber of repetition: "))
    b = input("String to write: ").encode('utf-8')
    c = float(input("Sleep time (s): "))
    myClient.send((a, b, c))
    print(" >>>>>> Struct sent to the client >>>>>>")

server_client_example