implement a transport with 2 independent sockets for sending and receiving

implementing a tie-breaking logic is error-prone due to netty's asynchronous nature. i think the code would be much simpler if we use two sockets for each peer, one for sending and the other for receiving.
i think this is ok. the worst case is when sender.channel gets initialized after the null pointer check, which results in one additional onDisconnected event.