閉じたばかりのソケット入力ストリームのコンテンツ全体を読み取ろうとしています。しかし、それを読み取ってみても通常は機能しますが、常にそのソケットの出力ストリームに同時に書き込みを試みています。それに書き込むと、ソケットの入力ストリームが「壊れ」、残りを読み取ることができなくなります。
私の問題を説明するために作成したこの小さな例を見てみましょう。
@Test
public void socketTest() throws Throwable
{
new Thread(() -> {
try
{
ServerSocket serverSocket = new ServerSocket(5555);
while(true)
{
//keep listening
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
System.out.println(in.read());
Thread.sleep(2000);
try
{
socket.getOutputStream().write(3);
}
catch(Throwable ex)
{
System.out.println("Error writing");
ex.printStackTrace();
}
System.out.println(in.read());
in.close();
socket.close();
System.exit(0);
}
}
catch(Throwable ex)
{
System.out.println("Error reading");
ex.printStackTrace();
}
}).start();
Thread.sleep(100); //you might need this
Socket socket = new Socket("localhost", 5555);
OutputStream out = socket.getOutputStream();
out.write(1);
out.write(2);
out.close();
socket.close();
synchronized(this)
{
wait();
}
}
私は出力を取得します:
1
java.net.SocketException: Software caused connection abort: recv failed
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:223)
at net.jumpai.test.SocketTTest.lambda$socketTest$0(SocketTTest.java:55)
at java.lang.Thread.run(Thread.java:745)
Error reading
ただし、2が読み取られることはなく、ストリームに3を書き込むことでエラーが発生することはありません。ストリームで書き込みをスローしてもかまいませんが、2を読みたいのですが、それを行う方法はありますか?
私はjdk1.8.0_91がインストールされたWindows 7を使用しています。jdk1.8.0_181(現在の最新バージョン)に更新した後でも、問題を再現できました。Java 1.8.0_111を搭載した別のWindows 7コンピューターで再現することもできます。
ArchLinux open-jdk1.8.0_172でバグを再現できませんでした。これは、Javaバージョンのバグであることを意味しますか?それは本当にWindowsまたは少なくともOracleの実装にリンクされているようです。
この動作は、どのバージョンの2つのWindowsマシンでも簡単に再現できますが、LinuxまたはMacシステムでは再現できません。open-jdkには存在しないOracleのJVMのバグだと思います。
このバグはかなり煩わしいものであり、誰かが回避策を投稿していただければ幸いです。一方、Oracleにバグレポートを提出しました:https : //bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8208479
回避策を構築しようとすると、システムにバグがあるかどうかを確認できるようになりました。
public static boolean hasOracleSocketBug()
{
try
{
int port = 10000;
while(!PortChecker.portAvailable(port))
port++;
ServerSocket serverSocket = new ServerSocket(port);
int fPort = port;
new Thread(() -> {
try
{
Socket socket = new Socket("localhost", fPort);
OutputStream out = socket.getOutputStream();
out.write(1);
out.write(2);
out.close();
socket.close();
}
catch(Exception ex)
{
try
{
serverSocket.close();
}
catch(IOException ignored) {}
}
}).start();
Socket socket = serverSocket.accept();
InputStream in = socket.getInputStream();
in.read();
socket.getOutputStream().write(3);
try
{
in.read();
}
catch(Exception ex)
{
socket.close();
return true;
}
in.close();
socket.close();
return false;
}
catch(Throwable ignored)
{
return false;
}
}
public static boolean portAvailable(int port)
{
ServerSocket ss = null;
try
{
ss = new ServerSocket(port);
ss.setReuseAddress(true);
return true;
}
catch(IOException ignored)
{
return false;
}
finally
{
if(ss != null)
{
try
{
ss.close();
}
catch(IOException ignored) {}
}
}
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加