Search code examples
pythontcpserverclientcommunication

Python TCP server sending data without promt


I have problem developing app in python.

I need to send data from server to client without prompt, but all examples I've found on internet are echo servers.

Server should have has static IP (127.0.0.1) and save clients IP on first connection. I need to send data from server to client for example every 5 seconds (until timeout) without server waiting to be asked for that data. Of course client sends another data in its own routine.

Server script:

import socket

TCP_IP = "127.0.0.1"
TCP_PORT = 5010
BUFFER_SIZE = 512
MESSAGE = 'Hi'

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((TCP_IP, TCP_PORT))
while(1):
    s.listen()

    conn, addr = s.accept()
    print ('Connection address:', addr)
    while 1:
        data = conn.recv(BUFFER_SIZE)
        if not data: 
            break
        print ("received data: ", data.decode())
        print ("address: ", addr[0])
        conn.send(MESSAGE.encode())  # echo
    print("Closing connection")
    conn.close()

and Client script:

import socket
import sys
import logging
import time

HOST, PORT = "127.0.0.1", 5010
data = " ".join(sys.argv[1:])

for x in range(100):
    # Create a socket (SOCK_STREAM means a TCP socket)
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
        # Connect to server and send data
        sock.connect_ex((HOST, PORT))
        sock.sendall(bytes(data + "\n", "utf-8"))

        # Receive data from the server and shut down
        received = str(sock.recv(1024), "utf-8")
sock.close()
logging.info("Socket closed")

print("Sent:     {}".format(data))
print("Received: {}".format(received))
print("Size: ", sys.getsizeof(received), "bytes")

time.sleep(5)

I would really appreciate every help.


Solution

  • Example in which server keeps connection and sends data every 5 seconds. At the same time server keeps connection and receives data in loop. But it blocks server and client and loops should work in separated threads

    server:

    import socket
    import time
    import datetime
    
    
    TCP_IP = "127.0.0.1"
    TCP_PORT = 5010
    BUFFER_SIZE = 512
    MESSAGE = 'Hi'
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP, TCP_PORT))
    
    s.listen() # it can be before loop
    
    while True:
    
        conn, addr = s.accept()
        print ('Connection address:', addr)
        while True:
            data = conn.recv(BUFFER_SIZE)
            if not data: 
                break
            print ("received data: ", data.decode())
            print ("address: ", addr[0])
            conn.send(MESSAGE.encode())  # echo
    
            # send data every 5 seconds - it should run in separated thread   
            while True:
                time.sleep(5)
                conn.send(str(datetime.datetime.now()).encode())
    
        print("Closing connection")
        conn.close()
    

    client

    import socket
    import sys
    import logging
    import time
    
    HOST, PORT = "127.0.0.1", 5010
    data = " ".join(sys.argv[1:])
    
    for x in range(100):
        # Create a socket (SOCK_STREAM means a TCP socket)
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            # Connect to server and send data
            sock.connect_ex((HOST, PORT))
            sock.sendall(bytes(data + "\n", "utf-8"))
    
            # Receive data from the server and shut down
            received = str(sock.recv(1024), "utf-8")
    
            print("Sent:     {}".format(data))
            print("Received: {}".format(received))
            print("Size: ", sys.getsizeof(received), "bytes")
    
            # receive data periodically - it should run in thread
            while True:
                received = str(sock.recv(1024), "utf-8")
                print("Received: {}".format(received))
    
    
    sock.close()
    logging.info("Socket closed")
    

    EDIT: version with threading. And with queue to send message to thread and stop it

    server - classic construction. It can work with many clients at the same time

    import socket
    import time
    import datetime
    import threading
    
    # --- functions ---
    
    def process_client(conn, addr):
        print('Connection address:', addr)
    
        data = conn.recv(BUFFER_SIZE)
        if not data: 
            return
    
        print("received data: ", data.decode())
        print("address: ", addr[0])
        conn.send(MESSAGE.encode())
    
        # send data every 5 seconds
        while True:
            time.sleep(5)
            conn.send( str(datetime.datetime.now()).encode() )
    
        conn.close()
    
    # --- main ---
    
    TCP_IP = "127.0.0.1"
    TCP_PORT = 5011
    BUFFER_SIZE = 512
    MESSAGE = 'Hi'
    
    #all_threads = []
    
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((TCP_IP, TCP_PORT))
    
    s.listen() # it can be before loop
    
    while True:
        print('wait for next client')
        conn, addr = s.accept()
    
        t = threading.Thread(target=process_client, args=(conn, addr))
        t.start()
        #all_threads.append(t)
    
    #for t in all_threads: t.join()    
    print("Closing connection")
    s.close()
    

    client - socket in thread so program can do other things

    import socket
    import sys
    import logging
    import time
    import threading
    import datetime
    import queue
    
    # --- functions ---
    
    def receive_data(q):
    
        # Create a socket (SOCK_STREAM means a TCP socket)
        with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
            # Connect to server and send data
            sock.connect_ex((HOST, PORT))
            sock.sendall(bytes(data + "\n", "utf-8"))
    
            # Receive data from the server and shut down
            received = str(sock.recv(1024), "utf-8")
    
            print("Sent:     {}".format(data))
            print("Received: {}".format(received))
            print("Size: ", sys.getsizeof(received), "bytes")
    
            # receive data periodically - it should run in thread
            while True:
                received = str(sock.recv(1024), "utf-8")
                print("Received: {}".format(received))
    
                if not q.empty() and q.get() == 'stop':
                    break 
    
        # sock.close() # doesn't need if you use `with ... as sock`
        print("Socket closed")
    
    # --- main ---
    
    HOST, PORT = "127.0.0.1", 5011
    data = " ".join(sys.argv[1:])
    
    q = queue.Queue()
    t = threading.Thread(target=receive_data, args=(q,))
    t.start()
    
    # other code
    
    #while True:
    for x in range(10):
        print('    Local time:', datetime.datetime.now())
        time.sleep(1)
    
    q.put("stop") # message to thread to stop it
    
    #t.join()
    

    It would need some try/except (ie. to catch Cltr+C and stop threads) and code which stop threads.


    BTW: some examples from other my answers furas/python-examples/socket (on GitHub)