2653885 发表于 2015-4-20 11:13:15

Python简单的多客户端聊天室程序

  本文所示代码将教你如何使用Python标准库中的select.select模块实现多路复用的命令行下CS模式的聊天室程序。
  服务器端代码:



#!/usr/bin/env python

"""
A basic, multiclient 'chat server' using Python's select module
with interrupt handling.
Entering any input at the terminal will exit the server.
"""
import select
import socket
import sys
import signal
from communication import send, receive
BUFSIZ = 4096

class ChatServer(object):
    """ Simple chat server using select """
    def __init__(self, port=3490, backlog=5):
      self.clients = 0
      # Client map
      self.clientmap = {}
      # Output socket list
      self.outputs = []
      self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
      self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      self.server.bind(('',port))
      print 'Listening to port',port,'...'
      self.server.listen(backlog)
      # Trap keyboard interrupts
      signal.signal(signal.SIGINT, self.sighandler)
    def sighandler(self, signum, frame):
      # Close the server
      print 'Shutting down server...'
      # Close existing client sockets
      for o in self.outputs:
            o.close()
      self.server.close()
    def getname(self, client):
      # Return the printable name of the
      # client, given its socket...
      info = self.clientmap
      host, name = info, info
      return '@'.join((name, host))
    def serve(self):
      inputs =
      self.outputs = []
      running = 1
      while running:
            try:
                inputready,outputready,exceptready = select.select(inputs, self.outputs, [])
            except select.error, e:
                break
            except socket.error, e:
                break
            for s in inputready:
                if s == self.server:
                  # handle the server socket
                  client, address = self.server.accept()
                  print 'chatserver: got connection %d from %s' % (client.fileno(), address)
                  # Read the login name
                  cname = receive(client).split('NAME: ')
                  # Compute client name and send back
                  self.clients += 1
                  send(client, 'CLIENT: ' + str(address))
                  inputs.append(client)
                  self.clientmap = (address, cname)
                  # Send joining information to other clients
                  msg = '\n(Connected: New client (%d) from %s)' % (self.clients, self.getname(client))
                  for o in self.outputs:
                        # o.send(msg)
                        send(o, msg)
                  self.outputs.append(client)
                elif s == sys.stdin:
                  # handle standard input
                  junk = sys.stdin.readline()
                  running = 0
                else:
                  # handle all other sockets
                  try:
                        # data = s.recv(BUFSIZ)
                        data = receive(s)
                        if data:
                            # Send as new client's message...
                            msg = '\n#[' + self.getname(s) + ']>> ' + data
                            # Send data to all except ourselves
                            for o in self.outputs:
                              if o != s:
                                    # o.send(msg)
                                    send(o, msg)
                        else:
                            print 'chatserver: %d hung up' % s.fileno()
                            self.clients -= 1
                            s.close()
                            inputs.remove(s)
                            self.outputs.remove(s)
                            # Send client leaving information to others
                            msg = '\n(Hung up: Client from %s)' % self.getname(s)
                            for o in self.outputs:
                              # o.send(msg)
                              send(o, msg)
                  except socket.error, e:
                        # Remove
                        inputs.remove(s)
                        self.outputs.remove(s)
                        

      self.server.close()
if __name__ == "__main__":
    ChatServer().serve()
  客户端代码:



#! /usr/bin/env python
"""
Simple chat client for the chat server. Defines
a simple protocol to be used with chatserver.
"""
import socket
import sys
import select
from communication import send, receive
BUFSIZ = 1024
class ChatClient(object):
    """ A simple command line chat client using select """
    def __init__(self, name, host='127.0.0.1', port=3490):
      self.name = name
      # Quit flag
      self.flag = False
      self.port = int(port)
      self.host = host
      # Initial prompt
      self.prompt='[' + '@'.join((name, socket.gethostname().split('.'))) + ']> '
      # Connect to server at port
      try:
            self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.sock.connect((host, self.port))
            print 'Connected to chat server@%d' % self.port
            # Send my name...
            send(self.sock,'NAME: ' + self.name)
            data = receive(self.sock)
            # Contains client address, set it
            addr = data.split('CLIENT: ')
            self.prompt = '[' + '@'.join((self.name, addr)) + ']> '
      except socket.error, e:
            print 'Could not connect to chat server @%d' % self.port
            sys.exit(1)
    def cmdloop(self):
      while not self.flag:
            try:
                sys.stdout.write(self.prompt)
                sys.stdout.flush()
                # Wait for input from stdin & socket
                inputready, outputready,exceptrdy = select.select(, [],[])
                for i in inputready:
                  if i == 0:
                        data = sys.stdin.readline().strip()
                        if data: send(self.sock, data)
                  elif i == self.sock:
                        data = receive(self.sock)
                        if not data:
                            print 'Shutting down.'
                            self.flag = True
                            break
                        else:
                            sys.stdout.write(data + '\n')
                            sys.stdout.flush()
            except KeyboardInterrupt:
                print 'Interrupted.'
                self.sock.close()
                break
if __name__ == "__main__":
    import sys
    if len(sys.argv)
页: [1]
查看完整版本: Python简单的多客户端聊天室程序