zoukankan      html  css  js  c++  java
  • 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[client]
    host, name = info[0][0], info[1]
    return '@'.join((name, host))

    def serve(self):

    inputs = [self.server,sys.stdin]
    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: ')[1]

    # Compute client name and send back
    self.clients += 1
    send(client, 'CLIENT: ' + str(address[0]))
    inputs.append(client)

    self.clientmap[client] = (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('.')[0])) + ']> '
    # 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: ')[1]
    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([0, self.sock], [],[])

    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)<3:
    sys.exit('Usage: %s chatid host portno' % sys.argv[0])

    client = ChatClient(sys.argv[1],sys.argv[2], int(sys.argv[3]))
    client.cmdloop()

    communication模块代码:

    import cPickle
    import socket
    import struct

    marshall = cPickle.dumps
    unmarshall = cPickle.loads

    def send(channel, *args):
    buf = marshall(args)
    value = socket.htonl(len(buf))
    size = struct.pack("L",value)
    channel.send(size)
    channel.send(buf)

    def receive(channel):

    size = struct.calcsize("L")
    size = channel.recv(size)
    try:
    size = socket.ntohl(struct.unpack("L", size)[0])
    except struct.error, e:
    return ''

    buf = ""

    while len(buf) < size:
    buf = channel.recv(size - len(buf))

    return unmarshall(buf)[0]

    (完全完)


  • 相关阅读:
    如何向线程传递参数
    IntelliJ IDEA 13 Keygen
    单链表的基本操作
    顺序表静态查找
    有向图的十字链表表存储表示
    BF-KMP 算法
    图的邻接表存储表示(C)
    二叉树的基本操作(C)
    VC远控(三)磁盘显示
    Android 数独游戏 记录
  • 原文地址:https://www.cnblogs.com/haippy/p/2314036.html
Copyright © 2011-2022 走看看