提问者:小点点

Socket从它的InputStream读取后关闭


向对等方发送消息的方法:

    public static void writeLineToPeer(Peer peer, String message) throws IOException
    {
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(peer.getSocket().getOutputStream(), StandardCharsets.UTF_8));
        
        writer.write(message + "\n");
        writer.flush();
    }

阅读回复:

public class PeersResponse extends Response<Peer>
{
    public PeersResponse(InputStream stream) throws InvalidMessageException, IOException
    {
        super(stream);
        parseResponse();
        getNextElement();
    }
    
    @Override
    protected void parseResponse() throws InvalidMessageException, IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream, "UTF-8"));
        
        setVersion(reader.readLine());
            
        setAmount(reader.readLine());
        //Fine until here
    }

    @Override
    public Peer getNextElement() throws InvalidMessageException, IOException
    {
        BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream, "UTF-8"));
        
        String ip = reader.readLine();
        //Socket exception: Socket is closed

        if (NetworkHelper.isValidIPAddress(ip))
        {
            throw new InvalidMessageException();
        }
            
        String port = reader.readLine();
            
        String typeOfPeer = reader.readLine();
    
        if (typeOfPeer.length() != 1)
        {
            throw new InvalidMessageException();
        }
            
        try
        {
            return PeerFactory.getPeer(typeOfPeer.charAt(0), ip, Integer.parseInt(port));
        }
        catch (Exception ex)
        {
            throw new InvalidMessageException(ex);
        }
    }

}

如您所见,我得到了一个Socket异常:当尝试从具有相同InputStream的BufferedReader的另一个实例读取时,Socket关闭。

正在发送的消息很好,适合此类的结构。

这是什么原因?我该怎么解决这个问题?


共1个答案

匿名用户

第一次在parseResponse()内部调用read. ReadLine()时,BufferedReader从流中读取一大块数据。它读取的不仅仅是一行,因为它还不知道行尾在哪里。它从套接字中读取(和删除)一行的唯一方法是逐个读取字符,并在看到新行时停止。但这将首先破坏使用BufferedReader的目的。

第二次在parseResponse()内部调用read. ReadLine()时,它根本不会从底层套接字读取。它只是解析已经存储在BufferedReader中的数据并返回下一行。

parseResponse()退出时,仍然有数据存储在BufferedReader中。当读取器变量超出范围时,该数据将丢失。它无法从套接字中读取,因为它已经从套接字中读取。

TLDR;您可以在调试器中单步执行parseResponse()并查看读取器实例(检查JDK的内部数据结构)。您将在那里看到整个消息。当parseResponse()返回时,您将看到消息的其余部分是如何丢失的。