zoukankan      html  css  js  c++  java
  • 基于select的python聊天室程序

    python网络编程具体参考《python select网络编程详细介绍》

    在python中,select函数是一个对底层操作系统的直接访问的接口。它用来监控sockets、files和pipes,等待IO完成(Waiting for I/O completion)。当有可读、可写或是异常事件产生时,select可以很容易的监控到。
    select.select(rlist, wlist, xlist[, timeout]) 传递三个参数,一个为输入而观察的文件对象列表,一个为输出而观察的文件对象列表和一个观察错误异常的文件列表。第四个是一个可选参数,表示超时秒数。其返回3个tuple,每个tuple都是一个准备好的对象列表,它和前边的参数是一样的顺序。

    聊天室程序如下。运行多个client,则可互相聊天,输入"exit"即可退出

    服务器代码

    #!/bin/env python
    #-*- coding:utf8 -*-
    
    """
    server select
    """
    
    
    import sys
    import time
    import socket
    import select
    import logging
    import Queue
    
    
    g_select_timeout = 10
    
    class Server(object):
        def __init__(self, host='10.1.32.80', port=33333, timeout=2, client_nums=10):
            self.__host = host
            self.__port = port
            self.__timeout = timeout
            self.__client_nums = client_nums
            self.__buffer_size = 1024
    
            self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.server.setblocking(False)
            self.server.settimeout(self.__timeout)
            self.server.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) #keepalive
            self.server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #端口复用
            server_host = (self.__host, self.__port)
            try:
                self.server.bind(server_host)
                self.server.listen(self.__client_nums)
            except:
                raise
    
            self.inputs = [self.server] #select 接收文件描述符列表  
            self.outputs = [] #输出文件描述符列表
            self.message_queues = {}#消息队列
            self.client_info = {}
    
        def run(self):
            while True:
                readable , writable , exceptional = select.select(self.inputs, self.outputs, self.inputs, g_select_timeout)
                if not (readable or writable or exceptional) :
                    continue
    
                for s in readable :
                    if s is self.server:#是客户端连接
                        connection, client_address = s.accept()
                        #print "connection", connection
                        print "%s connect." % str(client_address)
                        connection.setblocking(0) #非阻塞
                        self.inputs.append(connection) #客户端添加到inputs
                        self.client_info[connection] = str(client_address)
                        self.message_queues[connection] = Queue.Queue()  #每个客户端一个消息队列
    
                    else:#是client, 数据发送过来
                        try:
                            data = s.recv(self.__buffer_size)
                        except:
                            err_msg = "Client Error!"
                            logging.error(err_msg)
                        if data :
                            #print data
                            data = "%s %s say: %s" % (time.strftime("%Y-%m-%d %H:%M:%S"), self.client_info[s], data)
                            self.message_queues[s].put(data) #队列添加消息 
                            
                            if s not in self.outputs: #要回复消息
                                self.outputs.append(s)
                        else: #客户端断开
                            #Interpret empty result as closed connection
                            print "Client:%s Close." % str(self.client_info[s])
                            if s in self.outputs :
                                self.outputs.remove(s)
                            self.inputs.remove(s)
                            s.close()
                            del self.message_queues[s]
                            del self.client_info[s]
    
                for s in writable: #outputs 有消息就要发出去了
                    try:
                        next_msg = self.message_queues[s].get_nowait()  #非阻塞获取
                    except Queue.Empty:
                        err_msg = "Output Queue is Empty!"
                        #g_logFd.writeFormatMsg(g_logFd.LEVEL_INFO, err_msg)
                        self.outputs.remove(s)
                    except Exception, e:  #发送的时候客户端关闭了则会出现writable和readable同时有数据,会出现message_queues的keyerror
                        err_msg = "Send Data Error! ErrMsg:%s" % str(e)
                        logging.error(err_msg)
                        if s in self.outputs:
                            self.outputs.remove(s)
                    else:
                        for cli in self.client_info: #发送给其他客户端
                            if cli is not s:
                                try:
                                    cli.sendall(next_msg)
                                except Exception, e: #发送失败就关掉
                                    err_msg = "Send Data to %s  Error! ErrMsg:%s" % (str(self.client_info[cli]), str(e))
                                    logging.error(err_msg)
                                    print "Client: %s Close Error." % str(self.client_info[cli])
                                    if cli in self.inputs:
                                        self.inputs.remove(cli)
                                        cli.close()
                                    if cli in self.outputs:
                                        self.outputs.remove(s)
                                    if cli in self.message_queues:
                                        del self.message_queues[s]
                                    del self.client_info[cli]
    
                for s in exceptional:
                    logging.error("Client:%s Close Error." % str(self.client_info[cli]))
                    if s in self.inputs:
                        self.inputs.remove(s)
                        s.close()
                    if s in self.outputs:
                        self.outputs.remove(s)
                    if s in self.message_queues:
                        del self.message_queues[s]
                    del self.client_info[s]
            
    
    if "__main__" == __name__:
        Server().run()

    客户端代码

    #!/usr/local/bin/python
    # *-* coding:utf-8 -*-
    
    """
    client.py
    """
    
    
    import sys
    import time
    import socket
    import threading
    
    
    class Client(object):
        def __init__(self, host, port=33333, timeout=1, reconnect=2):
            self.__host = host
            self.__port = port
            self.__timeout = timeout
            self.__buffer_size = 1024
            self.__flag = 1
            self.client = None
            self.__lock = threading.Lock() 
        
        @property
        def flag(self):
            return self.__flag
    
        @flag.setter
        def flag(self, new_num):
            self.__flag = new_num
    
        def __connect(self):
            client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            #client.bind(('0.0.0.0', 12345,))
            client.setblocking(True)
            client.settimeout(self.__timeout)
            client.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) #端口复用
            server_host = (self.__host, self.__port)
            try:
                client.connect(server_host)
            except:
                raise
            return client
    
        def send_msg(self):
            if not self.client:
                return
            while True:
                time.sleep(0.1)
                #data = raw_input()
                data = sys.stdin.readline().strip()
                if "exit" == data.lower():
                    with self.__lock:
                        self.flag = 0
                    break
                self.client.sendall(data)
            return
    
        def recv_msg(self):
            if not self.client:
                return
            while True:
                data = None
                with self.__lock:
                    if not self.flag:
                        print 'ByeBye~~'
                        break
                try:
                    data = self.client.recv(self.__buffer_size)
                except socket.timeout:
                    continue
                except:
                    raise
                if data:
                    print "%s
    " % data
                time.sleep(0.1)
            return
    
        def run(self):
            self.client = self.__connect()
            send_proc = threading.Thread(target=self.send_msg)
            recv_proc = threading.Thread(target=self.recv_msg)
            recv_proc.start()
            send_proc.start()
            recv_proc.join()
            send_proc.join()
            self.client.close()
    
    
    if "__main__" == __name__:
        Client('10.1.32.80').run()
  • 相关阅读:
    JSON对象和字符串之间的相互转换
    Loadrunner 运行场景时:missing newline in XXX.dat 错误解决
    linux grep详解
    Object 保存到文件中
    'libxml/tree.h' file not found
    具有相同值的不同字符串常量在内存中是分开存储的
    为右键添加快速进入CMD的选项,Win7更简单
    iOS KVO & KVC
    南阳数乌龟——递归超时
    LibSVM笔记系列(3)——初学移植libsvm的C/C++版本
  • 原文地址:https://www.cnblogs.com/lxmhhy/p/6093159.html
Copyright © 2011-2022 走看看