为什么单独实现,这是因为JAVA标准库提供的函数有性能问题,它会走DNS查询有网络IO,而且还是同步阻塞的,无论是客户端还是服务器,这都应该是不被允许的行为。
JNI实现:
bytes_to_address_string(byte[] address) 字节转IP地址字符串
string_to_address_bytes(string address) IP地址字符串转字节
// package: com.app.android.c
// public final class libxxx
// public native string bytes_to_address_string(byte[] address)
__LIBXXX__(jstring) Java_com_app_android_c_libxxx_bytes_1to_1address_1string(JNIEnv* env, jobject this_, jbyteArray address_) {
__LIBXXX_MAIN__
if (NULL == address_) {
return env->NewStringUTF("0.0.0.0");
}
int length = env->GetArrayLength(address_);
if (length < 4) {
return env->NewStringUTF("0.0.0.0");
}
const char* address_bytes = (char*)env->GetByteArrayElements(address_, NULL);
if (NULL == address_bytes) {
return env->NewStringUTF("0.0.0.0");
}
char sz[INET6_ADDRSTRLEN];
const char* r = inet_ntop(length >= 16 ? INET6_ADDRSTRLEN : AF_INET, (struct in_addr*)address_bytes, sz, sizeof(sz)); /* in6_addr */
env->ReleaseByteArrayElements(address_, (jbyte*)address_bytes, 0);
if (!r) {
return env->NewStringUTF("0.0.0.0");
}
return env->NewStringUTF(sz); // inet_ntoa(*(struct in_addr*)address);
}
// package: com.app.android.c
// public final class libxxx
// public native byte[] string_to_address_bytes(string address)
__LIBXXX__(jbyteArray) Java_com_app_android_c_libxxx_string_1to_1address_1bytes(JNIEnv* env, jobject this_, jstring address_) {
__LIBXXX_MAIN__
std::shared_ptr<app::string> address_managed = JNIENV_GetStringUTFChars(env, address_);
uint8_t bytes[16];
int af = 0;
if (NULL == address_managed || address_managed->empty()) {
*(uint32_t*)bytes = 0;
af = AF_INET;
}
else {
const char* address = NULL;
if (NULL != address_managed) {
address = address_managed->data();
}
struct sockaddr_in6 in6;
int err = inet_pton(AF_INET6, address, &in6);
if (err > 0) {
af = AF_INET6;
memcpy(bytes, &in6.sin6_addr, sizeof(bytes));
}
else {
uint32_t addressV4 = inet_addr(address);
if (addressV4 == htonl(INADDR_NONE)) {
int b[4];
if (sscanf(address, "%d.%d.%d.%d", &b[0], &b[1], &b[2], &b[3]) != 4) {
return NULL;
}
}
af = AF_INET;
*(uint32_t*)bytes = addressV4;
}
}
int result_count =
af == AF_INET ?
4 :
16;
jbyteArray result = env->NewByteArray(result_count);
if (NULL == result) {
return NULL;
}
jbyte* p = env->GetByteArrayElements(result, NULL);
memcpy(p, bytes, result_count);
env->ReleaseByteArrayElements(result, p, 0);
return result;
}
static std::shared_ptr<xxx::string> JNIENV_GetStringUTFChars(JNIEnv* env, const jstring& v) noexcept {
std::shared_ptr<xxx::string> result;
if (NULL != v) {
char* s = (char*)env->GetStringUTFChars(v, NULL);
if (NULL != s) {
result =
xxx::make_shared_object<xxx::string>(s);
env->ReleaseStringUTFChars(v, s);
}
}
return result;
}
Java:
// Convert a string to an IP address.
@Nullable
public static InetAddress string_to_address(String address) {
try {
byte[] V = libxxx.c.string_to_address_bytes(address);
if (V == null) {
return null;
} else {
return address_of(V);
}
} catch (Throwable ignored) {
return null;
}
}
// Convert a bytes to an IP address string.
public static String bytes_to_address_string(byte[] address) {
return libxxx.c.bytes_to_address_string(address);
}