My code basically needs to start up a simple chat server with a client. Where the server and the client can talk back and forth to each other. I've gotten everything to be implemented correctly, but I can't figure out how to shut down the server whenever I'm done. (I know it's ss.shutdown()).
I'm wanting to end right now based on a keyword shared between the two (something like "bye"), but I don't know if I can somehow send a message to my SocketServer from BaseRequestHandler to shutdown() whenever it receives the message.
Eventually, my goal is to incorporate Tkinter to make a GUI, but I wanted to get everything else to work first, and this is my first time dealing with sockets in Python.
from sys import argv, stderr
from threading import Thread
import socket
import SocketServer
import threading
import sys
class ThreadedRecv(Thread):
def __init__(self,socket):
Thread.__init__(self)
self.__socket = socket
self.__message = ''
self.__done = False
def recv(self):
while self.__message.strip() != "bye" and not self.getStatus():
self.__message = self.__socket.recv(4096)
print 'received',self.__message
self.setStatus(True)
def run(self):
self.recv()
def setStatus(self,status):
self.__done = status
def getStatus(self):
return self.__done
class ThreadedSend(Thread):
def __init__(self,socket):
Thread.__init__(self)
self.__socket = socket
self.__message = ''
self.__done = False
def send(self):
while self.__message != "bye" and not self.getStatus():
self.__message = raw_input()
self.__socket.send(self.__message)
self.setStatus(True)
def run(self):
self.send()
def setStatus(self,status):
self.__done = status
def getStatus(self):
return self.__done
class HostException(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
class EchoServer(SocketServer.BaseRequestHandler):
def setup(self):
print self.client_address, 'is connected!'
self.request.send('Hello ' + str(self.client_address) + '\n')
self.__done = False
def handle(self):
sender = ThreadedSend(self.request)
recver = ThreadedRecv(self.request)
sender.start()
recver.start()
while 1:
if recver.getStatus():
sender.setStatus(True)
break
if sender.getStatus():
recver.setStatus(True)
break
def finish(self):
print self.client_address, 'disconnected'
self.request.send('bye client %s\n' % str(self.client_address))
self.setDone(True)
def setDone(self,done):
self.__done = done
def getDone(self):
return self.__done
def setup(arg1, arg2, arg3):
server = False
defaultPort,defaultHost = 2358,"localhost"
hosts = []
port = defaultPort
serverNames = ["TRUE","SERVER","S","YES"]
arg1 = arg1.upper()
arg2 = arg2.upper()
arg3 = arg3.upper()
if arg1 in serverNames or arg2 in serverNames or arg3 in serverNames:
server = True
try:
port = int(arg1)
if arg2 != '':
hosts.append(arg2)
except ValueError:
if arg1 != '':
hosts.append(arg1)
try:
port = int(arg2)
if arg3 != '':
hosts.append(arg3)
except ValueError:
if arg2 != '':
hosts.append(arg2)
try:
port = int(arg3)
except ValueError:
if arg3 != '':
hosts.append(arg3)
port = defaultPort
for sn in serverNames:
if sn in hosts:
hosts.remove(sn)
try:
if len(hosts) != 1:
raise HostException("Either more than one or no host "+ \
"declared. Setting host to localhost.")
except HostException as error:
print error.value, "Setting hosts to default"
return (server,defaultHost,port)
return (server,hosts[0].lower(),port)
def main():
bufsize = 4096
while len(argv[1:4]) < 3:
argv.append('')
settings = setup(*argv[1:4])
connections = (settings[1],settings[2])
print connections
if not settings[0]:
try:
mySocket = socket.socket(socket.AF_INET,\
socket.SOCK_STREAM)
except socket.error, msg:
stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(1)
try:
mySocket.connect(connections)
except socket.error, msg:
stderr.write("[ERROR] %s\n" % msg[1])
sys.exit(2)
message = ""
print "Enter a message to send to the server. "+\
"Enter \"bye\" to quit."
sender = ThreadedSend(mySocket)
recver = ThreadedRecv(mySocket)
sender.start()
recver.start()
while 1:
if sender.getStatus():
recver.setStatus(True)
break
if recver.getStatus():
sender.setStatus(True)
break
else:
xserverhandler = EchoServer
serversocket = SocketServer.ThreadedTCPServer(\
connections,xserverhandler)
server_thread = Thread(target = serversocket.serve_forever)
server_thread.setDaemon(True)
server_thread.start()
# I would like to shut down this server whenever
# I get done talking to it.
"""while 1:
if xserverhandler.getDone():
print 'This is now true!'
serversocket.shutdown()
break"""
if __name__ == '__main__':
main()
Yeah, I know setup() is a terrible function right now with the try's and catches, but it works for now, so I was going to fix it later.
My question is basically: How can I get the server to actually end based on a message that it receives? If possible, is there a way to access the Request Handler after it's started?
Please fix your code so it works, and include some way to use it. You need to add
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
since SocketServer doesn't actually include that class (at least not in my version of 2.6 nor 2.7). Instead, it's an example from the SocketServer definition.
Please include an example of how to start/use the code. In this case to start the server you need to do:
ss.py SERVER localhost 8001
and the client as
ss.py localhost 8001
If you do that then you can't do server_thread.setDaemon(True) because there are no other threads running, which means the server will exit immediately.
Once that's done the solution is to add a call (or two) to self.server.shutdown() insdie of your EchoServer.handle method, like:
while 1:
if recver.getStatus():
sender.setStatus(True)
self.server.shutdown()
break
However, I can't get that to work, and I think it's because I inherited things wrong, or guessed wrong in what you did.
What you should do is search for someone else who has done a chat server in Python. Using Google I found http://www.slideshare.net/didip/socket-programming-in-python and there are certainly others.
Also, if you are going to mix GUI and threaded programming then you should look into examples based on that. There are a number of hits when I searched for "tkinter chat". Also, you might want to look into twisted, which has solved a lot of these problems already.
What problems? Well, for example, you likely want an SO_REUSEADDR socket option.
Request handler object is created for each new request. So you have to store "done" flag in server, not handler. Something like the following:
class EchoServer(SocketServer.BaseRequestHandler):
...
def setDone(self):
self.server.setDone() # or even better directly self.server.shutdown()
Related
I hope the title is appropriate. If not please suggest an alternative. I am working with the following Python Client Class.
import Queue
import socket
import struct
import threading
import time
class ClientCommand(object):
CONNECT, SEND, RECEIVE, CLOSE = range(4)
def __init__(self, type, data=None):
self.type = type
self.data = data
class ClientReply(object):
ERROR, SUCCESS = range(2)
def __init__(self, type, data = None):
self.type = type
self.data = data
class SocketClientThread(threading.Thread):
def __init__(self, cmd_q = Queue.Queue(), reply_q = Queue.Queue()):
super(SocketClientThread, self).__init__()
self.cmd_q = cmd_q
self.reply_q = reply_q
self.alive = threading.Event()
self.alive.set()
self.socket = None
#self.stopped = False
self.handlers = {
ClientCommand.CONNECT: self._handle_CONNECT,
ClientCommand.CLOSE: self._handle_CLOSE,
ClientCommand.SEND: self._handle_SEND,
ClientCommand.RECEIVE: self._handle_RECEIVE
}
def run(self):
while self.alive.isSet():
#while not self.stopped:
try:
cmd = self.cmd_q.get(True, 0.1)
self.handlers[cmd.type](cmd)
except Queue.Empty as e:
continue
def stop(self):
self.alive.clear()
def join(self, timeout=None):
self.alive.clear()
threading.Thread.join(self, timeout)
def _handle_CONNECT(self, cmd):
try:
self.socket = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((cmd.data[0], cmd.data[1]))
self.reply_q.put(self._success_reply())
except IOError as e:
self.reply_q.put(self._error_reply(str(e)))
def _handle_CLOSE(self, cmd):
self.socket.close()
reply = ClientReply(ClientReply.SUCCESS)
self.reply_q.put(reply)
def _handle_SEND(self, cmd):
try:
print "about to send: ", cmd.data
self.socket.sendall(cmd.data)
print "sending data"
self.reply_q.put(self._success_reply())
except IOError as e:
print "Error in sending"
self.reply_q.put(self._error_reply(str(e)))
def _handle_RECEIVE(self, cmd):
try:
#TODO Add check for len(data)
flag = True
while flag:
print "Receiving Data"
data = self._recv_n_bytes()
if len(data) != '':
self.reply_q.put(self._success_reply(data))
if data == "Stop":
print "Stop command"
flag = False
except IOError as e:
self.reply_q.put(self._error_reply(str(e)))
def _recv_n_bytes(self):
data = self.socket.recv(1024)
return data
def _error_reply(Self, errstr):
return ClientReply(ClientReply.ERROR, errstr)
def _success_reply(self, data = None):
return ClientReply(ClientReply.SUCCESS, data)
My main script code -
import socket
import time
import Queue
import sys
import os
from client import *
sct = SocketClientThread()
sct.start()
host = '127.0.0.1'
port = 1234
sct.cmd_q.put(ClientCommand(ClientCommand.CONNECT, (host, port)))
try:
while True:
sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE))
reply = sct.reply_q
tmp = reply.get(True)
data = tmp.data
if data != None:
if data != "step1":
//call function to print something
else:
// call_function that prints incoming data till server stops sending data
print "Sending OK msg"
sct.cmd_q.put(ClientCommand(ClientCommand.SEND, "Hello\n"))
print "Done"
else:
print "No Data"
except:
#TODO Add better error handling than a print
print "Server down"
So here is the issue. Once the thread starts, and the Receive handler is called, I get some data, if that data is not "Step1", I just call a function (another script) to print it.
However, if the data is "step1", I call a function which will then continue printing whatever data the server sends next, till the server sends a "Stop" message. At this point, I break out of the "Receive Handler", and try to send an "Ok" message to the Server.
However, as soon as I break out of the "Receive Handler", it automatically calls upon that function again. So while I am trying to send back a message, the client is again waiting for data from the server. So due to the "Receiver function" being called again, the "Send function" blocks.
I can't seem to understand how to switch between receiving and sending. What is wrong with my approach here and how should I fix this? Do I need to re-write the code to have two separate threads for sending and receiving?
If you require any more details please let me know before you decide to flag my question for no reason.
However, as soon as I break out of the "Receive Handler", it
automatically calls upon that function again.
This is because you call sct.cmd_q.put(ClientCommand(ClientCommand.RECEIVE)) within the while True loop that's run through for each single chunk of data received, i. e. for each data before "step1" one more command to call the "Receive Handler" (which itself loops until "Stop") is put into the ClientCommand queue, and those commands are of course then executed before the SEND command. If you place the RECEIVE call before this while True loop, your approach can work.
The error is
if msgid != "step1":
NameError: name 'msgid' is not defined
Instead of
#TODO Add better error handling than a print
print "Server down"
you had better written
raise
and spotted it immediately.
I'm trying to make a multi threading udp server with python.
Here is what I am doing :
#!/usr/bin/python
# -*- coding:Utf-8 -*-
import sys
import socket
from thread import start_new_thread
class Broker():
def __init__(self, ip, port):
self.s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.ip = ip
self.port = port
self.s.bind((ip, port))
self.listclients = []
def listenMod(b):
dic = {}
msg, ip = b.s.recvfrom(1024)
dic[msg] = ip
b.listclients.append(dic)
print msg, " is connected."
def broker(arg):
try:
b = Broker(arg[2], int(arg[3]))
start_new_thread(listenMod, (b, ))
except Exception, e:
print e
sys.exit(-1)
def client(arg):
try:
pass
except:
pass
def usage():
print "usage ./udps.py <-b|-c> <args>"
print "-b\tserver mode\n\t<args>: host port"
sys.exit()
def main():
i = 1
if len(sys.argv) > 1:
while i < len(sys.argv):
if sys.argv[1] == "-b":
broker(sys.argv)
elif sys.argv[1] == "-c":
pass
else:
usage()
else:
usage()
if __name__ == '__main__':
main()
It always prints "[Errno 48] Address already in use"
I'm using this because I would like to be able do to some special things with my clients but also be able to connect new clients at the same time.
First, don't use SO_REUSEADDR. There are legitimate uses of SO_REUSEADDR, but in most simple cases it is not useful, and it hides the real problem. Feel free to re-add it if needed, but only when your program works without it.
Your problem here is in your main. You are looping on the number of arguments, but never increment i, so it loops infinitely. Also you are always testing argv[1]. If there are 4 arguments, and the 2nd is '-b', you will call broker() 4 times, which will obviously not work. Also, note that if your loop ends and the main exit, your program will terminate immediately, so you should at least add a while(True): sleep(5) at the end, but it's not a solution.
I'm running a python server using the socketserver module in python 2.7. OmniPeek packet analysis tool shows the TCP handshake completes,
but the server immediately sends a reset packet killing the connection.
Simplified server code which shows the problem is:
from threading import Lock, Thread, Condition
import SocketServer
import socket
import sys
import time
class ThreadedTCPRequestHandler(SocketServer.BaseRequestHandler):
def __init__(self, state, *args, **keys):
try:
state['lock'].acquire()
state['client_count'] += 1
finally:
state['lock'].release()
self.state = state
SocketServer.BaseRequestHandler.__init__(self, *args, **keys)
def handle(self):
self.state['lock'].acquire()
count = self.state['client_count']
self.state['lock'].release()
while True:
try:
self.state['lock'].acquire()
running = self.state['running']
self.state['lock'].release()
if not running:
break;
time.sleep(1) # do some work
except Exception as msg:
print msg
print "ThreadedTCPRequestHandler shutting down..."
class ThreadedTCPServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
pass
def handler_factory(state):
def createHandler(*args, **keys):
return ThreadedTCPRequestHandler(state, *args, **keys)
return createHandler
if __name__ == "__main__":
lock = Lock()
cv = Condition(lock)
state = {'running': True, 'client_count': 0, 'lock': lock, 'cv': cv}
server = ThreadedTCPServer(('localhost', 12345), handler_factory(state))
server_thread = Thread(target=server.serve_forever)
server_thread.daemon = True
server_thread.start()
print "Server loop running in thread:", server_thread.name
# wait for a client to connect
cv.acquire()
while state['client_count'] == 0 and state['running']:
cv.wait(1.0)
# print msg
cv.release()
# substitute real work here...
time.sleep(5)
lock.acquire()
state['running'] = False
lock.release()
server.shutdown()
and the client code:
import socket
if __name__ == "__main__":
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'ip: {} port {}'.format('10.4.2.54', 12345)
client.connect(('10.4.2.54', 12345))
while True:
data = client.recv(4096)
if len(data) == 0:
break;
print 'data: {}'.format(data)
client.shutdown(socket.SHUT_RDWR)
client.close()
except Exception as msg:
print msg
The server code is based off python 2.7 docs serversocket Mixin example, and seems pretty straightforward, but...
Thanks
not sure what your expected behaviour is but if you make a couple of changes, you'll be able to see that it can work
replace your handle method
def handle(self):
while True:
try:
data = self.request.recv(1024).strip()
if len(data) != 0:
print data
time.sleep(1) # do some work
self.request.send('test data')
except Exception as msg:
print msg
break
print "ThreadedTCPRequestHandler shutting down..."
and client(inside main):
try:
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print 'ip: {} port {}'.format('localhost', 1232)
client.connect(('localhost', 1232))
client.send('test')
n = 0
while True:
data = client.recv(4096)
if len(data) != 0:
print 'data: {}'.format(data)
time.sleep(1)
n += 1
client.send('keep-alive' + str(n) + '\n')
print 'here'
client.shutdown(socket.SHUT_RDWR)
client.close()
except Exception as msg:
print msg
I just modded it to send stuff and print stuff. But it doesn't crash.
I think there is an issue with your self.state['lock'].acquire() and release() calls. I took out the 'running' check as it's not really used except at the end of the server code.
Also, without any action, sockets will time out.
Once again, I'm not claiming to have 'fixed' your problem...and I'm not sure exactly what you are looking for...just helping you brainstorm!
Apologies - red herring. The problem is only occurring under VM when server is running under guest and client is running under host. TCP reset packet never sent when both client and server are running either on host or guest
I am writing a program in Python and a part of it is scanning for active ports on a website. in the module scanports, while if I were to say scan ports 79 to 81, I know that it should return a list with 80 in it. I know this for sure because when I run scanport it shows port 80 is up. Sorry for not having any comments:
import subprocess, socket, urllib2, sys
class pymap:
def __init__(self):
pass
################################################################################
################################################################################
def host(self, host):
self.host = host
socket1 = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock = socket1
################################################################################
################################################################################
def getip(self):
if self.host == None:
print "Specify a host first."
else:
return socket.gethostbyname(self.host)
################################################################################
################################################################################
def scanports(self, start, end):
ports = []
self.sock.settimeout(0.000001)
for i in xrange(start, end+1): #49151
try:
self.sock.connect((self.host, i))
ports.append(i)
except:
pass
return i
################################################################################
################################################################################
def scanport(self, port1):
self.sock.settimeout(0.000001)
try:
self.sock.connect((self.host, port1))
return 1
except:
return 0
################################################################################
################################################################################
def traceroute(self):
if self.host == None:
print "Specify a host first."
else:
proc=subprocess.Popen(('tracert', self.host), shell=True, stdout=subprocess.PIPE)
output=proc.communicate()[0]
return output
################################################################################
################################################################################
def getsource(self, url):
page = urllib2.urlopen(url)
return page.read()
################################################################################
################################################################################
x = pymap()
x.host("www.google.com")
print x.scanports(70, 85)
print x.scanport(80)
EDIT:
I changed it, thanks James Henstridge for pointing out that I was using the iteration variable, otherwise it would be much harder. However, it still doesn't work:
def scanports(self, start, end):
ports = []
self.sock.settimeout(3)
for i in xrange(start, end+1): #49151
try:
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, port1))
self.sock.close()
ports.append(i)
except:
pass
return ports
EDIT: I figured it out, it was a problem with ports.append, thanks for your help.
There are a few issues with your code:
Your scanports method is returning the loop iteration variable, so it will always return end no matter what ports it detects. Perhaps you meant to return the ports list instead?
You are reusing the same socket over and over. From the connect system call man page:
Generally, connection-based protocol sockets may successfully connect() only once
So if you want to test multiple connection attempts, create a new socket each time. You should also close those sockets after use.
Good evening, This is my 1st time on this site, I have been programming a python based user monitoring system for my work for the past 3 months and I am almost done with my 1st release. However I have run into a problem controlling what computer I want to connect to.
If i run the two sample code I put in this post I can receive the client and send commands to client with the server, but only one client at a time, and the server is dictating which client I can send to and which one is next. I am certain the problem is "server side but I am not sure how to fix the problem and a Google search does not turn up anyone having tried this.
I have attached both client and server base networking code in this post.
client:
import asyncore
import socket
import sys
do_restart = False
class client(asyncore.dispatcher):
def __init__(self, host, port=8000):
serv = open("srv.conf","r")
host = serv.read()
serv.close()
asyncore.dispatcher.__init__(self)
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.connect((host, port))
def writable(self):
return 0
def handle_connect(self):
pass
def handle_read(self):
data = self.recv(4096)
#Rest of code goes here
serv = open("srv.conf","r")
host = serv.read()
serv.close()
request = client(host)
asyncore.loop()
server:
import asyncore
import socket
import sys
class soc(asyncore.dispatcher):
def __init__(self, port=8000):
asyncore.dispatcher.__init__(self)
self.port = port
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.bind(('', port))
self.listen(5)
def handle_accept(self):
channel, addr = self.accept()
while 1:
j = raw_input(addr)
#Rest of my code is here
server = soc(8000)
asyncore.loop()
Here is a fast and dirty idea that I threw together.
The use of raw_input has been replaced with another dispatcher that is asyncore compatable, referencing this other question here
And I am expanding on the answer given by #user1320237 to defer each new connection to a new dispatcher.
You wanted to have a single command line interface that can send control commands to any of the connected clients. That means you need a way to switch between them. What I have done is created a dict to keep track of the connected clients. Then we also create a set of available commands that map to callbacks for your command line.
This example has the following:
list: list current clients
set <client>: set current client
send <msg>: send a msg to the current client
server.py
import asyncore
import socket
import sys
from weakref import WeakValueDictionary
class Soc(asyncore.dispatcher):
CMDS = {
'list': 'cmd_list',
'set': 'cmd_set_addr',
'send': 'cmd_send',
}
def __init__(self, port=8000):
asyncore.dispatcher.__init__(self)
self._conns = WeakValueDictionary()
self._current = tuple()
self.port = port
self.create_socket(socket.AF_INET, socket.SOCK_STREAM)
self.set_reuse_addr()
self.bind(('', port))
self.listen(5)
self.cmdline = Cmdline(self.handle_input, sys.stdin)
self.cmdline.prompt()
def writable(self):
return False
def handle_input(self, i):
tokens = i.strip().split(None, 1)
cmd = tokens[0]
arg = ""
if len(tokens) > 1:
arg = tokens[1]
cbk = self.CMDS.get(cmd)
if cbk:
getattr(self, cbk)(arg)
self.cmdline.prompt(self._addr_to_key(self._current))
def handle_accept(self):
channel, addr = self.accept()
c = Conn(channel)
self._conns[self._addr_to_key(addr)] = c
def _addr_to_key(self, addr):
return ':'.join(str(i) for i in addr)
def cmd_list(self, *args):
avail = '\n'.join(self._conns.iterkeys())
print "\n%s\n" % avail
def cmd_set_addr(self, addr_str):
conn = self._conns.get(addr_str)
if conn:
self._current = conn.addr
def cmd_send(self, msg):
if self._current:
addr_str = self._addr_to_key(self._current)
conn = self._conns.get(addr_str)
if conn:
conn.buffer += msg
class Cmdline(asyncore.file_dispatcher):
def __init__(self, cbk, f):
asyncore.file_dispatcher.__init__(self, f)
self.cbk = cbk
def prompt(self, msg=''):
sys.stdout.write('%s > ' % msg)
sys.stdout.flush()
def handle_read(self):
self.cbk(self.recv(1024))
class Conn(asyncore.dispatcher):
def __init__(self, *args, **kwargs):
asyncore.dispatcher.__init__(self, *args, **kwargs)
self.buffer = ""
def writable(self):
return len(self.buffer) > 0
def handle_write(self):
self.send(self.buffer)
self.buffer = ''
def handle_read(self):
data = self.recv(4096)
print self.addr, '-', data
server = Soc(8000)
asyncore.loop()
Your main server is now never blocking on stdin, and always accepting new connections. The only work it does is the command handling which should either be a fast operation, or signals the connection objects to handle the message.
Usage:
# start the server
# start 2 clients
>
> list
127.0.0.1:51738
127.0.0.1:51736
> set 127.0.0.1:51736
127.0.0.1:51736 >
127.0.0.1:51736 > send foo
# client 127.0.0.1:51736 receives "foo"
To me
while 1:
j = raw_input(addr)
seems to be the problem:
you only accept a socket an then do something with it until end.
You should create e new dispatcher for every client connecting
class conn(asyncore.dispatcher):
...
def handle_read(self):
...
class soc(asyncore.dispatcher):
def handle_accept(self):
...
c = conn()
c.set_socket(channel)
Asyncore will call you back for every read operation possible.
Asyncore uses only one thread. This is its strength. every dispatcher that has a socket is called one after an other with those handle_* functions.