From a6fbc181520f3432b77df752c98685ac99e095a7 Mon Sep 17 00:00:00 2001
From: tywo45 <tywo45@163.com>
Date: Fri, 2 Sep 2022 15:01:24 +0800
Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BD=9C=E4=B8=BATCP=20Clien?=
 =?UTF-8?q?t=E5=9C=A8=E6=96=AD=E7=BD=91=E7=8A=B6=E6=80=81=E4=B8=8B?=
 =?UTF-8?q?=E8=BF=9E=E6=8E=A5=E5=9F=9F=E5=90=8D=E6=97=B6=E6=8A=A5=E7=9A=84?=
 =?UTF-8?q?=E5=BC=82=E5=B8=B8?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

修复作为TCP Client在断网状态下连接域名时报的异常
---
 .../org/tio/client/ClientChannelContext.java  | 17 +++++-
 .../main/java/org/tio/client/TioClient.java   | 21 ++++---
 .../java/org/tio/core/ChannelContext.java     | 14 +++--
 .../org/tio/core/maintain/ClientNodes.java    | 58 +++++++------------
 .../org/tio/server/ServerChannelContext.java  | 17 +++++-
 5 files changed, 73 insertions(+), 54 deletions(-)

diff --git a/src/core/src/main/java/org/tio/client/ClientChannelContext.java b/src/core/src/main/java/org/tio/client/ClientChannelContext.java
index 47140616..d75b2653 100644
--- a/src/core/src/main/java/org/tio/client/ClientChannelContext.java
+++ b/src/core/src/main/java/org/tio/client/ClientChannelContext.java
@@ -251,8 +251,21 @@ public ClientChannelContext(TioConfig tioConfig) {
 	 */
 	@Override
 	public Node createClientNode(AsynchronousSocketChannel asynchronousSocketChannel) throws IOException {
-		InetSocketAddress inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getLocalAddress();
-		Node clientNode = new Node(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
+		Node clientNode = null;
+		InetSocketAddress inetSocketAddress = null;
+		if (asynchronousSocketChannel == null) {
+			clientNode = createUnknowNode();
+		} else {
+			inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getLocalAddress();
+		}
+		
+		if (inetSocketAddress == null) {
+			clientNode = createUnknowNode();
+		}
+		
+		if (clientNode == null) {
+			clientNode = new Node(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
+		}
 		return clientNode;
 	}
 
diff --git a/src/core/src/main/java/org/tio/client/TioClient.java b/src/core/src/main/java/org/tio/client/TioClient.java
index c65aa6d4..41e4d863 100644
--- a/src/core/src/main/java/org/tio/client/TioClient.java
+++ b/src/core/src/main/java/org/tio/client/TioClient.java
@@ -390,16 +390,23 @@ private ClientChannelContext connect(Node serverNode, String bindIp, Integer bin
 
 			CountDownLatch countDownLatch = new CountDownLatch(1);
 			attachment.setCountDownLatch(countDownLatch);
-			asynchronousSocketChannel.connect(inetSocketAddress, attachment, tioClientConfig.getConnectionCompletionHandler());
-			boolean f = countDownLatch.await(realTimeout, TimeUnit.SECONDS);
-			if (f) {
-				return attachment.getChannelContext();
-			} else {
-				log.error("countDownLatch.await(realTimeout, TimeUnit.SECONDS) 返回false ");
+			
+			try {
+				asynchronousSocketChannel.connect(inetSocketAddress, attachment, tioClientConfig.getConnectionCompletionHandler());
+			} catch (Throwable e) {
+				tioClientConfig.getConnectionCompletionHandler().failed(e, attachment);
 				return attachment.getChannelContext();
 			}
+			
+			@SuppressWarnings("unused")
+			boolean f = countDownLatch.await(realTimeout, TimeUnit.SECONDS);
+			return attachment.getChannelContext();
 		} else {
-			asynchronousSocketChannel.connect(inetSocketAddress, attachment, tioClientConfig.getConnectionCompletionHandler());
+			try {
+				asynchronousSocketChannel.connect(inetSocketAddress, attachment, tioClientConfig.getConnectionCompletionHandler());
+			} catch (Throwable e) {
+				tioClientConfig.getConnectionCompletionHandler().failed(e, attachment);
+			}
 			return null;
 		}
 	}
diff --git a/src/core/src/main/java/org/tio/core/ChannelContext.java b/src/core/src/main/java/org/tio/core/ChannelContext.java
index b2b2e9d6..b83847bd 100644
--- a/src/core/src/main/java/org/tio/core/ChannelContext.java
+++ b/src/core/src/main/java/org/tio/core/ChannelContext.java
@@ -211,7 +211,6 @@ recommend that a file or class name and description of purpose be included on
 import org.tio.core.task.DecodeRunnable;
 import org.tio.core.task.HandlerRunnable;
 import org.tio.core.task.SendRunnable;
-import org.tio.utils.hutool.CollUtil;
 import org.tio.utils.hutool.StrUtil;
 import org.tio.utils.lock.SetWithLock;
 import org.tio.utils.prop.MapWithLockPropSupport;
@@ -322,10 +321,13 @@ public ChannelContext(TioConfig tioConfig, String id) {
 
 		initOther();
 	}
-
-	private void assignAnUnknownClientNode() {
-		Node clientNode = new Node(UNKNOWN_ADDRESS_IP, UNKNOWN_ADDRESS_PORT_SEQ.incrementAndGet());
-		setClientNode(clientNode);
+	
+	protected void assignAnUnknownClientNode() {
+		setClientNode(createUnknowNode());
+	}
+	
+	public static Node createUnknowNode() {
+		return new Node(UNKNOWN_ADDRESS_IP, UNKNOWN_ADDRESS_PORT_SEQ.incrementAndGet());
 	}
 
 	/**
@@ -363,6 +365,8 @@ public boolean equals(Object obj) {
 		}
 		return true;
 	}
+	
+
 
 	/**
 	 * 等价于:getAttribute(DEFAULT_ATTUBITE_KEY)
diff --git a/src/core/src/main/java/org/tio/core/maintain/ClientNodes.java b/src/core/src/main/java/org/tio/core/maintain/ClientNodes.java
index 78e69db3..2b536db3 100644
--- a/src/core/src/main/java/org/tio/core/maintain/ClientNodes.java
+++ b/src/core/src/main/java/org/tio/core/maintain/ClientNodes.java
@@ -194,6 +194,7 @@ recommend that a file or class name and description of purpose be included on
 package org.tio.core.maintain;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.locks.Lock;
 
 import org.slf4j.Logger;
@@ -208,52 +209,34 @@ recommend that a file or class name and description of purpose be included on
  * 2017年4月1日 上午9:35:20
  */
 public class ClientNodes {
-	private static Logger log = LoggerFactory.getLogger(ClientNodes.class);
+	private static final Logger log = LoggerFactory.getLogger(ClientNodes.class);
 
-	/**
-	 *
-	 * @param channelContext
-	 * @return
-	 * @author tanyaowu
-	 */
-	public static String getKey(ChannelContext channelContext) {
-		Node clientNode = channelContext.getClientNode();
-		if (clientNode == null) {
-			throw new RuntimeException("client node is null");
-		}
-		String key = getKey(clientNode.getIp(), clientNode.getPort());
-		return key;
-	}
+	/** remoteAndChannelContext key: Node value: ChannelContext. */
+	private final MapWithLock<Node, ChannelContext> mapWithLock = new MapWithLock<>();
 
 	/**
 	 *
-	 * @param ip
-	 * @param port
-	 * @return
+	 * @param channelContext ChannelContext
+	 * @return Node
 	 * @author tanyaowu
 	 */
-	public static String getKey(String ip, int port) {
-		String key = ip + ":" + port;
-		return key;
+	public static Node getKey(ChannelContext channelContext) {
+		Node clientNode = channelContext.getClientNode();
+		return Objects.requireNonNull(clientNode, "client node is null");
 	}
 
-	/** remoteAndChannelContext key: "ip:port" value: ChannelContext. */
-	private MapWithLock<String, ChannelContext> mapWithLock = new MapWithLock<>();
-
 	/**
 	 *
-	 * @param key
+	 * @param clientNode
 	 * @return
 	 * @author tanyaowu
 	 */
-	public ChannelContext find(String key) {
+	public ChannelContext find(Node clientNode) {
 		Lock lock = mapWithLock.readLock();
 		lock.lock();
 		try {
-			Map<String, ChannelContext> m = mapWithLock.getObj();
-			return m.get(key);
-		} catch (Throwable e) {
-			throw e;
+			Map<Node, ChannelContext> m = mapWithLock.getObj();
+			return m.get(clientNode);
 		} finally {
 			lock.unlock();
 		}
@@ -267,8 +250,7 @@ public ChannelContext find(String key) {
 	 * @author tanyaowu
 	 */
 	public ChannelContext find(String ip, int port) {
-		String key = getKey(ip, port);
-		return find(key);
+		return find(new Node(ip, port));
 	}
 
 	/**
@@ -276,13 +258,13 @@ public ChannelContext find(String ip, int port) {
 	 * @return
 	 * @author tanyaowu
 	 */
-	public MapWithLock<String, ChannelContext> getObjWithLock() {
+	public MapWithLock<Node, ChannelContext> getObjWithLock() {
 		return mapWithLock;
 	}
 
 	/**
 	 * 添加映射
-	 * @param channelContext
+	 * @param channelContext ChannelContext
 	 * @author tanyaowu
 	 */
 	public void put(ChannelContext channelContext) {
@@ -290,8 +272,8 @@ public void put(ChannelContext channelContext) {
 			return;
 		}
 		try {
-			String key = getKey(channelContext);
-			mapWithLock.put(key, channelContext);
+			Node clientNode = getKey(channelContext);
+			mapWithLock.put(clientNode, channelContext);
 		} catch (Exception e) {
 			log.error(e.toString(), e);
 		}
@@ -307,8 +289,8 @@ public void remove(ChannelContext channelContext) {
 			return;
 		}
 		try {
-			String key = getKey(channelContext);
-			mapWithLock.remove(key);
+			Node clientNode = getKey(channelContext);
+			mapWithLock.remove(clientNode);
 		} catch (Throwable e) {
 			log.error(e.toString(), e);
 		}
diff --git a/src/core/src/main/java/org/tio/server/ServerChannelContext.java b/src/core/src/main/java/org/tio/server/ServerChannelContext.java
index 168e8fc3..c35bee8d 100644
--- a/src/core/src/main/java/org/tio/server/ServerChannelContext.java
+++ b/src/core/src/main/java/org/tio/server/ServerChannelContext.java
@@ -250,8 +250,21 @@ public ServerChannelContext(TioConfig tioConfig, String id) {
 	 */
 	@Override
 	public Node createClientNode(AsynchronousSocketChannel asynchronousSocketChannel) throws IOException {
-		InetSocketAddress inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getRemoteAddress();
-		Node clientNode = new Node(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
+		Node clientNode = null;
+		InetSocketAddress inetSocketAddress = null;
+		if (asynchronousSocketChannel == null) {
+			clientNode = createUnknowNode();
+		} else {
+			inetSocketAddress = (InetSocketAddress) asynchronousSocketChannel.getRemoteAddress();
+		}
+
+		if (inetSocketAddress == null) {
+			clientNode = createUnknowNode();
+		}
+
+		if (clientNode == null) {
+			clientNode = new Node(inetSocketAddress.getHostString(), inetSocketAddress.getPort());
+		}
 		return clientNode;
 	}