#方法:sk.setblocking(False)

#服务器端:
import socket
sk=socket.socket()
sk.setblocking(False)
sk.bind(('127.0.0.1',8080))
sk.listen()
#定义空列表用于存放各个conn
Conn_List = []
#定义删除列表用于删除Conn_List中断开连接的客户端conn
Conn_Del = []

while 1:
    try:
        conn,addr = sk.accept() #如果是阻塞IO,此时程序会一直在这里等待
        Conn_List.append(conn)  #将监听到的conn对象放到conn列表中,即为多客户端连接
    except BlockingIOError:
        '''如果try中没有客户端连接,则执行该代码块,判断客户端是否向服务器发送数据'''
        #遍历conn列表,看看有没有客户端发送数据
        for conn in Conn_List:
            try:
                #尝试接收数据
                info = conn.recv(1024).decode('utf-8')
                #注意!如果客户端正常关闭,即客户端执行了close,服务器会接收到一个空
                if not info:
                    #如果收到空,证明客户端断开连接,将该conn添加到删除列表中,用于后面删除Conn_List中对应的conn
                    Conn_Del.append(conn)
                    print('客户端已经断开连接了')
                    #在服务器中关闭对应的conn
                    conn.close()
                else:
                    '''服务器逻辑层'''
                    # 如果收到客户端的数据,逻辑层返回数据给客户端
                    print('这是接收到来自客户端{}的数据:{}'.format(conn,info))
                    #返回数据给客户端(例如将客户端的数据小写转为大写返回给客户端)
                    conn.send(info.upper().encode('utf-8'))
            except BlockingIOError:
                '''如果本次循环中该conn没有发送数据,则执行该代码块,即对下一个conn通信'''
                continue
            except ConnectionResetError:
                '''如果本次循环中该conn强制退出,则不执行任何操作'''
                pass
        #删除列表删除Conn_List中已经正常断开连接的客户端conn
        if Conn_Del:
            for conn in Conn_Del:
                Conn_List.remove(conn)
            #在删除完正常关闭链接的客户端后,应该把删除列表清空,否则会报错
            Conn_Del = []


#客户端:
import socket
sk = socket.socket()
sk.connect(('127.0.0.1',8080))
while 1:
    msg_s = input('>>>')
    if not msg_s:continue
    if msg_s == 'q':break
    sk.send(msg_s.encode('utf-8'))
    print(sk.recv(1024).decode('utf-8'))
sk.close()




01-20 06:27