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]

    (完全完)


  • 相关阅读:
    Windows 服务多语言化时读取配置文件失败的问题。
    从开始界面卸载Windows服务时,不小心点击了 取消,此后再次卸载会卸载不掉
    从数据库导出数据时,有的字段是时间,不同的时间向在窗口中去掉时用正则表达式匹配找到不同的时间
    C#使用ManagementObjectSearcher来获取系统信息时会有out of memory的异常
    C# TreeView设置SelectedNode设置无效的问题
    C#判断ListBox是否显示了水平滚动条/横向滚动条
    Jmeter运行不显示cmd对话框
    监控Linux系统所选的服务所占进程内存占用
    Linux的date用法
    shell的循环嵌套语法
  • 原文地址:https://www.cnblogs.com/haippy/p/2314036.html
Copyright © 2011-2022 走看看