Advertisement
rfmonk

chat_server.py

Jun 18th, 2014
325
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 5.85 KB | None | 0 0
  1. #!/usr/bin/env python
  2. #
  3. # usage - in one window type
  4. # chat_server.py --name=server --port=8080 or whatever
  5. # in another window
  6. # chat_server.py --name-client1 --port=8080 or whatever your server was
  7. # thanks to faruq
  8.  
  9. import select
  10. import socket
  11. import sys
  12. import signal
  13. import cPickle
  14. import struct
  15. import argparse
  16.  
  17. SERVER_HOST = 'localhost'
  18. CHAT_SERVER_NAME = 'server'
  19.  
  20. def send(channel, *args):
  21.     buffer = cPickle.dumps(args)
  22.     value = socket.htonl(len(buffer))
  23.     size = struct.pack("L", value)
  24.     channel.send(size)
  25.     channel.send(buffer)
  26.  
  27. def receive(channel):
  28.     size = struct.calcsize("L")
  29.     size = channel.recv(size)
  30.     try:
  31.         size = socket.ntohl(struct.unpack("L", size) [0])
  32.     except struct.error, e:
  33.         return ''
  34.     buf = ""
  35.     while len(buf) < size:
  36.         buf = channel.recv(size -len(buf))
  37.         return cPickle.loads(buf)[0]
  38.  
  39.  
  40. class ChatServer(object):
  41.     """ An example chat server using select"""
  42.     def __init__(self, port, backlog=5):
  43.         self.clients = 0
  44.         self.clientmap = {}
  45.         self.outputs = []  # list output sockets
  46.         self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  47.         # Enable reusing socket address
  48.         self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  49.         self.server.listen(backlog)
  50.         # Catch keyboard interrupts
  51.         signal.signal(signal.SIGINT, self.sighandler)
  52.  
  53.     def sighandler(self, signum, frame):
  54.         """ Clean up clients outputs"""
  55.         # Close the server
  56.         print 'Shutting down server...'
  57.         # Close existing client sockets
  58.         for output in self.outputs:
  59.             output.close()
  60.         self.server.close()
  61.  
  62.     def get_client_name(self, client):
  63.         """ Return the name of the client"""
  64.         info = self.clientmap[client]
  65.         host, name = info[0][0], info[1]
  66.         return '@'.join((name, host))
  67.  
  68.     def run(self):
  69.         inputs = [self.server, sys.stdin]
  70.         self.outputs = []
  71.         running = True
  72.         while running:
  73.             try:
  74.                 readable, writeable, exceptional = \
  75.                 select.select(inputs, self.outputs, [])
  76.             except select.error, e:
  77.                     break
  78.             for sock in readable:
  79.                 if sock == self.server:
  80.                     # handle the server socket
  81.                     client, address = self.server.accept()
  82.                     print "Chat server: got connection %d from %s" %\
  83.                     (client.fileno(), address)
  84.                     # Read the login name
  85.                     cname = receive(client).split('NAME: ')[1]
  86.                     # Compute the clients name and send back
  87.                     self.clients += 1
  88.                     send(client, 'CLIENT: ' + str(address[0]))
  89.                     inputs.append(client)
  90.                     self.clientmap[client] = (address, cname)
  91.                     # Send joining information to other clients
  92.                     msg = "\n(Connected: New client (%d) from %s)" %\
  93.                     (self.clients, self.get_client_name(client))
  94.                     for output in self.outputs:
  95.                         send(output, msg)
  96.                     self.outputs.append(client)
  97.                 elif sock == sys.stdin:
  98.                     # handle standard input
  99.                     junk = sys.stdin.readline()
  100.                     running = False
  101.                 else:
  102.                     # Handle all other sockets
  103.                     try:
  104.                         data = receive(sock)
  105.                         if data:
  106.                             # Send as new client's message...
  107.                             msg = '\n#[' + self.get_client_name(sock)\
  108.                             + ']>>' + data
  109.                             # Send data to all except ourself
  110.                             for output in self.outputs:
  111.                                 if output != sock:
  112.                                     send(output, msg)
  113.  
  114.                             else:
  115.                                 print "Chat server: %d hung up" % \
  116.                                 sock.fileno()
  117.                                 self.clients -= 1
  118.                                 sock.close()
  119.                                 inputs.remove(sock)
  120.                                 self.outputs.remove(sock)
  121.                                 # Sending client leaving info to others
  122.                                 msg = "\n(Now hung up: Client from %s)" %\
  123.                                 self.get_client_name(sock)
  124.                                 for output in self.outputs:
  125.                                     send(output, msg)
  126.                     except socket.error, e:
  127.                         # Remove
  128.                         inputs.remove(sock)
  129.                         self.outputs.remove(sock)
  130.             self.server.close()
  131.  
  132.  
  133. class ChatClient(object):
  134.     """ A command line chat client using select """
  135.  
  136.     def __init__(self, name, port, host=SERVER_HOST):
  137.         self.name = name
  138.         self.connected = False
  139.         self.host = host
  140.         self.port = port
  141.         # Initial prompt
  142.         self.prompt='[' + '@'.join((name, socket.gethostname().split('.') [0])) + ']> '
  143.         # Connect to server at port
  144.         try:
  145.             self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  146.             self.sock.connect((host, self.port))
  147.             print "Now connected to chat server@ port %d" % self.port
  148.             self.connected = True
  149.             # Send my name ...
  150.             send(self.sock, 'NAME: ' + self.name)
  151.             data = receive(self.sock)
  152.             # Contains client address, set it
  153.             addr = data.split('CLIENT: ') [1]
  154.             self.prompt = '[' + '@'.join((self.name, addr)) + ']> '
  155.         except socket.error, e:
  156.             print "Failed to connect to chat server @ port %d" % self.port
  157.             sys.exit(1)
  158.  
  159.     def run(self):
  160.         """ Chat client main loop """
  161.         while self.connected:
  162.             try:
  163.                 sys.stdout.write(self.prompt)
  164.                 sys.stdout.flush()
  165.                 # Wait for input from stdin and socket
  166.                 readable, writeable, exceptional = select.select([0, self.sock], [], [])
  167.                 for sock in readable:
  168.                     if sock == 0:
  169.                         data = sys.stdin.readline().strip()
  170.                         if data: send(self.sock, data)
  171.                     elif sock == self.sock:
  172.                         data = receive(self.sock)
  173.                         if not data:
  174.                             print 'Client shutting down.'
  175.                             self.connected = False
  176.                             break
  177.                         else:
  178.                             sys.stdout.write(data + '\n')
  179.                             sys.stdout.flush()
  180.  
  181.             except KeyboardInterrupt:
  182.                 print " Client interrupted. """
  183.                 self.sock.close()
  184.                 break
  185.  
  186. if __name__ == "__main__":
  187.     parser = argparse.ArgumentParser(description='Socket Server with Select')
  188.     parser.add_argument('--name', action="store", dest="name", required=True)
  189.     parser.add_argument('--port', action="store", dest="port", type=int, required=True)
  190.     given_args = parser.parse_args()
  191.     port = given_args.port
  192.     name = given_args.name
  193.     if name == CHAT_SERVER_NAME:
  194.         server = ChatServer(port)
  195.         server.run()
  196.     else:
  197.         client = ChatClient(name=name, port=port)
  198.         client.run()
  199. """ so when i run this program on desktop computer i get the error
  200. that it Failed to connect on port xxxxx as was coded into the chat
  201. client part of the program, this might be due to the locked-down nature
  202. of that computer. I will rerun this on my dev laptop latter, but i think
  203. its working finally  """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement