套接字在从其输入流读取后被关闭。

huangapple go评论59阅读模式
英文:

Socket is closed after reading from it's InputStream

问题

Method to send message to peer:

	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();
	}

Reading the response:

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);
		}
	}

}

As you can see I get a Socket exception: Socket is closed when trying to read from another instance of a BufferedReader with the same InputStream.

The message that is being sent is fine and fits the structure of this class.

What's the cause of this? How can I fix this?

英文:

Method to send message to peer:

	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 + &quot;\n&quot;);
writer.flush();
}

Reading the response:

public class PeersResponse extends Response&lt;Peer&gt;
{
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, &quot;UTF-8&quot;));
setVersion(reader.readLine());
setAmount(reader.readLine());
//Fine until here
}
@Override
public Peer getNextElement() throws InvalidMessageException, IOException
{
BufferedReader reader = new BufferedReader(new InputStreamReader(this.stream, &quot;UTF-8&quot;));
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);
}
}
}

As you can see I get a Socket exception: Socket is closed when trying to read from another instance of a
BufferedReader with the same InputStream.

The message that is being sent is fine and fits the structure of this class.

What's the cause of this? How can I fix this?

答案1

得分: 1

第一次在parseResponse()内调用reader.ReadLine()时,BufferedReader从流中读取一块数据。它不仅仅读取一行,因为它还不知道行的结尾在哪里。唯一的方式是逐个字符地读取并在看到换行符时停止,从套接字中读取(并移除)一行。但这将违背首次使用BufferedReader的目的。

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

parseResponse()退出时,BufferedReader内仍然存有数据。随着阅读器变量超出范围,该数据丢失。无法从套接字中读取它,因为它已经从套接字中读取过了。

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

英文:

The first time you call reader.ReadLine() inside of parseResponse() the BufferedReader reads a chunk of data from the stream. It reads more than just one line, because it does not yet know where the end of line is. The only way for it to read (and remove) just one line from the socket would be to read characters one-by-one and stop when it sees the new line. But that would defeat the purpose of using BufferedReader in the first place.

The second time you call reader.ReadLine() inside of parseResponse(), it does not read from the underlying socket at all. It just parses the data already stored inside BufferedReader and returns the next line.

At the time parseResponse() exits, there is still data stored inside BufferedReader. As the reader variable goes out of scope, that data is lost. It cannot be read from the socket, because it has already been read from the socket.

TLDR;
You can step through parseResponse() in the debugger and look inside the reader instance (examine JDK's internal data structure). You will see your entire message there. And you will see how the remainder of your message gets lost when parseResponse() returns.

huangapple
  • 本文由 发表于 2020年10月8日 01:52:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/64249665.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定