服务端的代码

import socket
import queue
import select
ip_bind = ("127.0.0.1",9000)

message_queue = {}
#保存客户端发送过来的信息,将消息放入到队列中

input_list = []

output_list = []

if __name__ == '__main__':
    server = socket.socket()
    server.bind(ip_bind)
    server.listen(10)
    server.setblocking(False)
    #设置socket服务端为非阻塞的

    input_list.append(server)
    #初始化将服务端加入到监听列表中

    while True:
        print("waiting for new connection")
        stdinput,stdoutput,stderr = select.select(input_list,output_list,input_list,2)
        #开始select监听,对input_list中的服务端server进行监听


        for obj in stdinput:
            #判断是否有客户端连接进来,当有客户端连接进来时select将触发,就会进入循环

            if obj == server:  #代表一个新的连接进来
                #判断当前触发的是不是服务端的对象,当触发的对象是服务端的对象时候,说明
                #有新的客户端连接进来了

                conn,addr = server.accept()
                print("Client {0} is connected".format(addr))
                conn.setblocking(False)
                #把这个新连接的实例设置为非阻塞

                #这个时候我们不能立即接受数据,因为在select中,是单线程的,如果这里直接开始接受数据,那么其他的客户端就无法连接进来了,所以只能
                #先把这个链接存起来,放到一个input_list中,为什么放到input_list中呢,因为我们想监控这个链接,如果这个客户端有消息过来,那么select
                #就会触发,如果没有数据返回,则select就不会被触发

                input_list.append(conn)
                #将和这个客户端的连接的服务端的实例也加入到监听列表中,当客户端发送消息的
                #时候,select就会被触发

                message_queue[conn] = queue.Queue()
                #为这个连接的客户端单独创建一个独一无二的消息队列,用来保存客户端发送的消息。


            else:  #代表一个有数据的链接进来了,这个时候我就可以开始收数据了

                #由于客户端连接进来时服务端接受客户端的连接请求,将这个客户端的服务端的
                #也加入到监听列表中,这个客户端如果发送消息,则会触发select
                try:
                    recv_data = obj.recv(1024)
                    if recv_data:
                        #客户端未断开
                        print("received {0} from client {1}".format(str(recv_data,encoding="utf-8"),addr))

                        #将收到的信息放入该客户端的队列中
                        message_queue[obj].put(recv_data)

                        #此时也不能直接给客户端返回数据,因为一旦返回数据,就又可能造成阻塞,所有将回复操作放到output列表中,让select监听
                        if obj not in output_list:
                            output_list.append(obj)


                except ConnectionResetError:
                    input_list.remove(obj)
                    del message_queue[obj]
                    print("client {0} is disconnected".format(addr))

        for sendobj in stdoutput: #这里处理的是返回的消息,output_list是我们自己维护的,我们自己往里面放数据
            try:
                if not message_queue[sendobj].empty():
                #如果消息队列中有消息,从消息队列中获取要发送的消息
                    send_data = message_queue[sendobj].get()
                    #从该客户端对象的消息队列中获取消息
                    sendobj.sendall(send_data)
                else:
                    output_list.remove(sendobj)
                    #将监听移除等待瞎猜疑客户端发送消息
            except ConnectionResetError:
                #客户端连接断开
                del  message_queue[sendobj]
                output_list.remove(sendobj)
                print("Client {0} disconnected".format(addr))

        for obj in stderr:  #如果出错的处理
            # print()
            input_list.remove(obj)
            if obj in output_list:
                output_list.remove(obj)
            obj.close()
            del message_queue[obj]

  

posted on 2017-09-03 00:22  bainianminguo  阅读(628)  评论(0编辑  收藏  举报