I open a socket which sends and receives data on a socket. I have the following code shown below to open a socket and then send information.
# Socket Information
host = "localhost"
port = 6800
# Initailize the socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))
# Method to send the data on the socket
# This method is called periodically every 5 seconds to send the data
def send_data():
sock.send((request_string).encode("utf-8"))
The issue that I am currently facing. I want to be able to continuously listen
for data and I am unsure on how to do it. I dont want to be blocking the other parts of my code as I am listening on the port. Do I need to do the listen on another thread? Is it just a simple while(1)
loop which listens on the same port 6800
.
Any help for the implementation of the listen method would be appreciated.
Example which use Thread
to handle client so listen()
can wait for another client. It is popular solution and you should see it in some tutorials for Python
or even for C
.
server.py
import struct
import socket
import sys
import threading
import time
# --- constants ---
HOST = '' # local address IP (not external address IP)
# '0.0.0.0' or '' - conection on all NICs (Network Interface Card),
# '127.0.0.1' or 'localhost' - local conection only (can't connect from remote computer)
# 'Local_IP' - connection only on one NIC which has this IP
PORT = 8000 # local port (not external port)
# --- functions ---
def handle_client(conn, addr):
data = conn.recv(1024)
#request_string = data.decode("utf-8")
try:
while True:
conn.send(data)
#conn.send(request_string.encode("utf-8"))
time.sleep(5)
except BrokenPipeError:
print('[DEBUG] addr:', addr, 'Connection closed by client?')
except Exception as ex:
print('[DEBUG] addr:', addr, 'Exception:', ex, )
finally:
conn.close()
# --- main ---
#all_threads = []
try:
# --- create socket ---
print('[DEBUG] create socket')
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket() # default value is (socket.AF_INET, socket.SOCK_STREAM) so you don't have to use it
# --- options ---
# solution for "[Error 89] Address already in use". Use before bind()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# --- assign socket to local IP (local NIC) ---
print('[DEBUG] bind:', (HOST, PORT))
s.bind((HOST, PORT)) # one tuple (HOST, PORT), not two arguments
# --- set size of queue ---
print('[DEBUG] listen')
s.listen(1) # number of clients waiting in queue for "accept".
# If queue is full then client can't connect.
while True:
# --- accept client ---
# accept client and create new socket `conn` (with different port) for this client only
# and server will can use `s` to accept other clients (if you will use threading)
print('[DEBUG] accept ... waiting')
conn, addr = s.accept() # socket, address
print('[DEBUG] addr:', addr)
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
#all_threads.append(t)
except Exception as ex:
print(ex)
except KeyboardInterrupt as ex:
print(ex)
except:
print(sys.exc_info())
finally:
# --- close socket ---
print('[DEBUG] close socket')
s.close()
#for t in all_threads:
# t.running = False # it would need to build own class Thread
# t.join()
And now you can run client's code many times at the same time and all of them will get data from server.
client.py
import struct
import socket
import sys
# --- constants ---
HOST = '' # (local or external) address IP of remote server
PORT = 8000 # (local or external) port of remote server
try:
# --- create socket ---
print('[DEBUG] create socket')
#s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s = socket.socket() # default: socket.AF_INET, socket.SOCK_STREAM
# --- connect to server ---
print('[DEBUG] connect:', (HOST, PORT))
s.connect((HOST, PORT)) # one tuple (HOST, PORT), not two arguments
# --- send data ---
print('[DEBUG] send')
text = 'Hello World of Sockets in Python'
print('[DEBUG] text:', text)
# convert text to bytes
data = text.encode('utf-8')
print('[DEBUG] data:', data)
# get data length
length = len(data)
print('[DEBUG] length:', length)
# convert `length` int to 4 bytes
#length = struct.pack('!i', length)
print('[DEBUG] length as 4 bytes:', length)
# send `length` as 4 bytes
#s.send(length)
# send data as bytes
s.send(data)
while True:
print(s.recv(1024))
except Exception as ex:
print(ex)
except KeyboardInterrupt as ex:
print(ex)
except:
print(sys.exc_info())
finally:
# --- close socket ---
print('[DEBUG] close socket')
s.close()
There are so many comments because I took example code from my GitHub and add Thread
: furas/python-examples/socket/simple-protocol
EDIT: Client uses thread to run while
loop with send()
and at the same time it runs while
loop with recv()
in main loop.
import socket
import sys
import threading
import time
# --- constants ---
HOST = ''
PORT = 8000
# --- functions ---
def sender(s):
print('sender')
while True:
s.send(data)
print('send:', data)
print('--- sleep ---')
time.sleep(3)
# --- main ---
data = b''
try:
s = socket.socket()
s.connect((HOST, PORT))
text = 'Hello World of Sockets in Python'
data = text.encode('utf-8')
threading.Thread(target=sender, args=(s,)).start()
print('receiver')
while True:
temp = s.recv(1024)
if temp:
data = temp
print('recv:', data)
except Exception as ex:
print(ex)
except KeyboardInterrupt as ex:
print(ex)
except:
print(sys.exc_info())
finally:
print('[DEBUG] close socket')
s.close()
Server which use thread
to handle client.
import socket
import sys
import threading
import time
import datetime
# --- constants ---
HOST = ''
PORT = 8000
# --- functions ---
def handle_client(conn, addr):
try:
while True:
data = conn.recv(1024)
print('recv:', data)
data = str(datetime.datetime.now()).encode()
conn.send(data)
print('send:', data)
print('--- sleep ---')
time.sleep(1)
except BrokenPipeError:
print('[DEBUG] addr:', addr, 'Connection closed by client?')
except Exception as ex:
print('[DEBUG] addr:', addr, 'Exception:', ex, )
finally:
conn.close()
# --- main ---
try:
print('[DEBUG] create socket')
s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
print('[DEBUG] bind:', (HOST, PORT))
s.bind((HOST, PORT))
print('[DEBUG] listen')
s.listen(1)
while True:
print('[DEBUG] accept ... waiting')
conn, addr = s.accept()
print('[DEBUG] addr:', addr)
t = threading.Thread(target=handle_client, args=(conn, addr))
t.start()
except Exception as ex:
print(ex)
except KeyboardInterrupt as ex:
print(ex)
except:
print(sys.exc_info())
finally:
print('[DEBUG] close socket')
s.close()