I am trying to design a multithreaded server. client1 send data to server and server forwards data to client2 for processing. client2 sends processed data to server and then server forwards it to client1.
Data from client1 is received by client2 through server while execution, but my server program after sending data to client2 terminates with error
[10054] An existing connection was forcibly closed by remote host.
client1.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
data=raw_input("Input lowercase :: ")
while data!="#close":
s.send(data)
data=raw_input("Input next word or type #close to exit: ")
s.close()
client2.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
s=socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
m=s.recv(1024)
k=m.upper()
print "Uppercase of ",m," in System--> ",k
s.close()
server.py
from socket import *
import thread
ip='127.1.1.2'
port=5554
data=''
def multi_threading(c,a):
while True:
global data
print "Inside client 1 thread"
data= c.recv(1024)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
def multi_threading2(c,a):
while True:
print "Inside client 2 thread"
c.send(data)
if not data:
break
if "close"==data.rstrip():
break
c.close()
print a,"--terminates connection"
if __name__=='__main__':
s=socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count=0
while True:
print "Server is listening on port number ",port
c,a=s.accept()
count=count+1
print "--------------------------------------------------"
print "Server connected to system having ip address --> ",a
if(count==1):
thread.start_new_thread(multi_threading,(c,a))
else:
thread.start_new_thread(multi_threading2,(c,a))
What i might be doing wrong?
I'm trying to help by changing your code as little as possible. It isn't how I would write it but should allow you to follow along. This is also not very idomatic Python. I just want you to see how to get the basic interaction going.
Some comments about my changes:
Remove the indent in client1.py so you don't always close the
socket with s.close(). I suspect this was a typo in your post?
In server.py it isn't safe to access the global data between two
threads. At the very least you need a semaphore to protect it.
Every time around multi_threading loop you destroy the last value of
data. You need to append the incoming bytes to a data structure
like a list. I renamed the threads to make it easier to understand.
You are expecting to see close in the server but you don't ever send this because your loop terminates when you type #close. You need to adjust for this.
Your code is order dependent because both client 'sender' and client 'receiver' use the same port. You need to put something into the protocol to distinguish between these two roles so you can start them in either order. This makes the system more robust.
Due to the sender not necessarily having any data I do a crude sleep. This can be avoided by using a shared queue between the threads which would block one end
You need some framing because you can't guarantee the speed at which the independent processes send and receive to the socket. I use \n for this.
There is an edge case if you sent very large strings (and removed the 1024 read) you could not get a full word with the \n through. I ignore this case.
I adjust the loopback address
I wrote this in PyCharm CE. I recommend using an IDE (PyCharm is excellent) with breakpoints. You can step through all the processes bit by bit. Put breakpoints in the threads and step through the actions.
Result:
server.py
from socket import *
import thread
from threading import Lock
import time
ip = '127.0.0.1'
port = 5554
data = []
data_lock = Lock()
def multi_threading_recv(sock, a):
should_run = True
while should_run:
global data
print "Inside client 1 thread"
_data = sock.recv(1024)
if _data:
with data_lock:
for word in _data.split('\n'):
data.append(word)
if "#close" == word:
should_run = False
break
else:
break
sock.close()
print a, "--terminates connection"
def multi_threading_send(sock, a):
while True:
print "Inside client 2 thread"
with data_lock:
if len(data) == 0:
time.sleep(1) # Not ideal. Ideally block on a shared queue
continue
else:
_data = data.pop(0)
if _data == "#close":
break
sock.send(_data + '\n')
c.close()
print a, "--terminates connection"
if __name__ == '__main__':
s = socket(AF_INET, SOCK_STREAM)
s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
s.bind((ip,port))
s.listen(4)
count = 0
while True:
print "Server is listening on port number ", port
c, a = s.accept()
print "--------------------------------------------------"
print "Server connected to system having ip address --> ", a
role = c.recv(4)
if role == 'PUSH':
thread.start_new_thread(multi_threading_recv, (c, a))
elif role == 'PULL':
thread.start_new_thread(multi_threading_send, (c,a))
else:
print('invalid role: ' + role)
c.close()
client1.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip,port))
s.send('PUSH')
while True:
data = raw_input("Input word or type #close to exit: ")
s.send(data + '\n')
if data == "#close":
break
s.close()
client2.py
from socket import *
ip = '127.0.0.1'
port = 5554
s = socket(AF_INET, SOCK_STREAM)
s.connect((ip, port))
s.send('PULL')
while True:
data = s.recv(1024)
if data:
words = data.split('\n')
for w in words:
print(w)
else:
break
s.close()
Output:
client1
Input word or type #close to exit: hello
Input word or type #close to exit: world
Input word or type #close to exit: #close
client2:
hello
world
server:
Server is listening on port number 5554
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62605)
Server is listening on port number 5554
Inside client 1 thread
('127.0.0.1', 62605) --terminates connection
--------------------------------------------------
Server connected to system having ip address --> ('127.0.0.1', 62614)
Server is listening on port number 5554
Inside client 2 thread
Inside client 2 thread
Inside client 2 thread
('127.0.0.1', 62614) --terminates connection
There is one final comment that the server will go around the loop again and keep on accepting clients. The code doesn't cope with this and I leave it as an exercise for you. You can multiplex multiple senders and receivers if you add a channel number to the PUSH and PULL initiation of the protocol (e.g. PUSH3, PULL3). This will then allow you to store the incoming data in a dictionary keyed by this integer and then send it out to the correct client.
Related
I'm quite new to socket programming, and I was wondering why the client stops responding after I send 3 messages to the server. Basically I send a message twice and the server responds to the client. The third time, the client just runs infinitely and the server doesn't receive anything.
Does it have something to do with overload? How does that work, especially with socket.listen()
Here is the code for reference:
client.py
# Import socket module
import socket
# Create a socket object
s = socket.socket()
# Define the port on which you want to connect
port = 12345
# connect to the server on local computer
s.connect(('127.0.0.1', port))
while True:
msg = input("Enter your message: ")
if msg != "quit":
s.send((msg).encode())
else:
# close the connection
s.close()
# receive data from the server
new_msg = (s.recv(1024).decode())
print ("[CLIENT]: ", new_msg)
server.py
# first of all import the socket library
import socket
# next create a socket object
s = socket.socket()
print ("Socket successfully created")
# reserve a port on your computer in our
# case it is 12345 but it can be anything
port = 12345
# Next bind to the port
# we have not typed any ip in the ip field
# instead we have inputted an empty string
# this makes the server listen to requests
# coming from other computers on the network
s.bind(('', port))
print ("socket binded to %s" %(port))
# a forever loop until we interrupt it or
# an error occurs
while True:
# put the socket into listening mode
s.listen(20)
print ("socket is listening")
# Establish connection with client.
c, addr = s.accept()
print('Got connection from', addr)
msg = c.recv(1024).decode()
if msg == "quit":
# Close the connection with the client
c.close()
else:
print ("[SERVER]: Recieved data: ", msg)
print ("[SERVER]: sending", msg)
c.send((msg).encode())
You still need a better understanding on how a listening socket works:
it listens only once
it accepts only once per connection
it can read and send as many packets as required until either side closes the connection
at that point (and for a single threaded server) it is ready to accept a new connection
You server.py should become:
...
s.bind(('', port))
print ("socket binded to %s" %(port))
# put the socket into listening mode
s.listen(20)
print ("socket is listening")
# a forever loop until we interrupt it or
# an error occurs
while True:
# Establish connection with client.
c, addr = s.accept()
print('Got connection from', addr)
while True:
msg = c.recv(1024).decode()
if len(msg) == 0: # the client does not send anything but just closes its side
# Close the connection with the client
c.close()
print('Client disconnected')
break
else:
print ("[SERVER]: Recieved data: ", msg)
print ("[SERVER]: sending", msg)
c.send((msg).encode())
A small fix for the client side:
...
if msg != "quit":
s.send((msg).encode())
else:
# close the connection
s.close()
break # break out of the loop after closing connection
But that is not all: TCP is a stream protocol. You should be prepared for packets send from one side to be splitted or re-assembled before reaching other side. The only guarantee is that bytes arrive in same order that they were send, but not necessarily in same packets.
I have two scripts, Server.py and Client.py.
I have two objectives in mind:
To be able to send data again and again to server from client.
To be able to send data from Server to client.
here is my Server.py :
import socket
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.1.3"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
serversocket.listen(5)
print ('server started and listening')
while 1:
(clientsocket, address) = serversocket.accept()
print ("connection found!")
data = clientsocket.recv(1024).decode()
print (data)
r='REceieve'
clientsocket.send(r.encode())
and here is my client :
#! /usr/bin/python3
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host ="192.168.1.3"
port =8000
s.connect((host,port))
def ts(str):
s.send('e'.encode())
data = ''
data = s.recv(1024).decode()
print (data)
while 2:
r = input('enter')
ts(s)
s.close ()
The function works for the first time ('e' goes to the server and I get return message back), but how do I make it happen over and over again (something like a chat application) ?
The problem starts after the first time. The messages don't go after the first time.
what am I doing wrong?
I am new with python, so please be a little elaborate, and if you can, please give the source code of the whole thing.
import socket
from threading import *
serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = "192.168.1.3"
port = 8000
print (host)
print (port)
serversocket.bind((host, port))
class client(Thread):
def __init__(self, socket, address):
Thread.__init__(self)
self.sock = socket
self.addr = address
self.start()
def run(self):
while 1:
print('Client sent:', self.sock.recv(1024).decode())
self.sock.send(b'Oi you sent something to me')
serversocket.listen(5)
print ('server started and listening')
while 1:
clientsocket, address = serversocket.accept()
client(clientsocket, address)
This is a very VERY simple design for how you could solve it.
First of all, you need to either accept the client (server side) before going into your while 1 loop because in every loop you accept a new client, or you do as i describe, you toss the client into a separate thread which you handle on his own from now on.
client.py
import socket
s = socket.socket()
s.connect(('127.0.0.1',12345))
while True:
str = raw_input("S: ")
s.send(str.encode());
if(str == "Bye" or str == "bye"):
break
print "N:",s.recv(1024).decode()
s.close()
server.py
import socket
s = socket.socket()
port = 12345
s.bind(('', port))
s.listen(5)
c, addr = s.accept()
print "Socket Up and running with a connection from",addr
while True:
rcvdData = c.recv(1024).decode()
print "S:",rcvdData
sendData = raw_input("N: ")
c.send(sendData.encode())
if(sendData == "Bye" or sendData == "bye"):
break
c.close()
This should be the code for a small prototype for the chatting app you wanted.
Run both of them in separate terminals but then just check for the ports.
This piece of code is incorrect.
while 1:
(clientsocket, address) = serversocket.accept()
print ("connection found!")
data = clientsocket.recv(1024).decode()
print (data)
r='REceieve'
clientsocket.send(r.encode())
The call on accept() on the serversocket blocks until there's a client connection. When you first connect to the server from the client, it accepts the connection and receives data. However, when it enters the loop again, it is waiting for another connection and thus blocks as there are no other clients that are trying to connect.
That's the reason the recv works correct only the first time. What you should do is find out how you can handle the communication with a client that has been accepted - maybe by creating a new Thread to handle communication with that client and continue accepting new clients in the loop, handling them in the same way.
Tip: If you want to work on creating your own chat application, you should look at a networking engine like Twisted. It will help you understand the whole concept better too.
Recently, I managed to create sockets on my PC and my Raspberry Pi to enable communication between both devices. Currently, the client is able to automatically send messages to the server. I was wondering, if it is possible to modify the scripts to send tcp data packets instead of purely text messages, as I would very much like to control the raspberry pi using my PC in the future without having the need to ssh/etc.
I've looked at some examples, but as I don't have much experience in writing my own scripts/codes, I'm not very sure how to go about doing this. I would appreciate if someone could guide me in the right direction with explanation and some examples if possible.
Anyway here is the server/client script I'm running at the moment:
Client:
import socket
import sys
import struct
import time
#main function
if __name__ == "__main__":
if(len(sys.argv) < 2) :
print 'Usage : python client.py hostname'
sys.exit()
host = sys.argv[1]
port = 8888
#create an INET, STREAMing socket
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print 'Socket Created'
try:
remote_ip = socket.gethostbyname( host )
s.connect((host, port))
except socket.gaierror:
print 'Hostname could not be resolved. Exiting'
sys.exit()
print 'Socket Connected to ' + host + ' on ip ' + remote_ip
#Send some data to remote server
message = "Test"
try :
#Set the whole string
while True:
s.send(message)
print 'Message sent successfully'
time.sleep(1)
print 'Sending...'
except socket.error:
#Send failed
print 'Send failed'
sys.exit()
def recv_timeout(the_socket,timeout=2):
#make socket non blocking
the_socket.setblocking(0)
#total data partwise in an array
total_data=[];
data='';
#beginning time
begin=time.time()
while 1:
#if you got some data, then break after timeout
if total_data and time.time()-begin > timeout:
break
#if you got no data at all, wait a little longer, twice the timeout
elif time.time()-begin > timeout*2:
break
#recv something
try:
data = the_socket.recv(8192)
if data:
total_data.append(data)
#change the beginning time for measurement
begin=time.time()
else:
#sleep for sometime to indicate a gap
time.sleep(0.1)
except:
pass
#join all parts to make final string
return ''.join(total_data)
#get reply and print
print recv_timeout(s)
s.close()
Server:
import socket
import sys
from thread import *
HOST = '' # Symbolic name meaning all available interfaces
PORT = 8888
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'Socket created'
try:
s.bind((HOST, PORT))
except socket.error , msg:
print 'Bind failed. Error Code : ' + str(msg[0]) + ' Message ' + msg[1]
sys.exit()
print 'Socket bind complete'
s.listen(10)
print 'Socket now listening'
#Function for handling connections
def clientthread(conn):
#Sending message to connected client
conn.send('Welcome to the server. Receving Data...\n') #send only takes string
#infinite loop so that function do not terminate and thread do not end.
while True:
#Receiving from client
data = conn.recv(1024)
reply = 'Message Received at the server!\n'
print data
if not data:
break
conn.sendall(reply)
conn.close()
#now keep talking with the client
while 1:
#wait to accept a connection
conn, addr = s.accept()
print 'Connected with ' + addr[0] + ':' + str(addr[1])
#start new thread
start_new_thread(clientthread ,(conn,))
s.close()
socket.socket(socket.AF_INET, socket.SOCK_STREAM) already creates a connection that provides a reliable stream of bytes between two machines. This uses TCP, which is on top of IP and Ethernet. The latter two are package-based, while TCP creates a stream of continuous bytes on top of it. It also adds some error checking and error correction, so it is pretty reliable.
I honestly don't understand what you want to achieve with what you call "send packets". What you don't want to do is to create an implementation of TCP yourself, as that's a non-trivial task, so sending RAW packets is out. In general, even using TCP is already relatively low-level and should be avoided unless really necessary.
Using e.g. ZeroMQ you get a message-based interface that does all the transmission for you. It does so on top of TCP (or other transports) and adds more error correction for e.g. disconnects. There, you also have something like "packets", but those are independent of how many TCP or IP packets were required to send it underneath. If you don't want to implement a specific protocol, I'd suggest you use this framework instead of lowlevel TCP sockets.
Another simple alternative is to use HTTP, for which there is also existing code in Python. The downside is that it is always one side that initiates some communication and the other side only replies. If you want some kind of active notification, you either have to poll or use hacks like delaying an answer.
You are already sending data packets - those packets juts happen to contain text data at the moment. Try looking into pickle in the standard libraries and into pyro.
I'm having a little trouble with sockets in Python. Whenever someone connects it works fine but if they disconnect the server program closes. I want the server program to remain open after the client closes. I'm using a while True loop to keep the connection alive but once the client closes the connection the server closes it's connection.
Here is the client:
import socket, sys
conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = sys.argv[1]
port = int(sys.argv[2])
conn.connect((host, port))
print("Connected to host " + sys.argv[1])
td = 1
while td == 1:
msg = raw_input('MSG: ')
Here is the server:
import socket, sys
socket.setdefaulttimeout(150)
host = ''
port = 50005
socksize = 1024
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host, port))
print("Server started on port: %s" % port)
s.listen(1)
print("Now listening...\n")
conn, addr = s.accept()
while True:
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
If a client closes a connection, you want it to close the socket.
It seems like there's a bit of a disconnect here that I'll try to elaborate on. When you create a socket, bind, and listen, you've established an open door for others to come and make connections to you.
Once a client connects to you, and you use the accept() call to accept the connection and get a new socket (conn), which is returned for you to interact with the client. Your original listening socket is still there and active, and you can still use it to accept more new connections.
Looking at your code, you probably want to do something like this:
while True:
print("Now listening...\n")
conn, addr = s.accept()
print 'New connection from %s:%d' % (addr[0], addr[1])
data = conn.recv(socksize)
if not data:
break
elif data == 'killsrv':
conn.close()
sys.exit()
else:
print(data)
Please note that this is just a starting point, and as others have suggested you probably want to use select() along with forking off processes or spawning threads to service each client.
Your code is only accepting a single connection - the loop only deals with the first accepted connection and terminates as soon as it lost. This is way your server exists:
data = conn.recv(socksize)
if not data:
break
What you will need to do is to accept several connections, while handling each of those in it's own loop. Note that it does not have to be a real loop for each socket, you can use a select-based approach to query which of the sockets has an event associated with it (data available, connection lost etc.) and then process only those sockets, all in the same loop.
You can also use a multi threaded / multi process approach, dealing with each client in it's own thread or process - I guess you won't run into scaling issues when playing around.
See:
http://docs.python.org/library/select.html
http://docs.python.org/library/multiprocessing.html
I have a main thread that waits for connection. It spawns client threads that will echo the response from the client (telnet in this case). But say that I want to close down all sockets and all threads after some time, like after 1 connection.
How would I do it? If I do clientSocket.close() from the main thread, it won't stop doing the recv. It will only stop if I first send something through telnet, then it will fail doing further sends and recvs.
My code looks like this:
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocket):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
# It will hang here, even if I do close on the socket
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
time.sleep(1)
# This won't make the recv in the clientThread to stop immediately,
# nor will it generate an exception
clientSocket.close()
I know this is an old thread and that Samuel probably fixed his issue a long time ago. However, I had the same problem and came across this post while google'ing. Found a solution and think it is worthwhile to add.
You can use the shutdown method on the socket class. It can prevent further sends, receives or both.
socket.shutdown(socket.SHUT_WR)
The above prevents future sends, as an example.
See Python docs for more info.
I don't know if it's possible to do what you're asking, but it shouldn't be necessary. Just don't read from the socket if there is nothing to read; use select.select to check the socket for data.
change:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
to something more like this:
r, _, _ = select.select([self.clientSocket], [], [])
if r:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
EDIT: If you want to guard against the possibility that the socket has been closed, catch socket.error.
do_read = False
try:
r, _, _ = select.select([self.clientSocket], [], [])
do_read = bool(r)
except socket.error:
pass
if do_read:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
I found a solution using timeouts. That will interrupt the recv (actually before the timeout has expired which is nice):
# Echo server program
import socket
from threading import Thread
import time
class ClientThread(Thread):
def __init__(self, clientSocke):
Thread.__init__(self)
self.clientSocket = clientSocket
def run(self):
while 1:
try:
data = self.clientSocket.recv(1024)
print "Got data: ", data
self.clientSocket.send(data)
except socket.timeout:
# If it was a timeout, we want to continue with recv
continue
except:
break
self.clientSocket.close()
HOST = ''
PORT = 6000
serverSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
serverSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
serverSocket.bind((HOST, PORT))
serverSocket.listen(1)
clientSocket, addr = serverSocket.accept()
clientSocket.settimeout(1)
print 'Got a new connection from: ', addr
clientThread = ClientThread(clientSocket)
clientThread.start()
# Close it down immediatly
clientSocket.close()
I must apologize for the comments below. The earlier comment by #Matt Anderson works. I had made a mistake when trying it out which led to my post below.
Using timeout is not a very good solution. It may seem that waking up for an instant and then going back to sleep is no big deal, but I have seen it greatly affect the performance of an application. You have an operation that for the most part wants to block until data is available and thus sleep forever. However, if you want to abort for some reason, like shutting down your application, then the trick is how to get out. For sockets, you can use select and listen on two sockets. Your primary one, and a special shutdown one. Creating the shutdown one though is a bit of a pain. You have to create it. You have to get the listening socket to accept it. You have to keep track of both ends of this pipe. I have the same issue with the Synchronized Queue class. There however, you can at least insert a dummy object into the queue to wake up the get(). This requires that the dummy object not look like your normal data though. I sometimes wish Python had something like the Windows API WaitForMultipleObjects.