diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md
index 0613e438deb..238c7ca1e28 100644
--- a/changes/en-us/2.0.0.md
+++ b/changes/en-us/2.0.0.md
@@ -25,6 +25,7 @@ The version is updated as follows:
- [[#4033](https://github.com/seata/seata/pull/4033)] add SQLServer support for Server DB storage mode
- [[#5717](https://github.com/seata/seata/pull/5717)] compatible with file.conf and registry.conf configurations in version 1.4.2 and below
- [[#5842](https://github.com/seata/seata/pull/5842)] adding metainfo to docker image
+- [[#5902](https://github.com/seata/seata/pull/5902)] support IPv6
- [[#5907](https://github.com/seata/seata/pull/5907)] support polardb-x 2.0 in AT mode
### bugfix:
@@ -181,6 +182,7 @@ Thanks to these contributors for their code commits. Please report an unintended
- [robynron](https://github.com/robynron)
- [XQDD](https://github.com/XQDD)
- [Weelerer](https://github.com/Weelerer)
+- [Ifdevil](https://github.com/Ifdevil)
Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.
diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md
index 5e01d22bee0..9ea2c10ecba 100644
--- a/changes/zh-cn/2.0.0.md
+++ b/changes/zh-cn/2.0.0.md
@@ -25,6 +25,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单
- [[#4033](https://github.com/seata/seata/pull/4033)] 增加ServerDB存储模式的SQLServer支持
- [[#5717](https://github.com/seata/seata/pull/5717)] 兼容1.4.2及以下版本的file.conf/registry.conf配置
- [[#5842](https://github.com/seata/seata/pull/5842)] 构建docker 镜像时添加相关git信息,方便定位代码关系
+- [[#5902](https://github.com/seata/seata/pull/5902)] 支持IPv6网络环境
- [[#5907](https://github.com/seata/seata/pull/5907)] 增加AT模式的PolarDB-X 2.0数据库支持
### bugfix:
@@ -181,6 +182,7 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单
- [robynron](https://github.com/robynron)
- [XQDD](https://github.com/XQDD)
- [Weelerer](https://github.com/Weelerer)
+- [Ifdevil](https://github.com/Ifdevil)
同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。
diff --git a/common/src/main/java/io/seata/common/util/NetAddressValidatorUtil.java b/common/src/main/java/io/seata/common/util/NetAddressValidatorUtil.java
new file mode 100644
index 00000000000..00f8b53d90c
--- /dev/null
+++ b/common/src/main/java/io/seata/common/util/NetAddressValidatorUtil.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 1999-2019 Seata.io Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.seata.common.util;
+
+import java.util.regex.Pattern;
+
+/**
+ * ipv4 ipv6 check util.
+ *
+ * @author Ifdevil
+ */
+public class NetAddressValidatorUtil {
+
+ private static final String PERCENT = "%";
+
+ private static final String DOUBLE_COLON = "::";
+
+ private static final String DOUBLE_COLON_FFFF = "::ffff:";
+
+ private static final String FE80 = "fe80:";
+
+ private static final int ZERO = 0;
+
+ private static final int SEVEN = 7;
+
+ private static final int FIVE = 5;
+
+ private static final Pattern IPV4_PATTERN = Pattern
+ .compile("^" + "(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)" + "(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}" + "$");
+
+ private static final Pattern IPV6_STD_PATTERN = Pattern
+ .compile("^" + "(?:[0-9a-fA-F]{1,4}:){7}" + "[0-9a-fA-F]{1,4}" + "$");
+
+ private static final Pattern IPV6_HEX_COMPRESSED_PATTERN = Pattern
+ .compile("^" + "(" + "(?:[0-9A-Fa-f]{1,4}" + "(?::[0-9A-Fa-f]{1,4})*)?" + ")" + "::"
+
+ + "(" + "(?:[0-9A-Fa-f]{1,4}" + "(?::[0-9A-Fa-f]{1,4})*)?" + ")" + "$");
+
+ private static final Pattern IPV6_MIXED_COMPRESSED_REGEX = Pattern.compile(
+ "^" + "(" + "(?:[0-9A-Fa-f]{1,4}" + "(?::[0-9A-Fa-f]{1,4})*)?" + ")" + "::" + "(" + "(?:[0-9A-Fa-f]{1,4}:"
+ + "(?:[0-9A-Fa-f]{1,4}:)*)?" + ")" + "$");
+
+ private static final Pattern IPV6_MIXED_UNCOMPRESSED_REGEX = Pattern
+ .compile("^" + "(?:[0-9a-fA-F]{1,4}:){6}" + "$");
+
+
+ public static boolean isIPv4Address(final String input) {
+ return IPV4_PATTERN.matcher(input).matches();
+ }
+
+ public static boolean isIPv6Address(final String input) {
+ return isIPv6StdAddress(input) || isIPv6HexCompressedAddress(input) || isLinkLocalIPv6WithZoneIndex(input)
+ || isIPv6IPv4MappedAddress(input) || isIPv6MixedAddress(input);
+ }
+
+ /**
+ * Check if the given address is a valid IPv6 address in the standard format
+ * The format is 'xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx'. Eight blocks of hexadecimal digits
+ * are required.
+ *
+ * @param input ip-address to check
+ * @return true if input
is in correct IPv6 notation.
+ */
+ public static boolean isIPv6StdAddress(final String input) {
+ return IPV6_STD_PATTERN.matcher(input).matches();
+ }
+
+ /**
+ * Check if the given address is a valid IPv6 address in the hex-compressed notation
+ * The format is 'xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx'. If all digits in a block are '0'
+ * the block can be left empty.
+ *
+ * @param input ip-address to check
+ * @return true if input
is in correct IPv6 (hex-compressed) notation.
+ */
+ public static boolean isIPv6HexCompressedAddress(final String input) {
+ return IPV6_HEX_COMPRESSED_PATTERN.matcher(input).matches();
+ }
+
+ /**
+ * Check if the given address is a valid IPv6 address in the mixed-standard or mixed-compressed notation.
+ * IPV6 Mixed mode consists of two parts, the first 96 bits (up to 6 blocks of 4 hex digits) are IPv6
+ * the IPV6 part can be either compressed or uncompressed
+ * the second block is a full IPv4 address
+ * e.g. '0:0:0:0:0:0:172.12.55.18'
+ *
+ * @param input ip-address to check
+ * @return true if input
is in correct IPv6 (mixed-standard or mixed-compressed) notation.
+ */
+ public static boolean isIPv6MixedAddress(final String input) {
+ int splitIndex = input.lastIndexOf(':');
+ if (splitIndex == -1) {
+ return false;
+ }
+ //the last part is a ipv4 address
+ boolean ipv4PartValid = isIPv4Address(input.substring(splitIndex + 1));
+ String ipV6Part = input.substring(ZERO, splitIndex + 1);
+ if (DOUBLE_COLON.equals(ipV6Part)) {
+ return ipv4PartValid;
+ }
+ boolean ipV6UncompressedDetected = IPV6_MIXED_UNCOMPRESSED_REGEX.matcher(ipV6Part).matches();
+ boolean ipV6CompressedDetected = IPV6_MIXED_COMPRESSED_REGEX.matcher(ipV6Part).matches();
+ return ipv4PartValid && (ipV6UncompressedDetected || ipV6CompressedDetected);
+ }
+
+ /**
+ * Check if input
is an IPv4 address mapped into a IPv6 address. These are
+ * starting with "::ffff:" followed by the IPv4 address in a dot-seperated notation.
+ * The format is '::ffff:d.d.d.d'
+ *
+ * @param input ip-address to check
+ * @return true if input
is in correct IPv6 notation containing an IPv4 address
+ */
+ public static boolean isIPv6IPv4MappedAddress(final String input) {
+ if (input.length() > SEVEN && input.substring(ZERO, SEVEN).equalsIgnoreCase(DOUBLE_COLON_FFFF)) {
+ String lowerPart = input.substring(SEVEN);
+ return isIPv4Address(lowerPart);
+ }
+ return false;
+ }
+
+ /**
+ * Check if input
is a link local IPv6 address starting with "fe80:" and containing
+ * a zone index with "%xxx". The zone index will not be checked.
+ *
+ * @param input ip-address to check
+ * @return true if address part of input
is in correct IPv6 notation.
+ */
+ public static boolean isLinkLocalIPv6WithZoneIndex(String input) {
+ if (input.length() > FIVE && input.substring(ZERO, FIVE).equalsIgnoreCase(FE80)) {
+ int lastIndex = input.lastIndexOf(PERCENT);
+ if (lastIndex > ZERO && lastIndex < (input.length() - 1)) {
+ String ipPart = input.substring(ZERO, lastIndex);
+ return isIPv6StdAddress(ipPart) || isIPv6HexCompressedAddress(ipPart);
+ }
+ }
+ return false;
+ }
+}
diff --git a/common/src/main/java/io/seata/common/util/NetUtil.java b/common/src/main/java/io/seata/common/util/NetUtil.java
index a5decf5c970..4feb47d1b7c 100644
--- a/common/src/main/java/io/seata/common/util/NetUtil.java
+++ b/common/src/main/java/io/seata/common/util/NetUtil.java
@@ -15,17 +15,22 @@
*/
package io.seata.common.util;
+import io.seata.common.Constants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.Inet6Address;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Enumeration;
-import java.util.regex.Pattern;
+import java.util.LinkedHashSet;
+import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
/**
* The type Net util.
@@ -34,13 +39,25 @@
*/
public class NetUtil {
private static final Logger LOGGER = LoggerFactory.getLogger(NetUtil.class);
- private static final String LOCALHOST = "127.0.0.1";
+ public static final boolean PREFER_IPV6_ADDRESSES = Boolean.parseBoolean(
+ System.getProperty("java.net.preferIPv6Addresses"));
+
+ private static final String LOCALHOST = "127.0.0.1";
private static final String ANY_HOST = "0.0.0.0";
+ public static final String LOCALHOST_IPV6 = "0:0:0:0:0:0:0:1";
+ public static final String LOCALHOST_SHORT_IPV6 = "::1";
+ public static final String ANY_HOST_IPV6 = "0:0:0:0:0:0:0:0";
+ public static final String ANY_HOST_SHORT_IPV6 = "::";
+
private static volatile InetAddress LOCAL_ADDRESS = null;
- private static final Pattern IP_PATTERN = Pattern.compile("\\d{1,3}(\\.\\d{1,3}){3,5}$");
+ private static final Set FORBIDDEN_HOSTS = Collections.unmodifiableSet(
+ new LinkedHashSet<>(Arrays.asList(
+ LOCALHOST, ANY_HOST,
+ LOCALHOST_IPV6, LOCALHOST_SHORT_IPV6,
+ ANY_HOST_IPV6,ANY_HOST_SHORT_IPV6)));
/**
* To string address string.
@@ -83,12 +100,12 @@ public static String toStringAddress(InetSocketAddress address) {
* @return the inet socket address
*/
public static InetSocketAddress toInetSocketAddress(String address) {
- int i = address.indexOf(':');
+ String[] ipPortStr = splitIPPortStr(address);
String host;
int port;
- if (i > -1) {
- host = address.substring(0, i);
- port = Integer.parseInt(address.substring(i + 1));
+ if (null != ipPortStr) {
+ host = ipPortStr[0];
+ port = Integer.parseInt(ipPortStr[1]);
} else {
host = address;
port = 0;
@@ -96,6 +113,27 @@ public static InetSocketAddress toInetSocketAddress(String address) {
return new InetSocketAddress(host, port);
}
+ public static String[] splitIPPortStr(String address) {
+ if (StringUtils.isBlank(address)) {
+ throw new IllegalArgumentException("ip and port string cannot be empty!");
+ }
+ if (address.charAt(0) == '[') {
+ address = removeBrackets(address);
+ }
+ String[] serverAddArr = null;
+ int i = address.lastIndexOf(Constants.IP_PORT_SPLIT_CHAR);
+ if (i > -1) {
+ serverAddArr = new String[2];
+ String hostAddress = address.substring(0,i);
+ if (hostAddress.contains("%")) {
+ hostAddress = hostAddress.substring(0, hostAddress.indexOf("%"));
+ }
+ serverAddArr[0] = hostAddress;
+ serverAddArr[1] = address.substring(i + 1);
+ }
+ return serverAddArr;
+ }
+
/**
* To long long.
*
@@ -121,7 +159,23 @@ public static long toLong(String address) {
*/
public static String getLocalIp(String... preferredNetworks) {
InetAddress address = getLocalAddress(preferredNetworks);
- return address == null ? LOCALHOST : address.getHostAddress();
+ if (null != address) {
+ String hostAddress = address.getHostAddress();
+ if (address instanceof Inet6Address) {
+ if (hostAddress.contains("%")) {
+ hostAddress = hostAddress.substring(0, hostAddress.indexOf("%"));
+ }
+ }
+ return hostAddress;
+ }
+ return localIP();
+ }
+
+ public static String localIP() {
+ if (PREFER_IPV6_ADDRESSES) {
+ return LOCALHOST_IPV6;
+ }
+ return LOCALHOST;
}
/**
@@ -224,7 +278,21 @@ private static boolean isValidAddress(InetAddress address) {
if (address == null || address.isLoopbackAddress()) {
return false;
}
- return isValidIp(address.getHostAddress(), false);
+ String hostAddress = address.getHostAddress();
+ if (address instanceof Inet6Address) {
+ if (!PREFER_IPV6_ADDRESSES) {
+ return false;
+ }
+ if (address.isAnyLocalAddress() // filter ::/128
+ || address.isLinkLocalAddress() //filter fe80::/10
+ || address.isSiteLocalAddress()// filter fec0::/10
+ || isUniqueLocalAddress(address)) //filter fd00::/8
+ {
+ return false;
+ }
+ return isValidIPv6(hostAddress);
+ }
+ return !FORBIDDEN_HOSTS.contains(hostAddress) && isValidIPv4(hostAddress);
}
/**
@@ -240,11 +308,10 @@ public static boolean isValidIp(String ip, boolean validLocalAndAny) {
}
ip = convertIpIfNecessary(ip);
if (validLocalAndAny) {
- return IP_PATTERN.matcher(ip).matches();
+ return isValidIPv4(ip) || isValidIPv6(ip);
} else {
- return !ANY_HOST.equals(ip) && !LOCALHOST.equals(ip) && IP_PATTERN.matcher(ip).matches();
+ return !FORBIDDEN_HOSTS.contains(ip) && (isValidIPv4(ip) || isValidIPv6(ip));
}
-
}
/**
@@ -254,7 +321,7 @@ public static boolean isValidIp(String ip, boolean validLocalAndAny) {
* @return java.lang.String
*/
private static String convertIpIfNecessary(String ip) {
- if (IP_PATTERN.matcher(ip).matches()) {
+ if (isValidIPv4(ip) || isValidIPv6(ip)) {
return ip;
} else {
try {
@@ -264,4 +331,24 @@ private static String convertIpIfNecessary(String ip) {
}
}
}
+
+ public static boolean isValidIPv4(String ip) {
+ return NetAddressValidatorUtil.isIPv4Address(ip);
+ }
+
+ public static boolean isValidIPv6(String ip) {
+ return NetAddressValidatorUtil.isIPv6Address(ip);
+ }
+
+ private static boolean isUniqueLocalAddress(InetAddress address) {
+ byte[] ip = address.getAddress();
+ return (ip[0] & 0xff) == 0xfd;
+ }
+
+ private static String removeBrackets(String str) {
+ if (StringUtils.isBlank(str)) {
+ return "";
+ }
+ return str.replaceAll("[\\[\\]]", "");
+ }
}
diff --git a/common/src/test/java/io/seata/common/util/NetAddressValidatorUtilTest.java b/common/src/test/java/io/seata/common/util/NetAddressValidatorUtilTest.java
new file mode 100644
index 00000000000..b274855cf1f
--- /dev/null
+++ b/common/src/test/java/io/seata/common/util/NetAddressValidatorUtilTest.java
@@ -0,0 +1,56 @@
+package io.seata.common.util;
+
+/*
+ * Copyright 1999-2019 Seata.io Group.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * The Net Validator util test.
+ *
+ * @author Ifdevil
+ */
+public class NetAddressValidatorUtilTest {
+
+ @Test
+ public void isIPv6Address() {
+ assertThat(NetAddressValidatorUtil.isIPv6Address("2000:0000:0000:0000:0001:2345:6789:abcd")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv6Address("2001:DB8:0:0:8:800:200C:417A")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv6Address("2001:DB8::8:800:200C:417A")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv6Address("2001:DB8::8:800:200C141aA")).isFalse();
+ assertThat(NetAddressValidatorUtil.isIPv6Address("::")).isTrue();
+ }
+
+ @Test
+ public void isIPv6MixedAddress() {
+ assertThat(NetAddressValidatorUtil.isIPv6MixedAddress("1:0:0:0:0:0:172.12.55.18")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv6MixedAddress("2001:DB8::8:800:200C141aA")).isFalse();
+ }
+
+ @Test
+ public void isIPv6IPv4MappedAddress() {
+ assertThat(NetAddressValidatorUtil.isIPv6IPv4MappedAddress(":ffff:1.1.1.1")).isFalse();
+ assertThat(NetAddressValidatorUtil.isIPv6IPv4MappedAddress("::FFFF:192.168.1.2")).isTrue();
+ }
+
+ @Test
+ public void isIPv4Address() {
+ assertThat(NetAddressValidatorUtil.isIPv4Address("192.168.1.2")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv4Address("127.0.0.1")).isTrue();
+ assertThat(NetAddressValidatorUtil.isIPv4Address("999.999.999.999")).isFalse();
+ }
+}
diff --git a/common/src/test/java/io/seata/common/util/NetUtilTest.java b/common/src/test/java/io/seata/common/util/NetUtilTest.java
index c830e0fc892..ba3f2c75aaf 100644
--- a/common/src/test/java/io/seata/common/util/NetUtilTest.java
+++ b/common/src/test/java/io/seata/common/util/NetUtilTest.java
@@ -181,4 +181,20 @@ public void testIsValidIp() {
}
+ @Test
+ public void testSplitIPPortStr() {
+ String[] ipPort = new String[]{"127.0.0.1","8080"};
+ assertThat(NetUtil.splitIPPortStr("127.0.0.1:8080")).isEqualTo(ipPort);
+ ipPort = new String[]{"::","8080"};
+ assertThat(NetUtil.splitIPPortStr("[::]:8080")).isEqualTo(ipPort);
+ ipPort = new String[]{"2000:0000:0000:0000:0001:2345:6789:abcd","8080"};
+ assertThat(NetUtil.splitIPPortStr("2000:0000:0000:0000:0001:2345:6789:abcd%10:8080")).isEqualTo(ipPort);
+ ipPort = new String[]{"2000:0000:0000:0000:0001:2345:6789:abcd","8080"};
+ assertThat(NetUtil.splitIPPortStr("[2000:0000:0000:0000:0001:2345:6789:abcd]:8080")).isEqualTo(ipPort);
+ ipPort = new String[]{"::FFFF:192.168.1.2","8080"};
+ assertThat(NetUtil.splitIPPortStr("::FFFF:192.168.1.2:8080")).isEqualTo(ipPort);
+ ipPort = new String[]{"::FFFF:192.168.1.2","8080"};
+ assertThat(NetUtil.splitIPPortStr("[::FFFF:192.168.1.2]:8080")).isEqualTo(ipPort);
+ }
+
}
diff --git a/core/src/main/java/io/seata/core/rpc/netty/ChannelManager.java b/core/src/main/java/io/seata/core/rpc/netty/ChannelManager.java
index 33e39033e95..49bd6b12d9c 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/ChannelManager.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/ChannelManager.java
@@ -19,6 +19,7 @@
import io.seata.common.Constants;
import io.seata.common.exception.FrameworkException;
import io.seata.common.util.CollectionUtils;
+import io.seata.common.util.NetUtil;
import io.seata.common.util.StringUtils;
import io.seata.core.protocol.IncompatibleVersionException;
import io.seata.core.protocol.RegisterRMRequest;
@@ -97,7 +98,16 @@ private static String buildClientId(String applicationId, Channel channel) {
}
private static String[] readClientId(String clientId) {
- return clientId.split(Constants.CLIENT_ID_SPLIT_CHAR);
+ int i = clientId.indexOf(Constants.CLIENT_ID_SPLIT_CHAR);
+ String[] clientIdInfo = null;
+ if (i > -1) {
+ String applicationId = clientId.substring(0, i);
+ String[] ipPortStr = NetUtil.splitIPPortStr(clientId.substring(i + 1));
+ if (null != ipPortStr && ipPortStr.length == 2) {
+ clientIdInfo = new String[]{applicationId, ipPortStr[0], ipPortStr[1]};
+ }
+ }
+ return clientIdInfo;
}
private static RpcContext buildChannelHolder(NettyPoolKey.TransactionRole clientRole, String version, String applicationId,
diff --git a/core/src/main/java/io/seata/core/rpc/netty/NettyClientChannelManager.java b/core/src/main/java/io/seata/core/rpc/netty/NettyClientChannelManager.java
index d93de7a2bde..8de294551a1 100644
--- a/core/src/main/java/io/seata/core/rpc/netty/NettyClientChannelManager.java
+++ b/core/src/main/java/io/seata/core/rpc/netty/NettyClientChannelManager.java
@@ -205,7 +205,7 @@ void reconnect(String transactionServiceGroup) {
if (CollectionUtils.isNotEmpty(channelAddress)) {
List aliveAddress = new ArrayList<>(channelAddress.size());
for (String address : channelAddress) {
- String[] array = address.split(":");
+ String[] array = NetUtil.splitIPPortStr(address);
aliveAddress.add(new InetSocketAddress(array[0], Integer.parseInt(array[1])));
}
RegistryFactory.getInstance().refreshAliveLookup(transactionServiceGroup, aliveAddress);
diff --git a/discovery/seata-discovery-core/src/main/java/io/seata/discovery/registry/FileRegistryServiceImpl.java b/discovery/seata-discovery-core/src/main/java/io/seata/discovery/registry/FileRegistryServiceImpl.java
index 4f4fa0840f8..8daad242736 100644
--- a/discovery/seata-discovery-core/src/main/java/io/seata/discovery/registry/FileRegistryServiceImpl.java
+++ b/discovery/seata-discovery-core/src/main/java/io/seata/discovery/registry/FileRegistryServiceImpl.java
@@ -19,6 +19,7 @@
import java.util.ArrayList;
import java.util.List;
+import io.seata.common.util.NetUtil;
import io.seata.common.util.StringUtils;
import io.seata.config.ConfigChangeListener;
import io.seata.config.Configuration;
@@ -88,7 +89,7 @@ public List lookup(String key) throws Exception {
String[] endpoints = endpointStr.split(ENDPOINT_SPLIT_CHAR);
List inetSocketAddresses = new ArrayList<>();
for (String endpoint : endpoints) {
- String[] ipAndPort = endpoint.split(IP_PORT_SPLIT_CHAR);
+ String[] ipAndPort = NetUtil.splitIPPortStr(endpoint);
if (ipAndPort.length != 2) {
throw new IllegalArgumentException("endpoint format should like ip:port");
}
diff --git a/discovery/seata-discovery-etcd3/src/main/java/io/seata/discovery/registry/etcd3/EtcdRegistryServiceImpl.java b/discovery/seata-discovery-etcd3/src/main/java/io/seata/discovery/registry/etcd3/EtcdRegistryServiceImpl.java
index b2bc4b1858e..4330e9d6bda 100644
--- a/discovery/seata-discovery-etcd3/src/main/java/io/seata/discovery/registry/etcd3/EtcdRegistryServiceImpl.java
+++ b/discovery/seata-discovery-etcd3/src/main/java/io/seata/discovery/registry/etcd3/EtcdRegistryServiceImpl.java
@@ -248,7 +248,7 @@ private void refreshCluster(String cluster) throws Exception {
GetResponse getResponse = getClient().getKVClient().get(buildRegistryKeyPrefix(cluster), getOption).get();
//2.add to list
List instanceList = getResponse.getKvs().stream().map(keyValue -> {
- String[] instanceInfo = keyValue.getValue().toString(UTF_8).split(":");
+ String[] instanceInfo = NetUtil.splitIPPortStr(keyValue.getValue().toString(UTF_8));
return new InetSocketAddress(instanceInfo[0], Integer.parseInt(instanceInfo[1]));
}).collect(Collectors.toList());
clusterAddressMap.put(cluster, new Pair<>(getResponse.getHeader().getRevision(), instanceList));
diff --git a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
index 1a0363c70d5..336037f8c9d 100644
--- a/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
+++ b/discovery/seata-discovery-redis/src/main/java/io/seata/discovery/registry/redis/RedisRegistryServiceImpl.java
@@ -84,7 +84,7 @@ private RedisRegistryServiceImpl() {
this.clusterName = seataConfig.getConfig(REDIS_FILEKEY_PREFIX + REGISTRY_CLUSTER_KEY, DEFAULT_CLUSTER);
String password = seataConfig.getConfig(getRedisPasswordFileKey());
String serverAddr = seataConfig.getConfig(getRedisAddrFileKey());
- String[] serverArr = serverAddr.split(":");
+ String[] serverArr = NetUtil.splitIPPortStr(serverAddr);
String host = serverArr[0];
int port = Integer.parseInt(serverArr[1]);
int db = seataConfig.getInt(getRedisDbFileKey());
diff --git a/discovery/seata-discovery-sofa/src/main/java/io/seata/discovery/registry/sofa/SofaRegistryServiceImpl.java b/discovery/seata-discovery-sofa/src/main/java/io/seata/discovery/registry/sofa/SofaRegistryServiceImpl.java
index 28105f390c7..a5011638214 100644
--- a/discovery/seata-discovery-sofa/src/main/java/io/seata/discovery/registry/sofa/SofaRegistryServiceImpl.java
+++ b/discovery/seata-discovery-sofa/src/main/java/io/seata/discovery/registry/sofa/SofaRegistryServiceImpl.java
@@ -190,8 +190,8 @@ private List flatData(Map> instances) {
for (Map.Entry> entry : instances.entrySet()) {
for (String str : entry.getValue()) {
- String ip = StringUtils.substringBefore(str, HOST_SEPERATOR);
- String port = StringUtils.substringAfter(str, HOST_SEPERATOR);
+ String ip = StringUtils.substringBeforeLast(str, HOST_SEPERATOR);
+ String port = StringUtils.substringAfterLast(str, HOST_SEPERATOR);
InetSocketAddress inetSocketAddress = new InetSocketAddress(ip, Integer.parseInt(port));
result.add(inetSocketAddress);
}
diff --git a/discovery/seata-discovery-zk/src/main/java/io/seata/discovery/registry/zk/ZookeeperRegisterServiceImpl.java b/discovery/seata-discovery-zk/src/main/java/io/seata/discovery/registry/zk/ZookeeperRegisterServiceImpl.java
index 24344d196ec..fe2613a5fde 100644
--- a/discovery/seata-discovery-zk/src/main/java/io/seata/discovery/registry/zk/ZookeeperRegisterServiceImpl.java
+++ b/discovery/seata-discovery-zk/src/main/java/io/seata/discovery/registry/zk/ZookeeperRegisterServiceImpl.java
@@ -42,8 +42,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static io.seata.common.Constants.IP_PORT_SPLIT_CHAR;
-
/**
* zookeeper path as /registry/zk/
*
@@ -303,7 +301,7 @@ private void refreshClusterAddressMap(String clusterName, List instances
}
for (String path : instances) {
try {
- String[] ipAndPort = path.split(IP_PORT_SPLIT_CHAR);
+ String[] ipAndPort = NetUtil.splitIPPortStr(path);
newAddressList.add(new InetSocketAddress(ipAndPort[0], Integer.parseInt(ipAndPort[1])));
} catch (Exception e) {
LOGGER.warn("The cluster instance info is error, instance info:{}", path);