考虑下面的java伪代码(clisent用IP和端口23(telnet)打开一个到服务器的套接字:
static Socket skt = null;
skt = new Socket(IP, 23);
do something
skt.close()
ALMOST NO DELAY
skt = new Socket(IP, 23); // re-opening same socket variable (skt) right after closing it
..并且有时会发生异常,因为我们正在尝试重新打开尚未完全关闭的同一个套接字 错误:java.io.IOException:连接重置
如何确保(检查)套接字在另一端关闭?换句话说,在我们继续并在另一部分代码中重新打开该套接字之前,等待来自服务器的确认。 - 由于某种原因,我们必须重新打开相同的插座 - 我们也不想在重新打开相同的套接字之前放置延迟。
简而言之:我们希望从服务器读取确认(蓝线)
答案 0 :(得分:2)
套接字由两端,源和目标中的IP和端口标识。您的第二个连接应该获得不同的源端口,因此服务器将其视为单独的连接。确保服务器始终接受新连接,您应该没问题。
答案 1 :(得分:1)
每次创建客户端套接字的本地端口后都打印它。如果为每个新的客户端套接字获得一个新的本地端口,除非TCP堆栈中存在错误,否则它实际上不太可能是“套接字重用”的问题。那么,您是否通过例如明确指定本地套接字号码? Socket.bind或the Socket constructor which accepts a local port?你可能不应该。让系统选择一个短暂的端口。
问题可能出在服务器上,而不是客户端。当我关闭然后立即重新创建到同一主机和端口的客户端套接字时,我没有问题。在我退出之前,SSCCE在没有任何问题的情况下达到130k连接。环回接口可能比真实的NIC更宽容,但您可以轻松修改此代码以在真实网络上运行。
public class TestTcpClientServer
{
public static final int SERVER_PORT = 10111;
public static void main(String[] args) throws Exception
{
Server server = new Server();
server.start();
Thread.sleep(500);
Client client = new Client();
client.start();
System.out.println("Press enter to shutdown...");
System.in.read();
client.shutdown();
client.join();
server.shutdown();
server.join();
System.out.println("Done.");
}
public static class Client extends Thread
{
private volatile boolean shutdown = false;
public void run()
{
try
{
int totalClientConnections = 0;
while (!shutdown)
{
Socket socket = new Socket("localhost", SERVER_PORT);
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
bw.write("Client saying hello to server");
bw.newLine();
bw.flush();
String readLine = br.readLine();
//System.out.println("Client read from server: " + readLine);
System.out.println("Socket local port: " + socket.getLocalPort());
socket.close();
totalClientConnections++;
if (totalClientConnections % 10000 == 0)
{
System.out.println("totalClientConnections=" + totalClientConnections);
}
Thread.sleep(1000);
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
public void shutdown()
{
shutdown = true;
}
}
public static class Server extends Thread
{
private volatile boolean shutdown = false;
private ServerSocket serverSocket = null;
public void run()
{
try
{
int totalServerConnections = 0;
serverSocket = new ServerSocket(SERVER_PORT);
while (!shutdown)
{
Socket socket = serverSocket.accept();
InputStream inputStream = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(outputStream));
String readLine = br.readLine();
//System.out.println("Server read from client: " + readLine);
bw.write("Server saying hello to client");
bw.newLine();
bw.flush();
socket.close();
totalServerConnections++;
if (totalServerConnections % 10000 == 0)
{
System.out.println("totalServerConnections=" + totalServerConnections);
}
}
}
catch (Exception e)
{
if (!shutdown)
{
e.printStackTrace();
}
}
}
public void shutdown()
{
shutdown = true;
try
{
serverSocket.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
}
答案 2 :(得分:0)
..并且有时会发生以下异常,因为我们正在尝试 重新打开尚未完全关闭的同一插座错误: java.io.IOException:连接重置
您的分析不正确。那不是原因。插座是全新的。这种联系是全新的。如果您有“连接重置”,那是因为服务器软件选择重置连接。除非调查原因,最糟糕的睡眠和重试,否则你无法做到这一点。
这也与本地端口耗尽无关,正如其他一些答案所暗示的那样。如果那是问题,你会得到一个BindException
。
您的客户端发送RST这一事实非常好奇。您是否正在调用上面未显示的一些Socket API?