ndk中使用native Socket

这篇博客介绍了在Android NDK中使用本地Socket通信的两种命名方式:普通命名和抽象命名空间。普通命名需要创建socket文件,客户端需知道文件路径;而抽象命名空间则无需创建文件,仅需全局名字即可连接。文章提到了在使用抽象命名空间时,sun_path数组的第一个字节应置0。还提供了相关参考资料和Demo的下载链接。
摘要由CSDN通过智能技术生成

socket进程通信命名方式有两种。一是普通的命名,socket会根据此命名创建一个同名的socket文件,客户端连接的时候通过读取该socket文件连接到socket服务端。这种方式的弊端是服务端必须对socket文件的路径具备写权限,客户端必须知道socket文件路径,且必须对该路径有读权限。

另外一种命名方式是抽象命名空间,这种方式不需要创建socket文件,只需要命名一个全局名字,即可让客户端根据此名字进行连接。后者的实现过程与前者的差别是,后者在对地址结构成员sun_path数组赋值的时候,必须把第一个字节置0,即sun_path[0] = 0。

具体实现

#include "com_apress_echo_EchoClientActivity.h"
#include "com_apress_echo_EchoServerActivity.h"
#include "com_apress_echo_LocalEchoActivity.h"

// JNI
#include <jni.h>

// NULL
#include <stdio.h>

// va_list, vsnprintf
#include <stdarg.h>

// errno
#include <errno.h>

// strerror_r, memset
#include <string.h>

// socket, bind, getsockname, listen, accept, recv, send, connect
#include <sys/types.h>
#include <sys/socket.h>

// sockaddr_un
#include <sys/un.h>

// htons, sockaddr_in
#include <netinet/in.h>

// inet_ntop
#include <arpa/inet.h>

// close, unlink
#include <unistd.h>

// offsetof
#include <stddef.h>

// 最大消息长度
#define MAX_LOG_MESSAGE_LENGTH 256

// 最大数据缓冲区大小
#define MAX_BUFFER_SIZE 80

/**
 * 将给定的消息记录到应用程序
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param format message format and arguments.
 */
static void LogMessage(
		JNIEnv* env,
		jobject obj,
		const char* format,
		...)
{
	// 缓存日志方法id
	static jmethodID methodID = NULL;

	// 如果方法id未缓存
	if (NULL == methodID)
	{
		// 从对象获取类
		jclass clazz = env->GetObjectClass(obj);

		// 从给定方法获取方法id
		methodID = env->GetMethodID(clazz, "logMessage",
				"(Ljava/lang/String;)V");

		// 释放引用类
		env->DeleteLocalRef(clazz);
	}

	// 如果找到方法
	if (NULL != methodID)
	{
		// 格式化日志消息
		char buffer[MAX_LOG_MESSAGE_LENGTH];

		va_list ap;
		va_start(ap, format);
		vsnprintf(buffer, MAX_LOG_MESSAGE_LENGTH, format, ap);
		va_end(ap);

		// 将缓冲区转换为java字符串
		jstring message = env->NewStringUTF(buffer);

		// 如果字符串构造正确
		if (NULL != message)
		{
			// 记录消息
			env->CallVoidMethod(obj, methodID, message);

			// 释放消息引用
			env->DeleteLocalRef(message);
		}
	}
}

/**
 *
 * 用给定的异常类和异常消息抛出新的异常
 *
 * @param env JNIEnv interface.
 * @param className class name.
 * @param message exception message.
 */
static void ThrowException(
		JNIEnv* env,
		const char* className,
		const char* message)
{
	// 获取异常类
	jclass clazz = env->FindClass(className);

	// 如果异常类未找到
	if (NULL != clazz)
	{
		// 抛出异常
		env->ThrowNew(clazz, message);

		// 释放原生类引用
		env->DeleteLocalRef(clazz);
	}
}

/**
 * 用给定异常类和基于错误号的错误消息抛出新异常
 *
 *
 * @param env JNIEnv interface.
 * @param className class name.
 * @param errnum error number.
 */
static void ThrowErrnoException(
		JNIEnv* env,
		const char* className,
		int errnum)
{
	char buffer[MAX_LOG_MESSAGE_LENGTH];

	// 获取错误号消息
	if (-1 == strerror_r(errnum, buffer, MAX_LOG_MESSAGE_LENGTH))
	{
		strerror_r(errno, buffer, MAX_LOG_MESSAGE_LENGTH);
	}

	// 抛出异常
	ThrowException(env, className, buffer);
}

/**
 * Constructs a new TCP socket.
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @return socket descriptor.
 * @throws IOException
 */
static int NewTcpSocket(JNIEnv* env, jobject obj)
{
	// 构造socket
	LogMessage(env, obj, "Constructing a new TCP socket...");
	//socket(int domain,int type,int protocol)
	//domain PF_LOCAL:主机内部通信协议族,改协议族使物理上运行在同一设备上的
	//应用程序可以用socket apis彼此通信
	//PF_INET:internet第4版协议族,改协议族使应用程序可以与网络上其他
	//运行的应用程序进行通信
	//type:指定通信语义 SOCK_STREAM使用TCP协议
	//SOCK_DGRAM:使用UDP协议
	int tcpSocket = socket(PF_INET, SOCK_STREAM, 0);

	// 检查socket构造是否正确
	if (-1 == tcpSocket)
	{
		// T抛出带错误号的异常
		ThrowErrnoException(env, "java/io/IOException", errno);
	}

	return tcpSocket;
}

/**
 * 将socket绑定到某一端口号
 *
 * @param env JNIEnv interface.
 * @param obj object instance.
 * @param sd socket descriptor.
 * @param port port number or zero for random port.
 * @throws IOException
 */
static void BindSocketToPort(
		JNIEnv* env,
		jobject obj,
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值