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]

    (完全完)


  • 相关阅读:
    C++ 并发编程 01 线程api
    C# CS1591 缺少对公共可见类型或成员的 XML 注释 问题解决
    Web Api HelpPage
    C++11新特性介绍 02
    C++11新特性介绍 01
    Autofac框架详解
    Linux gdb调试器用法全面解析
    BCM_SDK命令
    VLAN
    java_Observer Design Pattern
  • 原文地址:https://www.cnblogs.com/haippy/p/2314036.html
Copyright © 2011-2022 走看看