Python长期存在的socket连接怪异

时间:2017-06-30 07:57:11

标签: python sockets redis

我实现了一些代码,允许客户端连接到套接字服务器,引入自身,然后服务器进入无限循环,发送"命令" (字符串)从Redis列表到客户端。服务器使用Redis' blpop'阻止字符串到达​​然后被发送到客户端并等待响应的方法。

然而,在测试中(在另一个本地工作站上使用python客户端套接字脚本)我发现如果我断开客户端连接(Ctrl + c)来模拟连接中断,服务器会愉快地将下一个接收到的字符串写入客户端,报告一个空响应,但只在写入第二个字符串时抛出损坏的管道异常:/因此,两个写入"丢失"在发生任何事情之前。这是我的代码:

# Create global Redis resource
rds_cnx = redis.StrictRedis(host='localhost', port=6379, db=6)

def initialise_server():
    """ Setup server socket """
    try:
        srv_skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        srv_skt.bind((IP, PORT))
        srv_skt.listen(1)
        print("Listening on:[{}]".format(IP, PORT))
        return srv_skt
    except socket.error as skt_err:  # e.g. port in use
        print("Could not initialise tcp server:[{}]".format(skt_err))
        sys.exit(1)
    except Exception as exp:
        print("Unable to setup server socket:[{}]".format(exp))
        sys.exit(1)


def main():

    server_socket = initialise_server()

    while True:

        client_socket, remote_address = server_socket.accept()

        try:
            # Block and wait for connection and data
            initial_data = client_socket.recv(1024).decode()
            print("Connection from [{}] - Data:[{}]".format(remote_address, initial_data))

            while True:
                wait_for_queue_command(client_socket)

        except (BrokenPipeError, socket.error, Exception) as sck_exp:
            print("Exception in client loop:[{}]".format(sck_exp))
            continue
        except KeyboardInterrupt:
            # Close client socket
            client_socket.shutdown(2)
            client_socket.close()
            print('Caught Ctrl+c ... Shutting down.')
            break

    # Tear down context
    server_socket.shutdown(2)  # Param ref: 0 = done receiving, 1 = done     sending, 2 = both
    server_socket.close()


def wait_for_queue_command(client_skt):
    """ Blocking while waiting for command for Redis list
    :param client_skt: socket
    :return: None
    """
    print('Waiting for command...')

    queue_cmd = rds_cnx.blpop('queuetest', 0)

    print("Received something from the queue:")
    pprint(queue_cmd)

    try:
        #client_skt.settimeout(15)
        client_skt.send(queue_cmd[1])

        # Block for response
        response_data = client_skt.recv(1024).decode()
        print("Response:[{}]".format(response_data))

    except BrokenPipeError as brkn_p:

        print('Outbound write detected "Broken Pipe":[{}]'.format(brkn_p))
        ''' Here one would decide to either re-schedule the command or 
            ignore the error and move on to the next command. A "pause"
            (sleep) could also useful? 
        '''
        raise

    except socket.timeout as sck_tmo:
        print('Socket timed out:[{}]'.format(sck_tmo))
    except socket.error as sck_err:
        print('Socket timed out:[{}]'.format(sck_err))
        raise

    print('Command handling complete.')

有没有更好的方法来处理这种情况?我粗略地看了一下Twisted,但似乎很难实现特定的阻塞行为以及可能用于处理来自客户端的特定响应的其他代码。

0 个答案:

没有答案