下面只是代码片段,想看详细的代码请clone代码。
本人没有在android虚拟机上看到通信成功,试了好多配置依然不行,过段时间找两个手机再试试。
运行项目时,如果要看tcp的,则需要更改ClientTask、ServerTask类中的onBackground方法,将jni方法替换成tcp的。udp的也一样,udp的则替换成udp的jni方法。
地址:https://gitee.com/xd_box/NDK_Socket
1.接收数据报
__fd:socket实例
__buf:保存从socket接收的数据
__n:缓冲区大小
__flags:额外标志
__src_addr:保存客户端发送包的协议地址
__src_addr_length:协议地址的内存空间大小
成功返回接收到的字节数,失败返回-1
__socketcall ssize_t recvfrom(int __fd, void* __buf, size_t __n, int __flags, struct sockaddr* __src_addr, socklen_t* __src_addr_length);
static ssize_t ReceiveDatagramFromSocket(JNIEnv *env, jobject obj, int sd,
struct sockaddr_in *address, char *buffer,
size_t bufferSize) {
socklen_t addressLength = sizeof(struct sockaddr_in);
//从socket中接受数据包
LogMessage(env, obj, "从socket接受数据");
ssize_t recvSize = recvfrom(sd, buffer, bufferSize, 0, (struct sockaddr *) address,
&addressLength);
if (-1 == recvSize) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else {
LogAddress(env, obj, "接收到", address);
//以NULL种植缓冲区使其为一个字符串
buffer[recvSize] = NULL;
if (recvSize > 0) {
LogMessage(env, obj, "接收到%d字节:%s", recvSize, buffer);
}
}
return recvSize;
}
2.发送数据报
__fd:socket实例
__buf:要发送的数据的指针
__n:缓冲区大小
__flags:额外标志
__dst_addr:目标地址
__dst_addr_length:地址结构大小
成功返回传送的字节数,失败但会-1
__socketcall ssize_t sendto(int __fd, const void* __buf, size_t __n, int __flags, const struct sockaddr* __dst_addr, socklen_t __dst_addr_length);
static ssize_t SendDatagramToSpcket(JNIEnv *env, jobject obj, int sd,
const struct sockaddr_in *address, const char *buffer,
size_t bufferSize) {
LogAddress(env, obj, "Sending to", address);
ssize_t sentSize = sendto(sd, buffer, bufferSize, 0, (const sockaddr *) address,
sizeof(struct sockaddr_in));
if (-1 == sentSize) {
ThrowErrnoException(env, "java/io/IOException", errno);
} else if (sentSize > 0) {
LogMessage(env, obj, "sent %d 字节:%s", sentSize, buffer);
}
return sentSize;
}
3.udp服务
开启udp服务
extern "C"
JNIEXPORT void JNICALL
Java_com_example_testnt_EchoServerActivity_nativeStartUdpServer(JNIEnv *env, jobject thiz,
jint port) {
int serverSocket = NewUdpSocket(env, thiz);
if (NULL == env->ExceptionOccurred()) {
BindSocketToPort(env, thiz, serverSocket, (unsigned short) port);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
if (0 == port) {
GetSocketPort(env, thiz, serverSocket);
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
}
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
char buffer[MAX_BUFFER_SZIE];
ssize_t recvSize;
ssize_t sentSize;
//接收
recvSize = ReceiveDatagramFromSocket(env, thiz, serverSocket, &address, buffer,
MAX_BUFFER_SZIE);
if ((0 == recvSize) || (NULL != env->ExceptionOccurred())) {
goto exit;
}
sentSize = SendDatagramToSpcket(env, thiz, serverSocket, &address, buffer,
(size_t) recvSize);
if ((0 == sentSize) || (NULL != env->ExceptionOccurred())) {
goto exit;
}
}
exit:
if (serverSocket > 0) {
close(serverSocket);
}
}
4.udp客户端
extern "C"
JNIEXPORT void JNICALL
Java_com_example_testnt_EchoClientActivity_nativeStartUdpClient(JNIEnv *env, jobject thiz,
jstring ip, jint port,
jstring message) {
int clientSocket = NewUdpSocket(env, thiz);
if (NULL == env->ExceptionOccurred()) {
struct sockaddr_in address;
memset(&address, 0, sizeof(address));
address.sin_family = PF_INET;
const char *ipAddress = env->GetStringUTFChars(ip, NULL);
if (NULL == ipAddress) {
goto exit;
}
//将IP地址字符串转换为网络地址
int result = inet_aton(ipAddress, &(address.sin_addr));
env->ReleaseStringUTFChars(ip, ipAddress);
if (0 == result) {
ThrowErrnoException(env, "java/io/IOException", errno);
goto exit;
}
//转换为网络字节顺序
address.sin_port = htons(port);
const char *messageText = env->GetStringUTFChars(message, NULL);
if (NULL == messageText) {
goto exit;
}
jsize messageSize = env->GetStringUTFLength(message);
//发送
SendDatagramToSpcket(env, thiz, clientSocket, &address, messageText, (size_t) messageSize);
env->ReleaseStringUTFChars(message, messageText);
//失败
if (NULL != env->ExceptionOccurred()) {
goto exit;
}
char buffer[MAX_BUFFER_SZIE];
memset(&address, 0, sizeof(address));
ReceiveDatagramFromSocket(env, thiz, clientSocket, &address, buffer, MAX_BUFFER_SZIE);
}
exit:
if (clientSocket > 0) {
close(clientSocket);
}
}