为什么在成千上万次创建套接字后调用IOException
?
我做了一个简单的服务器代码(Java)接受连接然后创建一个线程读取套接字并将另一个字符发送给客户端 客户端代码开始循环(足够长以重现问题)并且在每个循环中在每个线程中创建50个线程,创建到服务器机器的客户端套接字并发送一个字符,然后从套接字读取服务器发回的字符。 然后客户端和服务器都关闭套接字。
一段时间后,我注意到在客户端,我在客户端套接字创建中遇到异常。 是否有一些限制我应该考虑正确地工作,或者这应该在无限循环中工作?
我正在考虑这样的情况:可能在经过足够长的循环时间后,客户端尝试将新套接字绑定到客户端计算机上的端口,该端口仍然绑定到处于CLOSED状态的套接字但该时间段需要过去才能被尚未传递的内核释放。 (抱歉不知道这段时间的正式名称) 客户端和服务器计算机是VMware中的两个Linux系统。
答案 0 :(得分:0)
听起来好像你的连接被丢弃了。
您忘记了Fallacies of Distributed Computing中的规则#1:网络始终可靠。
答案 1 :(得分:0)
您是否在ServerSocket上将setReuseAddress
参数设置为true?如果没有,您必须在内核释放网络资源之前等待很长时间。
答案 2 :(得分:0)
谢谢! 实际上这是我的服务器端代码
public class TestServer {
public void createThread() {
System.out.println("createThread");
ServerThread servThread = new ServerThread();
servThread.start();
}
public static final void main(String[] args) {
ServerSocket server = null;
try {
System.out.println("Started");
server = new ServerSocket(12345);
}
catch(IOException ex) {
System.out.println("Server: Exception at socket creation: " + ex.getMessage());
}
try {
while(true) {
Socket clientSock = server.accept();
System.out.println("Connection Accepted: server: "+clientSock.getLocalPort()+", Client: "+clientSock.getPort());
ServerThread servThread = new ServerThread(clientSock);
servThread.start();
}
}
catch(IOException ex) {
System.out.println("Server: Exception at socket accept: " + ex.getMessage());
}
}
}
class ServerThread extends Thread {
private Socket sock;
public ServerThread() {}
public ServerThread(Socket sock) {
this.sock = sock;
}
public void run() {
InputStream is = null;
OutputStream os = null;
try {
is = sock.getInputStream();
os = sock.getOutputStream();
}
catch(IOException ex) {}
try {
int b = is.read();
System.out.println("server: received = " + (char)b);
}
catch(IOException ex) {
System.out.println("Server: IOException at read = " + ex.getMessage());
}
try {
os.write('R');
os.flush();
}
catch(IOException ex) {
System.out.println("Server: IOException at write = " + ex.getMessage());
}
try {
sock.close();
}
catch(IOException ex) {
System.out.println("Server: IOException at close = " + ex.getMessage());
}
}
}
这是客户部分:
public class TestClient {
public static void main(String[] args) {
if (args.length != 4) {
System.out.println("Usage: java TestClient <ServerIP> <nbThreads> <cycle> <delay>");
System.exit(1);
}
String host = args[0];
int nbThreads = Integer.parseInt(args[1]);
int cycle = Integer.parseInt(args[2]);
int delay = Integer.parseInt(args[3]);
for (int i = 0; i<cycle; i++) {
for (int j = 0; j<nbThreads; j++) {
ClientThread clThread = new ClientThread(host);
clThread.start();
}
/* try {
Thread.sleep(delay);
}
catch (Exception ex) {} */
}
}
}
class ClientThread extends Thread {
private String host;
public ClientThread(String host) {
this.host = host;
}
public void run(){
for (int i=0; i<3; i++) {
Socket clientSock = null;
try {
clientSock = new Socket(host, 12345);
}
catch(IOException ex) {
System.out.println("Client: IOException at socket creation = " + ex.getMessage());
}
OutputStream os = null;
InputStream is = null;
try {
os = clientSock.getOutputStream();
is = clientSock.getInputStream();
}
catch (IOException ex) { }
try {
os.write('B');
os.flush();
}
catch (IOException ex) {
System.out.println("Client: IOException at write = " + ex.getMessage());
}
try {
int reply = is.read();
System.out.println("Client: reply = " + (char)reply);
}
catch(IOException ex) {
System.out.println("Client: IOException at read = " + ex.getMessage());
}
try {
clientSock.close();
}
catch(IOException ex) {
System.out.println("Client: IOException at close = " + ex.getMessage());
}
}
}
}
我正在测试60个线程和1000个周期,没有延迟。
我在第一个问题中出错了,一段时间后来自is.read()调用的异常就是'连接重置'异常。 我做了这个示例代码来模拟我在我的应用程序代码中遇到的问题,我在客户端套接字创建过程中遇到了异常......但似乎我需要进一步找到这个和我的应用程序代码之间的区别。 但是我认为这也有助于我理解为什么一段时间后我会在客户端获得“连接重置”异常。 有可能在服务器端,一旦os.write('R')发生了sock.close()发生得如此之快,以至于在客户端,is.read()调用尚未到达。声音奇怪:))
还不确定我应该在哪个套接字上使用setReuseAddress函数。不是在客户端,因为我一次又一次地创建套接字......虽然现在我没有在客户端套接字创建时获得异常。 谢谢!