/apple/ - 12421 - #228813 - 2017-06-09 15:16:33 Ø
```
import socket
import select
import Queue
from threading import Thread
# from time import sleep
# from random import randint - no need for random values, may be later
# for some kind of identification keys or something
import sys


# used for external process running & other processing
class ProcessThread(Thread):
def __init__(self):
super(ProcessThread, self).__init__()
self.running = True
self.q = Queue.Queue()

def add(self, data):
self.q.put(data)

def stop(self):
self.running = False

def run(self):
q = self.q
while self.running:
try:
# block for 0.1 second only:
value = q.get(block=True, timeout=0.1)
process(value)
except Queue.Empty:
pass # do nothing I guess
# sys.stdout.write('.') dots to show activity
# sys.stdout.flush()
#
if not q.empty():
print "Elements left in the queue:"
while not q.empty():
print q.get()


def process(value): # nice place for parser or something else for ex.
print 'External thread processing value:'
print value
print 'Trying to execute shell command'
# We should pass all the messages to other clients somehow
# sleep(randint(1, 9)) # emulating processing time


def main(port, usingExternalThread):
s = socket.socket() # Create a socket object
host = socket.gethostname() # Get local machine name
# port = 55555 # cfg.PORT # Reserve a port for your service.
try:
s.bind((host, port)) # Bind to the port
print 'Welcome to py-chat server: an interactive chat &',
print 'remote code execution app.'
print "Listening on port {p}...".format(p=port)
except socket.error, msg:
print "Socket error on bind: %s Aborting." % msg
if usingExternalThread:
cleanup()
sys.exit(-1)
s.listen(5) # Now wait for client connection up to FIVE
inputs = [s, sys.stdin] # sys.stdin can be just another client
outputs = [] # we'll fill that as clients connect
clNames = [] # names, seen in chat
IDs = [] # ip+port unique values
# ip, prt
# no need to do something special about this.
while True:
try:
# classic select function '\' sign for line breaking
inputsReady, outsReady, ecxepts = \
select.select(inputs, outputs, [])
# getting index of iteraded lists ex:
# ints = [8, 23, 45, 12, 78]
# for idx, val in enumerate(ints):
# print(idx, val)
# for idx, ss in enumerate(inputsReady):
for ss in inputsReady:
# idx - index, ss - iterator to socket object
if ss == s: # main socket ready, new client
client, addr = s.accept()
ip, prt = addr
inputs.append(client)
outputs.append(client)
newID = '{}:{}'.format(ip, prt)
IDs.append(newID)
newName = 'client{}'.format(len(IDs))
clNames.append(newName)
print 'New client from: {}, now named: {}'.format(newID, newName)
# may be some welcome message here
elif ss == sys.stdin: # got something from keyboard
toSend = '[server]{}'.format(sys.stdin.readline())
bcast(toSend, outsReady, ss)
# for o in outsReady:
# o.send(toSend)
# t.add(toSend) we are not planning to pass this to
# thread yet, may be later
else: # this case we've got data from socket
data = ss.recv(4096) # max data block size?
ip, prt = ss.getpeername()
senderID = '{}:{}'.format(ip, prt)
# print '[{}:{}]{}'.format(ip, prt, data.rstrip())
clID = ip2name(senderID, IDs)
if data:
# print clID
toSend = '[{}]{}'.format(clNames[clID], data)
# as we're not at bcast list being server just print
print toSend.rstrip()
# and now bcast to clients
bcast(toSend, outsReady, ss)
# re-send to all clients?
# simply strips whitespaces
# print ss, data.rsplit(';')
# separates to list with given sep
if usingExternalThread:
# if we pass data from socket to external thread
t.add(data) # see the above comments
else:
ip, prt = ss.getpeername()
ss.close()
inputs.remove(ss)
outputs.remove(ss)
# We have to update all ID's and names
# May be we should inform clients about changes?
print 'Lost connection with {} remaning clients'.format(clNames[clID])
del clNames[:]
del IDs[clID]
for x in IDs:
newName = 'client{}'.format(ip2name(x, IDs) + 1)
print 'ID: {} is now {}'.format(x, newName)
clNames.append(newName)
except socket.error, msg:
print "Socket error! %s" % msg
break
except KeyboardInterrupt:
print
print "Stop."
break
# except:
# print 'Unexpected error. Abotring.'
if usingExternalThread:
cleanup()


def ip2name(toFind, ids):
for idx, l in enumerate(ids):
# print 'searching ID:', l
if l == toFind:
return idx
return -1


# send to all outsReady except omit_socket
def bcast(str, outsReady, omit_socket):
for o in outsReady:
if o != omit_socket:
o.send(str)


def cleanup():
t.stop()
t.join()


def usage():
print 'Usage str'

# main() here

if __name__ == "__main__":
usingExternalThread = False
if usingExternalThread:
t = ProcessThread()
t.start()
try:
port = int(sys.argv[1])
except:
print 'Error on parsing port argument, set to default (55555)'
port = 55555
main(port, usingExternalThread)
```
Пока, конечно, крайне сыро, но уже работает, в следующей серии: трехмерные графики, бинарные файлы и может что-нибудь еще. Всем добра.