问题是什么:
基于Java Socket的服务器程序似乎虚假地重置了它在已建立的连接中与基于Java套接字的客户端的连接,尽管数据传输的SO_TIMEOUT设置被设置为"无限&#34 ;
我测试了服务器:
Linux Ubuntu 14.04 LTS内核3.13.0-29-通用Java(TM)SE运行时环境(版本1.7.0_03-b04) 并且 Windows 8.1版本6.3.9600 Java(TM)SE运行时环境(版本1.7.0_51-b13)
并且存在差异。在Windows上,当所有线程都忙并且使用积压时,服务器不接受连接,因此它应该是。在接受Linux连接时,可以写入和刷新数据(另外还有TCP_NODELAY),但在客户端随后读取时,它会接收"连接重置"时不时地。我在服务器端没有例外。 如果客户端在Windows或Linux下运行,则行为没有变化,在环回地址,本地网络地址或外部网络地址上运行服务器也没有任何区别。
非常欢迎任何帮助或贡献。我也在这里学习,所以如果我编码错误就告诉我。
在早期的帖子中,没有添加任何来源,而是链接到我网站上的JAR和源图像。我同意这不是常见的做法,所以我做了一个浓缩版本,也揭示了这个问题。请注意,故意选择所有设置以使服务器处于过载状态,并将连接和读取的超时设置为"无限"。我确实意识到这些不是人们在现实生活中所选择的那些,而只是为了生成"连接重置"。
这是客户端的代码:
package resetconntest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.concurrent.Semaphore;
class MiniClient {
static boolean SHOW_EXC_ONLY = true; // show exceptions only
static int THREADS = 64; // number of "simultaneous connections"
static int LOOPS = 256; // total number of connections
static String HOST = "192.168.0.10"; // server hostname
static int PORT = 7272; // server port
static int CONN_TIMEOUT = 0; // keep infinite connect time for test
static int SO_TIMEOUT = 0; // keep infinite read time for test
static int SO_LINGER = -1; // no linger
static boolean REUSE_ADDRESS = false; // chosen for test
static boolean TCP_NODELAY = true; // small blocks, so no Nagle
static boolean KEEP_ALIVE = false; // chosen for test
static int TRAFFIC_CLASS = 0; // if used, use mask as for ToS
public static void main ( String[] args ) {
new MiniClient().runTest ();
System.exit ( 0 );
}
MiniClient () {}
void runTest () {
Object syncer = new Object();
System.out.println ( "--> start MiniClient" );
try {
Semaphore semaphore = new Semaphore ( THREADS );
for ( int x = 0 ; x < LOOPS ; x++ ) {
semaphore.acquireUninterruptibly ();
new Requester ( syncer ,x + 1 ,semaphore ).start();
}
while ( semaphore.availablePermits() < THREADS ) {
Thread.sleep ( 100 );
}
} catch ( Throwable anyThrown ) {
synchronized ( syncer ) {
System.out.println ( "--> throwable in main" );
anyThrown.printStackTrace ( System.out );
System.out.println ( "<-- throwable in main" );
}
}
System.out.println ( "<-- end MiniClient" );
}
class Requester extends Thread {
Object syncer;
String index;
Semaphore semaphore;
Requester ( Object syncer ,int index ,Semaphore semaphore ) {
this.syncer = syncer;
this.index = Integer.toString ( index );
this.semaphore = semaphore;
}
public void run () {
try {
Socket socket = new Socket ();
socket.connect ( new InetSocketAddress ( HOST ,PORT ) ,CONN_TIMEOUT );
socket.setSoTimeout ( SO_TIMEOUT );
socket.setSoLinger ( (SO_LINGER >= 0) ,SO_LINGER );
socket.setReuseAddress ( REUSE_ADDRESS );
socket.setTcpNoDelay ( TCP_NODELAY );
socket.setKeepAlive ( KEEP_ALIVE );
if ( TRAFFIC_CLASS != 0 ) socket.setTrafficClass ( TRAFFIC_CLASS );
PrintWriter out = new PrintWriter ( new OutputStreamWriter ( socket.getOutputStream() ) );
BufferedReader in = new BufferedReader ( new InputStreamReader ( socket.getInputStream() ) );
if ( dialog ( "aaaaa" ,out ,in ) )
if ( dialog ( "bbbbb" ,out ,in ) )
dialog ( "close" ,out ,in );
socket.shutdownInput();
socket.shutdownOutput();
in.close();
out.close();
socket.close ();
} catch ( Throwable anyThrown ) {
synchronized ( syncer ) {
System.out.println ( "--> throwable in client thread:" + index );
anyThrown.printStackTrace ( System.out );
System.out.println ( "<-- throwable in client thread:" + index );
}
}
semaphore.release ();
}
boolean dialog ( String text
,PrintWriter out
,BufferedReader in ) throws Throwable {
String msg = index + ':' + text;
try {
if ( SHOW_EXC_ONLY == false ) synchronized ( syncer ) { System.out.println ( "--> send: " + msg ); }
out.println ( msg );
out.flush();
String resp = in.readLine();
if ( resp == null ) {
synchronized ( syncer ) { System.out.println ( "<-- got EOF after: " + msg ); }
return false;
}
if ( SHOW_EXC_ONLY == false ) synchronized ( syncer ) { System.out.println ( "<-- received: " + resp ); }
} catch ( Throwable anyThrown ) {
synchronized ( syncer ) {
System.out.println ( "--> throwable in client thread:" + index );
System.out.println ( "--> at processing message: " + msg );
anyThrown.printStackTrace ( System.out );
System.out.println ( "<-- at processing message: " + msg );
System.out.println ( "<-- throwable in client thread:" + index );
}
return false;
}
return true;
}
} // end of inner class
} // end of code
这是服务器的代码:
package resetconntest;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.Semaphore;
class MiniServer {
static boolean SHOW_EXC_ONLY = false; // show messages and exceptions
static String HOST = "192.168.0.10"; // host name binded to
static int PORT = 7272; // port number binded to
static int ACC_TIMEOUT = 0; // keep timeout for accept infinite for test
static boolean REUSE_SERVER_ADDRESS = false; // chosen for test
static int BACKLOG = 2; // keep low for test
static int THREADS = 8; // keep low for test
static int SO_TIMEOUT = 0; // keep infinite read timeout for test
static int SO_LINGER = -1; // no lingering
static boolean REUSE_ACC_ADDRESS = false; // chosen for test
static boolean TCP_NODELAY = true; // small blocks, so no Nagle
static boolean KEEP_ALIVE = false; // chosen for test
static int TRAFFIC_CLASS = 0; // if used, use mask as for ToS
static int PROCESS_DELAY = 500; // simulate long message processing 0.5 sec
public static void main ( String[] args ) {
new MiniServer().runTest ();
System.exit ( 0 );
}
MiniServer () {}
public void runTest () {
Object syncer = new Object();
System.out.println ( "--> start MiniServer" );
try {
InetSocketAddress socketAddress = new InetSocketAddress ( InetAddress.getByName ( HOST ), PORT );
ServerSocket serverSocket = new ServerSocket ();
serverSocket.bind ( socketAddress ,BACKLOG );
serverSocket.setReuseAddress ( REUSE_SERVER_ADDRESS );
serverSocket.setSoTimeout ( ACC_TIMEOUT );
Semaphore semaphore = new Semaphore ( THREADS );
Socket accepted;
while ( true ) {
semaphore.acquireUninterruptibly();
accepted = serverSocket.accept();
new Servicer ( syncer ,accepted ,semaphore ).start();
}
// never reached, gives the warning at server construction.
// to end the server, just use the old fashioned blunt CTRL-C
// while ( semaphore.availablePermits() < THREADS ) {
// Thread.sleep ( 100 );
// }
// serverSocket.close ();
} catch ( Throwable anyThrown ) {
synchronized ( syncer ) {
System.out.println ( "--> throwable in main" );
anyThrown.printStackTrace ( System.out );
System.out.println ( "<-- throwable in main" );
}
}
System.out.println ( "<-- end MiniServer" );
}
class Servicer extends Thread {
Object syncer;
Socket socket;
Semaphore semaphore;
Servicer ( Object syncer
,Socket socket
,Semaphore semaphore ) {
this.syncer = syncer;
this.socket = socket;
this.semaphore = semaphore;
}
public void run () {
try {
socket.setSoTimeout ( SO_TIMEOUT );
socket.setSoLinger ( (SO_LINGER >= 0) ,SO_LINGER );
socket.setReuseAddress ( REUSE_ACC_ADDRESS );
socket.setTcpNoDelay ( TCP_NODELAY );
socket.setKeepAlive ( KEEP_ALIVE );
if ( TRAFFIC_CLASS != 0 ) socket.setTrafficClass ( TRAFFIC_CLASS );
BufferedReader in = new BufferedReader( new InputStreamReader ( socket.getInputStream() ) );
PrintWriter out = new PrintWriter ( new OutputStreamWriter ( socket.getOutputStream() ) );
String clientMessage;
while ( true ) {
clientMessage = in.readLine ();
if ( clientMessage == null ) {
synchronized ( syncer) { System.out.println ( "<-> received end of file from accepted socket" ); }
break;
}
if ( SHOW_EXC_ONLY == false ) synchronized ( syncer ) { System.out.println ( "client said: " + clientMessage ); }
if ( PROCESS_DELAY > 0 ) Thread.sleep ( PROCESS_DELAY );
out.println ( "echo: " + clientMessage );
out.flush();
if ( clientMessage.indexOf ( "close" ) >= 0 ) break;
}
socket.shutdownInput();
socket.shutdownOutput();
in.close();
out.close();
socket.close();
} catch ( Throwable anyThrown ) {
synchronized ( syncer ) {
System.out.println ( "--> throwable in server thread" );
anyThrown.printStackTrace ( System.out );
System.out.println ( "<-- throwable in server thread" );
}
}
semaphore.release();
}
} // end of inner class
} // end of code
答案 0 :(得分:0)
socket.setSoLinger( (SO_LINGER >= 0) ,SO_LINGER );
在服务器和客户端完全摆脱这一行。除了我在评论中所说的,这是激发连接重置的另一种方法。只需删除它。你不需要它。这是一个问题,而不是解决方案。