I am working for the first time on sockets with python.
I need to connect more than a client socket to the same server socket.
To do this I used the the following code:
import socket
import time
import random
from threading import Thread
import thread
import subprocess, signal, os
class ServerObject:
def __init__(self, port):
self.socket = ''
self.host = ''
self.port = port
self.conn = ''
self.data = ''
print "Server port is: ", self.port
def openSocketConnectionAsServer(self):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.bind((self.host, self.port))
self.socket.listen(5)
self.conn, addr = self.socket.accept()
print 'Server Connected by', addr
def getData(self):
return self.data
def getHost(self):
return self.host
def getPort(self):
return self.port
def sendMessage(self, message):
try :
self.conn.sendall(message)
except socket.error:
print 'Server Send failed'
sys.exit()
def receiveMessageFromClient(self):
while 1:
reply = self.conn.recv(4096)
if not self.data: break
return reply
def receiveMessageFromServer(self):
reply = self.socket.recv(4096)
return reply
def closeConnectionAsServer(self):
self.socket.shutdown(1)
self.socket.close()
del self.socket
class ClientObject:
def __init__(self):
self.data = str(random.choice('abcdefghil'))
print "Client Data Random: ", self.data
self.host = 'localhost'
self.port = ''
def openSocketConnectionAsClient(self):
self.port = 50000 + random.randint(1,3)
print "Client socket port is: ", self.port
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Client Failed to create socket'
sys.exit()
print 'Client Socket Created'
try:
remote_ip = socket.gethostbyname( self.host )
except socket.gaierror:
print 'Client Hostname could not be resolved. Exiting'
sys.exit()
self.socket.connect((remote_ip , self.port))
def getData(self):
return self.data
def getHost(self):
return self.host
def getPort(self):
return self.port
def sendMessage(self, message):
try :
self.socket.sendall(message)
except socket.error:
print 'Client Send failed'
os.sys.exit()
def receiveMessageFromServer(self):
reply = self.socket.recv(4096)
return reply
def closeConnection(self):
self.socket.shutdown(1)
self.socket.close()
del self.socket
def clientProcess():
print "Client Start the client process"
client1 = ClientObject()
for i in range(1,10):
try:
print "Client try to open the connection socket: attempt number ",i
client1.openSocketConnectionAsClient()
print "Client connection socket established on port ", client1.getPort()
break
except socket.error:
print "Client connection error on the port ", client1.getPort()
if i == 10:
os.sys.exit()
print "Client send the message"
client1.sendMessage(client1.getData())
print "Client receive the message back"
client1.receiveMessageFromServer()
print "Client Data requested: ", client1.getData(), " Hostname: ", client1.getHost(), " Port: ", client1.getPort()
print "Client Close connection"
client1.closeConnection()
def serverProcess(port=40007):
print "Server oject create"
server = ServerObject(port)
print "Server open connection as server"
server.openSocketConnectionAsServer()
print "Server receive the client message"
receivedMessage = server.receiveMessageFromClient()
message = "Server Data requested are: "+receivedMessage
print "Server send the message back to the client"
server.sendMessage(message)
print "Server close the connection with the client"
server.closeConnectionAsServer()
if __name__ == '__main__':
threadServer = Thread(target=serverProcess, args=[50001])
print "New Server thread created with name: ", threadServer.getName()
threadServer.start()
for i in range(1,3):
threadClient = Thread(target=clientProcess)
print "New Client thread created with name: ", threadClient.getName()
threadClient.start()
threadClient.join()
When I run it, the first client is able to connect to the server, the second one never get connected, even though I close the connection (from server and client side) at the end of the first client thread.
Please, could anybody tell me, what's wrong in my code?
Thanks
I would highly recommend using the excellent socketserver module for doing stuff like this. As for your code, the problem is that your threaded socket server only runs in a single thread. At the very least, you should create a new thread to handle the connection after accepting the new connection in openSocketConnectionAsServer.
What #Ber said was correct but incomplete.
You're problem is here:
self.socket.listen(5)
self.conn, addr = self.socket.accept()
listen will open up the port and prepare to receive connections. accept will wait for the next connection.
While you only need to call listen once, you must call accept multiple times, once per connection. There are several ways you can arrange this. For starters you could call accept again when the current connection closes, but this will only allow one client at a time. Better to have one thread call accept to wait for the next connection, but have it start a worker thread to handle each one.
Or you could use non-blocking I/O, but if you go this way, check out Twisted.
Related
below is a basic program that has the client enter a name, then it connects to the server and gets a response, and the server then appends the name to a list, the problem is when a second client connects to the server the first client loses connection and this happens for every client that connects. how do I solve this?
server.py :
import socket
s = socket.socket()
host = "127.0.0.1"
port = 5409
s.bind((host, port))
names = []
while True:
s.listen(5)
c, addr = s.accept() # Establish connection with client.
print 'Got connection from', addr
while True:
try:
name = c.recv(1024)
print name
except:
print ""
if name not in names:
names.append(name)
message = "Hello " + name
c.sendall(message)
print names
break
client.py :
import socket # Import socket module
s = socket.socket() # Create a socket object
host = "127.0.0.1" # Get local machine name
port = 5409 # Reserve a port for your service.
name = raw_input("What Is your Name? ")
s.connect((host, port))
while True:
try:
s.send(name)
except:
break
try:
print s.recv(1024)
except:
break
You will need to make your server able to handle concurrent connections, either with multithreading, multiprocessing, or select.
The socketserver module provides convenient basic server classes using threading or multiprocessing. The official documentation has some good examples. Here is one using the threading module for concurrency:
import socket
import threading
import socketserver
class ThreadedTCPRequestHandler(socketserver.BaseRequestHandler):
def handle(self):
data = str(self.request.recv(1024), 'ascii')
cur_thread = threading.current_thread()
response = bytes("{}: {}".format(cur_thread.name, data), 'ascii')
self.request.sendall(response)
class ThreadedTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
def client(ip, port, message):
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.connect((ip, port))
sock.sendall(bytes(message, 'ascii'))
response = str(sock.recv(1024), 'ascii')
print("Received: {}".format(response))
if __name__ == "__main__":
# Port 0 means to select an arbitrary unused port
HOST, PORT = "localhost", 0
server = ThreadedTCPServer((HOST, PORT), ThreadedTCPRequestHandler)
ip, port = server.server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread = threading.Thread(target=server.serve_forever)
# Exit the server thread when the main thread terminates
server_thread.daemon = True
server_thread.start()
print("Server loop running in thread:", server_thread.name)
client(ip, port, "Hello World 1")
client(ip, port, "Hello World 2")
client(ip, port, "Hello World 3")
server.shutdown()
server.server_close()
If you would like to build your own server without using socketserver, you can look at the source for the socketserver module (it's simple), or there are plenty of examples online of basic TCP/UDP servers using all three concurrency methods.
I'm trying to understand the basics of networking and I believe the right way to start learning basic server handling is through sockets.
I am aware there are better libraries such as twisted or socketServer. I want to do it specifically in socket module.
I am aware using socket module to build servers is unreliable.
I also am aware I need to implement some kind of protocol for future use.
I tried building P2pClient with threading.Thread inheritance:
import socket
import threading
class P2pServer(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self)
print "Info: %s:%s" % (host, port)
self.server = socket.socket()
self.server.bind((host, port))
print "Created the server"
self.server.listen(1) # p2p chat
def run(self):
while True:
c, addr = self.server.accept()
print "Connected from %s (%s)" % (addr, c)
class P2pClient(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self, host, port)
self.client = socket.socket()
self.client.connect((host, port))
def send_msg(self, msg):
try:
self.client.send(msg)
return "Sent: %s" % msg
except socket.error as e:
return "Could not send because of %s" % e
def run(self):
while True:
recv = self.client.recv(1024)
if len(recv) > 0:
print recv
server = P2pServer("localhost", 44444) # This is our server
server.start() # Run it
client = None
print "Ready to take input"
while True:
print "Your command: ",
cmd = raw_input()
if cmd.startswith("connect "):
cmd = cmd.split()
client = P2pClient(cmd[1], cmd[2])
client.start()
else:
client.send_msg(cmd)
But ended up getting the following error when the input is "connect localhost :
Traceback (most recent call last):
File "C:/Users/edız/Desktop/Ediz/Python/Playground/servers test/p2p.py", line 49, in <module>
client = P2pClient(cmd[1], cmd[2])
File "C:/Users/edız/Desktop/Ediz/Python/Playground/servers test/p2p.py", line 22, in __init__
threading.Thread.__init__(self, host, port)
File "C:\Python27\lib\threading.py", line 670, in __init__
assert group is None, "group argument must be None for now"
AssertionError: group argument must be None for now
Solution on the site suggested making it so that I use the threading.Thread() function directly instead of doing it the former way. However, the threading documenation doesn't give me an idea about how to reach the target function. How can I build the thread that will allow me to access P2pClient in the client variable?
Purpose of the following code is so that it will be run in two different port in same host, making a P2P connection between two servers.
import socket
import threading
class P2pServer(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self)
print "Info: %s:%s" % (host, port)
self.server = socket.socket()
self.server.bind((host, port))
print "Created the server"
self.server.listen(1) # p2p chat
def run(self):
while True:
c, addr = self.server.accept()
print "Connected from %s (%s)" % (addr, c)
class P2pClient(object):
def __init__(self, host, port):
self.client = socket.socket()
self.client.connect((host, int(port)))
def send_msg(self, msg):
try:
self.client.send(msg)
return "Sent: %s" % msg
except socket.error as e:
return "Could not send because of %s" % e
def run(self):
while True:
recv = self.client.recv(1024)
if len(recv) > 0:
print recv
server = P2pServer("localhost", 44444) # This is our server
server.start() # Run it
client = None
print "Ready to take input"
while True:
print "Your command: ",
cmd = raw_input()
if cmd.startswith("connect "):
cmd = cmd.split()
client = threading.Thread(target=P2pClient, args=(cmd[1], cmd[2]))
client.start()
else:
pass
# Here I just want something like this:
# client.send_msg("Hello other server")
Your first example is close. The problem is that you passed the extra parameters you need for the child P2pClient to the parent Thread class. thread takes a different set of parameters. Just leave those parameters out when initializing the parent.
class P2pClient(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self)
self.client = socket.socket()
self.client.connect((host, port))
I got this multi threaded server code and it works but when I type something to send to the client its not sending it the send function only work if I send the data string
anyone knows what's the problem?
#!/usr/bin/env python
import socket, threading
class ClientThread(threading.Thread):
def __init__(self, ip, port, clientsocket):
threading.Thread.__init__(self)
self.ip = ip
self.port = port
self.csocket = clientsocket
print "[+] New thread started for "+ip+":"+str(port)
def run(self):
print "Connection from : "+ip+":"+str(port)
clientsock.send("Welcome to the server ")
data = "dummydata"
while len(data):
data = self.csocket.recv(2048)
print "Client(%s:%s) sent : %s"%(self.ip, str(self.port), data)
userInput = raw_input(">")
self.csocket.send(userInput)
print "Client at "+self.ip+" disconnected..."
host = "0.0.0.0"
port = 4444
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind((host, port))
while True:
tcpsock.listen(4)
print "nListening for incoming connections..."
(clientsock, (ip, port)) = tcpsock.accept()
#pass clientsock to the ClientThread thread object being created
newthread = ClientThread(ip, port, clientsock)
newthread.start()
Well, I can see at least one thing that will prevent this from working as intended:
def run(self):
print "Connection from : "+ip+":"+str(port)
clientsock.send("Welcome to the server ")
clientsock is undefined.
My suggestion is don't try to reinvent the wheel (unless you want to understand how the wheel works). There's already the built-in SocketServer but that is synchronous, meaning each request must be completed before the next request can be started.
There are already very easy to use implementations of asynchronous (non-blocking) TCP servers out there. If you want something that doesn't require you to learn a framework and just runs out-of-the-box, I suggest simpleTCP. Here's an example of an echo server:
from simpletcp.tcpserver import TCPServer
def echo(ip, queue, data):
queue.put(data)
server = TCPServer("localhost", 5000, echo)
server.run()
And here's an example of a client connecting to it:
from simpletcp.clientsocket import ClientSocket
s1 = ClientSocket("localhost", 5000)
response = s1.send("Hello, World!")
All of the below mentioned is on windows machines using python 2.7
Hello,
I am currently attempting to listen on a socket for data send by a remote program. This data is then printed to the screen and user input is requested that is then returned to remote program. In testing I have been able to have the remote program send me a menu of command line programs (cmd, ipconfig, whoami, ftp) and then my program returns with a number as a selection of the menu option.
The remote program receives my response and sends the output of the selected command. ipconfig and whoami work perfectly, but cmd and ftp only returns the output of the terminal once. (I.E. I can enter one command into the FTP program and send that too the remote program before I never hear back)
The part of my code that fails is that
if ready[0]: never becomes ready a second time after the first conversation.
I know the remote program is functioning correctly as I can use netcat to act in lieu of my code and operate the cmd terminal indefinitely.
How do I go about properly implementing a python socket listener that can account for this type of connection?
My "program" in its entirety:
import socket, sys, struct, time, select
host = ''
port = 50000
connectionSevered=0
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except socket.error:
print 'Failed to create socket'
sys.exit()
print '[+] Listening for connections on port '+str(port)+'.'
s.bind((host,port))
s.listen(5)
def recvall(the_socket,timeout=2):
global connectionSevered
data=''; # Data found by recv
total_data=[]; # Finally list of everything
s.setblocking(0) #make socket non blocking
begin=time.time() #beginning time
while 1:
ready = select.select([client], [], [], .2)
if time.time()-begin > timeout:
print 'Timeout reached'
#Leave loop, timer has reached its threshold
break
if ready[0]:
print 'In ready loop!'
try:
data = client.recv(4096) #attempt to fetch data
if data:
begin=time.time() #reset timeout timer
total_data.append(data)
data='';
except socket.error:
print '[+] Lost connection to client. Printing buffer...'
connectionSevered=1 # Let main loop know connection has errored
pass
time.sleep(1)
#join all parts to make final string
return ''.join(total_data)
client, address = s.accept()
print '[+] Client connected!'
while (connectionSevered==0): # While connection hasn't errored
print "connectionSevered="+str(connectionSevered) # DEBUG
recvall(s)
response = raw_input() #take user input
client.sendto(response) #send input
client.close(0)
Please let me know if you need more information, any help would be greatly appreciated, I am very new to this and eager to learn.
Playing around with this for a while finally got it working nice with a telnet session locally using python 2.7.
What it does is it sets up a thread that runs when the client connects listening for client stuff.
When the client sends a return ("\r\n" might have to change that if your interacting with a Linux system?) the message gets printed to the server, while this is happening if there is a raw input at the server side this will get sent to the client:
import socket
import threading
host = ''
port = 50000
connectionSevered=0
class client(threading.Thread):
def __init__(self, conn):
super(client, self).__init__()
self.conn = conn
self.data = ""
def run(self):
while True:
self.data = self.data + self.conn.recv(1024)
if self.data.endswith(u"\r\n"):
print self.data
self.data = ""
def send_msg(self,msg):
self.conn.send(msg)
def close(self):
self.conn.close()
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((host,port))
s.listen(5)
except socket.error:
print 'Failed to create socket'
sys.exit()
print '[+] Listening for connections on port: {0}'.format(port)
conn, address = s.accept()
c = client(conn)
c.start()
print '[+] Client connected: {0}'.format(address[0])
c.send_msg(u"\r\n")
print "connectionSevered:{0}".format(connectionSevered)
while (connectionSevered==0):
try:
response = raw_input()
c.send_msg(response + u"\r\n")
except:
c.close()
The above answer will not work for more than a single connection. I have updated it by adding another thread for taking connections. It it now possible to have more than a single user connect.
import socket
import threading
import sys
host = ''
port = 50000
class client(threading.Thread):
def __init__(self, conn):
super(client, self).__init__()
self.conn = conn
self.data = ""
def run(self):
while True:
self.data = self.data + self.conn.recv(1024)
if self.data.endswith(u"\r\n"):
print self.data
self.data = ""
def send_msg(self,msg):
self.conn.send(msg)
def close(self):
self.conn.close()
class connectionThread(threading.Thread):
def __init__(self, host, port):
super(connectionThread, self).__init__()
try:
self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.s.bind((host,port))
self.s.listen(5)
except socket.error:
print 'Failed to create socket'
sys.exit()
self.clients = []
def run(self):
while True:
conn, address = self.s.accept()
c = client(conn)
c.start()
c.send_msg(u"\r\n")
self.clients.append(c)
print '[+] Client connected: {0}'.format(address[0])
def main():
get_conns = connectionThread(host, port)
get_conns.start()
while True:
try:
response = raw_input()
for c in get_conns.clients:
c.send_msg(response + u"\r\n")
except KeyboardInterrupt:
sys.exit()
if __name__ == '__main__':
main()
Clients are not able to see what other clients say, messages from the server will be sent to all clients. I will leave that as an exercise for the reader.
If you're in Python 3 by now and still wondering about sockets, here's a basic way of using them:
server.py
import time
import socket
# creating a socket object
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
# get local Host machine name
host = socket.gethostname() # or just use (host == '')
port = 9999
# bind to pot
s.bind((host, port))
# Que up to 5 requests
s.listen(5)
while True:
# establish connection
clientSocket, addr = s.accept()
print("got a connection from %s" % str(addr))
currentTime = time.ctime(time.time()) + "\r\n"
clientSocket.send(currentTime.encode('ascii'))
clientSocket.close()
client.py
import socket
# creates socket object
s = socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
host = socket.gethostname() # or just use (host = '')
port = 9999
s.connect((host, port))
tm = s.recv(1024) # msg can only be 1024 bytes long
s.close()
print("the time we got from the server is %s" % tm.decode('ascii'))
Run server.py first, then run client.py.
This is just send and receive the currentTime.
What's new in Python 3.4 sockets?
A major difference between python 2.7 sockets and python 3.4 sockets is the sending messages. you have to .encode() (usually using 'ascii' or blank as parameters/arguments)
and then using .decode()
For example use .encode() to send, and use .decode() to receive.
Extra info: client/server socket tutorial
I'm writing an application that is supposed to listen for a client, and when it connects, it should grab some data. It works fine when I run it locally on either my own computer, or the server, but when I try and run it on the server, and connect from my computer, it doesn't work at all. The connection times out.
I've tried running the program, and then checking netstat (on the server), and it only shows anything if I have my host set to localhost. If I set my host to the server's IP address (or hostname, or socket.getfqdn()), then nothing shows up in netstat.
The code is as follows:
class Listen(threading.Thread):
def __init__(self):
self.PORT = 2079
self.HOST = socket.getfqdn()
threading.Thread.__init__(self)
self.finished = threading.Event()
def stop(self):
self.finished.set()
self.join()
def run(self):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((self.HOST, self.PORT))
server.listen(5)
while not self.finished.isSet():
try:
server.settimeout(1)
channel, details = server.accept()
server.settimeout(None)
Client(channel, details).start()
except socket.timeout:
pass
class Client(threading.Thread):
def __init__(self, channel, details):
self.channel = channel
self.details = details
self.log = []
threading.Thread.__init__(self)
def run(self):
print 'Received connection:', self.details [ 0 ]
entries = int(self.channel.recv(3))
print "Receiving", entries, "new entries"
for i in range(entries):
self.log.append([])
self.log[i].append(float(self.channel.recv(10)))
self.log[i].append(float(self.channel.recv(10)))
self.log[i].append(self.channel.recv(14))
self.channel.close()
print 'Closed connection:', self.details [ 0 ]
print "The obtained log: "
print self.log
def main():
listen = Listen()
listen.start()
while True:
input = raw_input(">>").lower()
if input in ["start"]:
if listen.isAlive():
print "Already started"
else:
listen = Listen()
listen.start()
if input in ["stop"]:
if not listen.isAlive():
print "Already stopped"
else:
listen.stop()
if input in ["exit"]:
if listen.isAlive():
listen.stop()
sys.exit()
if input in ["status"]:
print "The server is " + ["not ", ""][listen.isAlive()] + "running"
if __name__ == '__main__':
main()
Instead of server.bind((self.HOST, self.PORT)), try:
server.bind(('', self.PORT))
For IPv4 addresses the empty string represents INADDR_ANY; when receiving a socket bound to this address, your process will receive packets from all interfaces (not just the loop-back or the primary Ethernet interface).