how do i get socket to accept more than one connection? - python

Currently I have a socket server that can only accept ONE connection. Any second connection, it just hangs and not do anything.
The server can get the message send from one client. I have the server to send back confirmation only for now.
server.py:
import socket, sys
# some vars
HOST = "localhost";
PORT = 4242;
# create the socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
# bind the socket to port
server_addr = (HOST, PORT);
print >>sys.stderr, "starting server %s on port %s" % (HOST, PORT);
soc.bind(server_addr);
# check for connections
soc.listen(1);
while True:
# wait for a connection
connection, client_address = soc.accept();
try:
# since just test
# just send back whatever server receives
while True:
data = connection.recv(16);
if data:
connection.sendall(str(client_address[1]) + " said " + data);
finally:
connection.close();
client.py:
import socket, sys, thread
# some vars
HOST = "localhost";
PORT = 4242;
# create the socket
soc = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
# connect to server/port
server_addr = (HOST, PORT);
print >>sys.stderr, "connecting to %s on port %s" % (HOST, PORT);
soc.connect(server_addr);
# try to send data over
while True:
try:
# send the message
msg = raw_input("Message: ");
soc.sendall(msg);
# check if there is response
amt_recd = 0;
amt_expd = len(msg);
while amt_recd < amt_expd:
data = soc.recv(16);
amt_recd += len(data);
print >>sys.stderr, data, "\n";
finally:
msg = '';

There is no exit condition from this infinite loop in the server:
while True:
data = connection.recv(16)
if data:
connection.sendall(str(client_address[1]) + " said " + data)
If the client closes the connection data will be empty, but it will still continue looping. To fix:
while True:
data = connection.recv(16)
if not data:
break
connection.sendall(str(client_address[1]) + " said " + data)
Also, even after fixing this the server can only handle one connection at a time. If you desire to service multiple clients at once, you'll need to use select.select or spin off threads for each client connection.
As an aside, Python does not require semicolons at the end of statements.

Related

Python3 - [Errno 32] Broken Pipe while using sockets

I have the following code for the server:
import socket
import threading
def handle_client(client_socket):
request = client_socket.recv(1024)
print ("[*] Received: %s" % request)
client_socket.send("ACK!".encode("utf-8"))
client_socket.close()
bind_ip = "0.0.0.0"
bind_port = 9998
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((bind_ip, bind_port))
server.listen(5)
print ("[*] Listening on %s:%d" % (bind_ip, bind_port))
while True:
client, addr = server.accept()
print ("[*] Accepted connection from: %s:%d" % (addr[0], addr[1]))
client_handler = threading.Thread(target = handle_client, args = (client))
client_handler.start()
And the following on the client side:
def client_sender(buffer):
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target, port))
if len(buffer) > 0:
client.send(buffer.encode("utf-8"))
data = client.recv(4096).decode("utf-8")
print(" - " + data)
while True:
buffer = input("Input:")
buffer += "\n"
client.send(buffer.encode("utf-8"))
data = client.recv(4096).decode("utf-8")
print (" - " + data)
The function client_sender is called by another function where I can choose if listen incoming connection or send data to someone.
I will call it in this way:
python3 filename.py -ip 0.0.0.0 -port 9998
I can then write some data. The first time I do it I press CTRL + D to send it and the server gets and the client gets the response.But when I try to send some data from inside the "While True" loop the server never gets it and I receive this:
client.send(buffer.encode("utf-8"))
BrokenPipeError: [Errno 32] Broken pipe
How do I solve it? The only solution I found that works is to move these two lines inside the "While True" loop:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect((target, port))
However it seems inefficient to me to re-connect every time.
EDIT
As suggested by Sam Mason, changing the handle_client in the following way solves the problem:
def handle_client(client_socket):
while True:
request = client_socket.recv(1024).decode("utf-8")
if len(request):
print ("[*] Received: %s" % request)
client_socket.send("ACK!".encode("utf-8"))
else:
client_socket.close()
break
your server is closing the port immediately after a single recv. I'd suggest changing your handle_client code to have some sort of while loop that ends when recv returns an empty string (this indicates the client has shutdown their end of the connection, probably by closeing their connection)

Send sensor data over socket communication (TCP/IP) between Pi's with python

Hello everyone,
I have a problemen with some socket communication coding. I have two pi's communicating over TCP/IP with python scripts. The idea is that one pi (client)reads temperature/humidity sensor data and sends it over to the other pi (server), where it will be stored in a SQLite database. In the future I want multiple pi's (clients) sends over sensor data to one (web)server with database to display data on a local website.
I have written some python code for server and client side and it works pretty well. If I start the server side it will listen for other connections. When I start the client side it will generate sensor data and send it to the server. The server receives the data. But when I want to close to connection to make room for (a future other pi) it terminates completely the script and don't listens for new "calls". See code below for both sides. Code is written in Python2.7.
Goal of this project: Within a zoo setting monitor and log multiple exhibits and aquariums on temperature and humidity, display the information on LCD in every exhibit, use LED as warning, and have a central-server to store/log data, that is displayed with a central computer.
RaspiServer - server-side
import socket
from LED import callLED
host = ''
port = 5560
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
except socket.error as msg:
print(msg)
print("Socket bind complete.")
return s
def setupConnection():
s.listen(1)
conn, address = s.accept()
print("Connected to: " + address[0] + ":" + str(address[1]))
return conn
def dataTransfer(conn):
while True:
data = conn.recv(1024)
data = data.decode('utf-8')
dataMessage = data.split(":", 2)
command = dataMessage[0]
humidity = dataMessage[1]
temperature = dataMessage[2]
if command == 'DATA':
print("Received: " + humidity + " : " + temperature)
callLED()
elif command == 'EXIT':
print("Disconnected with Client")
break
else:
reply = 'Unknow Command'
conn.sendall(str.encode(reply))
Print("Reply has been send.")
conn.close()
s = setupServer()
while True:
try:
conn = setupConnection()
dataTransfer(conn)
except:
break
On the client-side there are three python scripts, where the main python scripts communicate with other scripts. I have decides to split it in multiple script to use them also as stand-alone (blinking LED, display data on LCD etc.).
RaspiMonitor - client-side
Run this script on client-side
from time import sleep
from client_sensordata import GetTemp
from monitor_client import transmit
sleepTime = 20
def tempMonitorServer():
humidity, temperature = GetTemp()
temp = str(temperature)
hum = str(humidity)
message = "DATA:" + hum + ":" + temp
print("Transmitting Data.")
response = transmit(message)
print(response)
while True:
tempMonitorServer()
sleep(sleepTime)
Use this script to send and receive data over TCP/IP
import socket
host = '192.168.2.3'
port = 5560
def setupSocket():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((host, port))
return s
def sendReceive(s, message):
s.send(str.encode(message))
print("Message transmitted")
reply = s.recv(1024)
print("We have received a reply.")
print("Send closing message.")
s.send(str.encode("EXIT"))
s.close()
reply = reply.decode('utf-8')
return reply
def transmit(message):
s = setupSocket()
response = sendReceive(s, message)
return response
Use this script to retrieve sensor data
def GetReading():
import sys
import Adafruit_DHT
humidity, temperature = Adafruit_DHT.read_retry(Adafruit_DHT.DHT22, 17)
if humidity is not None and temperature is not None:
print('Reading sensor data')
return humidity, temperature
else:
print('no sensor data')
def GetTemp():
humidity, temperature = GetReading()
name = "DHT22Client1"
print('Read sensor: {0} humidity: {1:0.2f}% temperature: {2:0.2f}C'.format(name, humidity, temperature))
return humidity, temperature
Terminal output
Terminal output, left server and right the client
Could anyone give some tips or help, or tell me why how to fix this problemen? I searched already multiple threads and other posts, but can't find the solution.
Thanks in advance for every help you give.
You have may few error in your server socket setup. The way a server socket works is it should be always open listening for new connection. When you accept a connection from the client(s.accept), it create a connection to the client. If you close that connection , it should not impact the server listening to incomming socket, The number of client or conn to client is limited only by the number you specify in the server socket.listen(NUMBER). When that number is reached, incoming connection will be rejected.
def setupServer():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print("Socket created.")
try:
s.bind((host, port))
s.listen(5)
except socket.error as msg:
print(msg)
print("Socket bind complete.")
return s
Then remove s.listen from setup connection()
I also suggests that you handle data transfer() in a new thread to be able to process incoming connection concurrently insted of consecutive.
Here is a reference: https://docs.python.org/2/howto/sockets.html
Rather than closing and opening new sockets repeatedly, I would suggest maintaining multiple open socket connections server side and handling each socket using the select() method.
https://docs.python.org/2/library/select.html
https://pymotw.com/2/select/
Can a server handle multiple sockets in a single thread?
The code that works for now (still under construction for adding more functionalities) is:
Server-side
import socket
import sys
from LED import callLED
from monitor_log3 import ExtractStoreData
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the port
server_address = ('', 5560)
print >>sys.stderr, 'Starting up on %s port %s' % server_address
sock.bind(server_address)
# Listen for incoming connections
sock.listen(1)
while True:
# Wait for a connection
print >>sys.stderr, 'Waiting for a connection'
connection, client_address = sock.accept()
try:
print >>sys.stderr, 'Connection from', client_address
# Receive the data in small chunks and retransmit it
while True:
data = connection.recv(1024)
data = data.decode('utf-8')
message = data
if data:
print >>sys.stderr, 'Send data receive confirmation'
connection.sendall(data)
callLED()
ExtractStoreData(message)
else:
print >>sys.stderr, 'No more data from', client_address
break
finally:
# Clean up the connection
print >>sys.stderr, 'Closing connection'
print >>sys.stderr, '------------------'
connection.close()
And the client-side looks like this:
Client-side
import socket
import sys
import datetime
from time import sleep
from client_sensordata import GetTemp
timeSleep = 10
def ClientSocket():
# Create a TCP/IP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect the socket to the port where the server is listening
server_address = ('192.168.2.3', 5560)
print >>sys.stderr, 'Connecting to: %s port: %s' % server_address
sock.connect(server_address)
try:
# Send data
name, humidity, temperature = GetTemp()
Sensorname = str(name)
temp = str(temperature)
hum = str(humidity)
print(Sensorname + ":" + temp + ":" + hum)
message = (Sensorname + ":" + temp + ":" + hum)
print("Transmitting data...")
print >>sys.stderr, 'Sending data...'
sock.send(str.encode(message))
# Look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = sock.recv(1024)
amount_received += len(data)
print >>sys.stderr, 'Send data'
finally:
print >>sys.stderr, 'Closing connection'
print >>sys.stderr, '------------------'
sock.close()
while True:
print("Start external server measurement at " + datetime.datetime.now().strftime("%H:%M:%S"))
ClientSocket()
sleep(timeSleep)
for t2 in range(5):
print("Start internal display measurement at " + datetime.datetime.now().strftime("%H:%M:%S"))
GetTemp()
print("------------------")
sleep(timeSleep)
It is looping 5 cyclus for internal measurement (for on a LCD display) and then send the data once to the server, that will store it in the database (SQlite3). Still want to add more functionalities (LED when reading, warning LED when under or above limits, alarm sound, LCD connected. When there is progress I'll update the code.
Offcourse any tips and sugestions are more then welcome!

An operation was attempted on something that is not a socket (tried fixing a lot)

Before you say this is a duplicate, I have looked at many articles on this and still can't fix it.
I am making a very basic chat client and server python program.
However after connecting through my client, it says 'Connected' on the server console, but disconnects immediately on the chat one with the error 'OSError: [WinError 10038] An operation was attempted on something that is not a
socket'
CHAT
def chat_client():
if(len(sys.argv) not in (3, 4)):
print("Usage: python chat_client.py <hostname> <port> <optional-username>\n")
sys.exit()
host = sys.argv[1]
port = int(sys.argv[2])
username = ""
if len(sys.argv) == 4:
username = sys.argv[3]
else:
username = "Guest"
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(2)
# Connect to remote host
try:
s.connect((host, port))
except:
print("Unable to connect")
sys.exit()
print("Connected to remote host. You can start sending messages")
print("*** Press Control-C to log off ***\n")
sys.stdout.write("[" + username + "] ")
sys.stdout.flush()
while True:
socket_list = [sys.stdin, s]
try:
# Get the list sockets which are readable
ready_to_read, ready_to_write, in_error = select.select(socket_list, [], [])
except KeyboardInterrupt:
system("clear")
sys.stdout.write("\nYou have logged off\n")
sys.stdout.flush()
sys.exit()
SERVER
HOST = ""
SOCKET_LIST = []
RECV_BUFFER = 4096
PORT = 9009
CONVERSATION = ""
def chat_server():
global CONVERSATION
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((HOST, PORT))
server_socket.listen(10)
# Add server socket object to the list of readable connections
SOCKET_LIST.append(server_socket)
print("Chat server started on port " + str(PORT))
while True:
try:
# Get the list sockets which are ready to be read through select
# 4th arg, time_out = 0 : poll and never block
ready_to_read, ready_to_write, in_error = select.select(SOCKET_LIST, [], [], 0)
for sock in ready_to_read:
# A new connection request recieved
if sock == server_socket:
sockfd, addr = server_socket.accept()
SOCKET_LIST.append(sockfd)
print("Client (%s, %s) connected" % addr)
broadcast(server_socket, sockfd, "[%s, %s] entered our chatting room\n" % addr)
# A message from a client, not a new connection
else:
# Process data recieved from client
try:
# Recieving data from socket
data = sock.recv(RECV_BUFFER)
if data:
# there is something in the socket
# broadcast(server_socket, sock, "\r" + '[' + str(sock.getpeername()) + '] ' + data) # old
broadcast(server_socket, sock, "\r" + data)
else:
# Remove the socket that's broken
if sock in SOCKET_LIST:
SOCKET_LIST.remove(sock)
# at this stage, no data probably means the connection has been broken
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
except:
broadcast(server_socket, sock, "Client (%s, %s) is offline\n" % addr)
continue
except KeyboardInterrupt:
server_socket.close()
sys.exit()
server_socket.close()
# broadcast chat messages to all connected clients
def broadcast(server_socket, sock, message):
for socket in SOCKET_LIST:
# send the message only to peer
if socket != server_socket and socket != sock:
try:
socket.send(message)
except:
# Broken socket connection
socket.close()
# Broken socket, remove it
if socket in SOCKET_LIST:
SOCKET_LIST.remove(socket)
if __name__ == "__main__":
sys.exit(chat_server())
From select's documentation:
File objects on Windows are not acceptable, but sockets are. On
Windows, the underlying select() function is provided by the WinSock
library, and does not handle file descriptors that don’t originate
from WinSock.
This rules out using sys.stdin.
Alternatives:
Use Cygwin (No modifications to code needed)
Create a thread that waits on sys.stdin (like here)
Go the full Windows route and use WaitForMultipleObjects
Use some library that abstracts these details away, I like libuv but haven't used it with python
Another thing: Don't use select with a zero timeout in an infinite loop. This busy waiting is really inefficient. Instead omit the timeout to have select block till a descriptor becomes ready.

TCP Proxy Using Python

I am studying Black Hat Python and trying to understand the TCP proxy code.
I now almost understand it, but it doesn't quite work when I try to test it with
python proxy.py localhost 21 ftp.target.ca 21 True
in one terminal and
ftp ftp.target.ca 21
in another.
In the first terminal, I get only listen on localhost on port 21 and nothing else; and in the second terminal, it's happen connection between me and server and I wrote username and password.
The packages that transfer between me and server should appear in the first terminal.
What am I doing wrong?
Here is the code:
import sys
import socket
import threading
# this is a pretty hex dumping function directly taken from
# http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src, unicode) else 2
for i in xrange(0, len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
text = b''.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
print b'\n'.join(result)
def receive_from(connection):
buffer = ""
# We set a 2 second time out depending on your
# target this may need to be adjusted
connection.settimeout(2)
try:
# keep reading into the buffer until there's no more data
# or we time out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except:
pass
return buffer
# modify any requests destined for the remote host
def request_handler(buffer):
# perform packet modifications
return buffer
# modify any responses destined for the local host
def response_handler(buffer):
# perform packet modifications
return buffer
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
# connect to the remote host
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))
# receive data from the remote end if necessary
if receive_first:
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
# send it to our response handler
remote_buffer = response_handler(remote_buffer)
# if we have data to send to our local client send it
if len(remote_buffer):
print "[<==] Sending %d bytes to localhost." % len(remote_buffer)
client_socket.send(remote_buffer)
# now let's loop and reading from local, send to remote, send to local
# rinse wash repeat
while True:
# read from local host
local_buffer = receive_from(client_socket)
if len(local_buffer):
print "[==>] Received %d bytes from localhost." % len(local_buffer)
hexdump(local_buffer)
# send it to our request handler
local_buffer = request_handler(local_buffer)
# send off the data to the remote host
remote_socket.send(local_buffer)
print "[==>] Sent to remote."
# receive back the response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print "[<==] Received %d bytes from remote." % len(remote_buffer)
hexdump(remote_buffer)
# send to our response handler
remote_buffer = response_handler(remote_buffer)
# send the response to the local socket
client_socket.send(remote_buffer)
print "[<==] Sent to localhost."
# if no more data on either side close the connections
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print "[*] No more data. Closing connections."
break
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host,local_port))
except:
print "[!!] Failed to listen on %s:%d" % (local_host,local_port)
print "[!!] Check for other listening sockets or correct permissions."
sys.exit(0)
print "[*] Listening on %s:%d" % (local_host,local_port)
server.listen(5)
while True:
client_socket, addr = server.accept()
# print out the local connection information
print "[==>] Received incoming connection from %s:%d" % (addr[0],addr[1])
# start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))
proxy_thread.start()
def main():
# no fancy command line parsing here
if len(sys.argv[1:]) != 5:
print "Usage: ./proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]"
print "Example: ./proxy.py 127.0.0.1 9000 10.12.132.1 9000 True"
sys.exit(0)
# setup local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
# setup remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
# this tells our proxy to connect and receive data
# before sending to the remote host
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
# now spin up our listening socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
main()
Simply running a proxy server on port 21 won't make the ftp client use it - so you shouldn't be trying to connect to the remote host. if the commandline is running the proxy on for example 9000, then ftp to that port i.e. localhost 9000 and the proxy will forward communication to/from that remote host.

multiple clients cannot listen and write at the same time

I'm writing a very basic chat room in python. Clients connect and any message from a client is relayed to all clients. The problem I'm having is getting the client to listen and send messages at the same time. It seems to only do either one. I've set up a separate listening client and confirmed that the message is received but the listening server cannot send anything.
Currently the client has to send data before getting a response from the server, but I want clients to be able to receive data before sending - otherwise the chat room won't work. I attempted using clientsock.settimeout() and then use recv but it did not solve the issue as it did not move past the input part.
server.py
#!/usr/bin/python
#socket server using threads
import socket, sys, threading
from _thread import *
HOST = 'localhost'
PORT = 2222
lock = threading.Lock()
all_clients = []
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print ("Socket created")
#bind socket to local host and port
try:
s.bind((HOST, PORT))
except socket.error as msg:
print ("Bind failed. Error code: " + str(msg[0]) + ' Message ' + msg[1])
sys.exit(0)
print ("Socket bind complete")
#Start listening on socket
s.listen(5)
print ("Socket now listening")
#function for handling connections. This will be used to create threads
def clientthread(conn):
#sending message to connected client
conn.send("Welcome to the server. Type something and hit enter\n".encode('utf-8'))
#infinite loop so that function does not terminate and thread does not end
while True:
#receiving data from client
data = conn.recv(1024)
reply = "OK..." + str(data, "utf-8")
if not data:
break
with lock:
for c in all_clients:
c.sendall(reply.encode('utf-8'))
#came out of loop
conn.close()
#keep talking with the client
while 1:
#wait to accept a connection - blocking call
conn, addr = s.accept()
with lock:
all_clients.append(conn)
print ("Connected with " + addr[0] + ":" + str(addr[1]))
#start new thread takes 1st argument as a function name to be run, second
#is the tuple of arguments to the function
start_new_thread(clientthread ,(conn,))
s.close()
client.py
#!/usr/bin/python
import socket, sys
#client to transfer data
def main():
#create tcp stocket
clientsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
#connect the socket to the server open port
server_address = ('localhost', 2222)
print ("connecting to %s port %s" % server_address)
clientsock.connect(server_address)
#receive data
data = clientsock.recv(1024)
print(str(data, "utf-8"))
while 1:
#send data
message = "sean: " + input()
clientsock.send(message.encode('utf-8'))
#look for the response
amount_received = 0
amount_expected = len(message)
while amount_received < amount_expected:
data = clientsock.recv(1024)
amount_received += len(data)
print ("received %s " % data)
print ("closing socket")
clientsock.close()
main()
new_client.py
#!/usr/bin/python
import socket, sys
from threading import Thread
#client for chat room
def send_msg(sock):
while True:
data = input()
sock.send(data.encode('utf-8'))
def recv_msg(sock):
while True:
stuff = sock.recv(1024)
sock.send(stuff)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_address = ('localhost', 2222)
sock.connect(server_address)
print("Connected to chat")
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()
Create two threads, one for receiving the other for sending. This is the simplest way to do.
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect("address")
def send_msg(sock):
while True:
data = sys.stdin.readline()
sock.send(data)
def recv_msg(sock):
while True:
data, addr = sock.recv(1024)
sys.stdout.write(data)
Thread(target=send_msg, args=(sock,)).start()
Thread(target=recv_msg, args=(sock,)).start()

Categories