android socket

android socket实际上还是linux sokcet,只是android socket不支持原始套接字,下面概括下介绍socket和一些常用的函数原型


Socket接口是TCP/IP网络的APISocket接口定义了许多函数或例程,程式员能够用他们来研发TCP/IP网络上的应用程式。要学Internet上的TCP/IP网络编程,必须理解Socket接口。
Socket
接口设计者最先是将接口放在Unix操作系统里面的。假如了解Unix系统的输入和输出的话,就很容易了解Socket了。网络的 Socket数据传输是一种特别的I/OSocket也是一种文档描述符。Socket也具备一个类似于打开文档的函数调用Socket(),该函数返回一个整型的Socket描述符,随后的连接建立、数据传输等操作都是通过该Socket实现的。常用的Socket类型有两种:流式Socket SOCK_STREAM)和数据报式SocketSOCK_DGRAM)。流式是一种面向连接的Socket,针对于面向连接的TCP服务应用;数据报式Socket是一种无连接的Socket,对应于无连接的UDP服务应用。


Socket的建立


为了建立Socket,程式能够调用Socket函数,该函数返回一个类似于文档描述符的句柄。socket函数原型为:
   

int socket(int domain, int type, int protocol);


domain 指明所使用的协议族,通常为 PF_INET ,表示互连网协议族( TCP/IP 协议族); type 参数指定 socket 的类型:  SOCK_STREAM  SOCK_DGRAM Socket 接口还定义了原始 Socket SOCK_RAW ),允许程式使用低层协议; protocol 通常赋值 "0"  Socket() 调用返回一个整型 socket 描述符,您能够在后面的调用使用他。
    Socket 描述符是个指向内部数据结构的指针,他指向描述符表入口。调用 Socket 函数时, socket 执行体将建立一个 Socket ,实际上 " 建立一个 Socket" 意味着为一个 Socket 数据结构分配存储空间。 Socket 执行体为您管理描述符表。
  两个网络程式之间的一个网络连接包括五种信息:通信协议、本地协议地址、本地主机端口、远端主机地址和远端协议端口。 Socket 数据结构中包含这五种信息。

Socket的配置


通过socket调用返回一个socket描述符后,在使用socket进行网络传输以前,必须配置该socket。面向连接的socket客户端通过调用Connect函数在socket数据结构中保存本地和远端信息。无连接socket的客户端和服务端连同面向连接socket的服务端通过调用 bind函数来配置本地信息。
Bind
函数将socket和本机上的一个端口相关联,随后您就能够在该端口监听服务请求。Bind函数原型为:
  

 int bind(int sockfd,struct sockaddr *my_addr, int addrlen);


    Sockfd 是调用 socket 函数返回的 socket 描述符 ,my_addr 是个指向包含有本机 IP 地址及端口号等信息的 sockaddr 类型的指针; addrlen 常被配置为 sizeof(struct sockaddr)
    struct sockaddr 结构类型是用来保存 socket 信息的:
 
  struct sockaddr {
   unsigned short sa_family; /* 地址族, AF_xxx */
char sa_data[14]; /* 14 字节的协议地址 */
};


    sa_family 一般为 AF_INET ,代表 Internet TCP/IP )地址族; sa_data 则包含该 socket IP 地址和端口号。
     另外更有一种结构类型:
  
 struct sockaddr_in {
   short int sin_family; /* 地址族 */
   unsigned short int sin_port; /* 端口号 */
   struct in_addr sin_addr; /* IP地址 */
   unsigned char sin_zero[8]; /* 填充0 以保持和struct sockaddr同样大小 */
   };


这个结构更方便使用。 sin_zero 用来将 sockaddr_in 结构填充到和 struct sockaddr 同样的长度,能够用 bzero() memset() 函数将其置为零。指向 sockaddr_in  的指针和指向 sockaddr 的指针能够相互转换,这意味着假如一个函数所需参数类型是 sockaddr 时,您能够在函数调用的时候将一个指向  sockaddr_in 的指针转换为指向 sockaddr 的指针;或相反。
  使用 bind 函数时,能够用下面的赋值实现自动获得本机 IP 地址和随机获取一个没有被占用的端口号:
    my_addr.sin_port = 0; /*  系统随机选择一个未被使用的端口号  */
    my_addr.sin_addr.s_addr = INADDR_ANY; /*  填入本机 IP 地址  */
通过将 my_addr.sin_port 置为 0 ,函数会自动为您选择一个未占用的端口来使用。同样,通过将 my_addr.sin_addr.s_addr 置为 INADDR_ANY ,系统会自动填入本机 IP 地址。
注意在使用 bind 函数是需要将 sin_port sin_addr 转换成为网络字节优先顺序;而 sin_addr 则无需转换。
  电脑数据存储有两种字节优先顺序:高位字节优先和低位字节优先。 Internet 上数据以高位字节优先顺序在网络上传输,所以对于在内部是以低位字节优先方式存储数据的机器,在 Internet 上传输数据时就需要进行转换,否则就会出现数据不一致。
     下面是几个字节顺序转换函数:
·htonl()
:把 32 位值从主机字节序转换成网络字节序
·htons()
:把 16 位值从主机字节序转换成网络字节序
·ntohl()
:把 32 位值从网络字节序转换成主机字节序
·ntohs()
:把 16 位值从网络字节序转换成主机字节序
    Bind() 函数在成功被调用时返回 0 ;出现错误时返回 "-1" 并将 errno 置为相应的错误号。需要注意的是,在调用 bind 函数时一般不要将端口号置为小于 1024 的值,因为 1 1024 是保留端口号,您能够选择大于 1024 中的任何一个没有被占用的端口号。


连接建立


面向连接的客户程式使用Connect函数来配置socket并和远端服务器建立一个TCP连接,其函数原型为:
 

  int connect(int sockfd, struct sockaddr *serv_addr,int addrlen);


Sockfd 
socket 函数返回的 socket 描述符; serv_addr 是包含远端主机 IP 地址和端口号的指针; addrlen 是远端地质结构的长度。  Connect 函数在出现错误时返回 -1 ,并且配置 errno 为相应的错误码。进行客户端程式设计无须调用 bind() ,因为这种情况下只需知道目的机器的 IP 地址,而客户通过哪个端口和服务器建立连接并无需关心, socket 执行体为您的程式自动选择一个未被占用的端口,并通知您的程式数据什么时候到打断口。
    Connect 函数启动和远端主机的直接连接。只有面向连接的客户程式使用 socket 时才需要将此 socket 和远端主机相连。无连接协议从不建立直接连接。面向连接的服务器也从不启动一个连接,他只是被动的在协议端口监听客户的请求。
    Listen 函数使 socket 处于被动的监听模式,并为该 socket 建立一个输入数据队列,将到达的服务请求保存在此队列中,直到程式处理他们。
  
 int listen(int sockfd, int backlog);


Sockfd 
Socket 系统调用返回的 socket  描述符; backlog 指定在请求队列中允许的最大请求数,进入的连接请求将在队列中等待 accept() 他们(参考下文)。 Backlog 对队列中等待服务的请求的数目进行了限制,大多数系统缺省值为 20 。假如一个服务请求到来时,输入队列已满,该 socket 将拒绝连接请求,客户将收到一个出错信息。
当出现错误时 listen 函数返回 -1 ,并置相应的 errno 错误码。
    accept() 函数让服务器接收客户的连接请求。在建立好输入队列后,服务器就调用 accept 函数,然后睡眠并等待客户的连接请求。
    
int accept(int sockfd, void *addr, int *addrlen);


sockfd 是被监听的 socket 描述符, addr 通常是个指向 sockaddr_in 变量的指针,该变量用来存放提出连接请求服务的主机的信息(某台主机从某个端口发出该请求); addrten 通常为一个指向值为 sizeof(struct sockaddr_in) 的整型指针变量。出现错误时 accept 函数返回 -1 并置相应的 errno 值。
  首先,当 accept 函数监控的  socket 收到连接请求时, socket 执行体将建立一个新的 socket ,执行体将这个新 socket 和请求连接进程的地址联系起来,收到服务请求的初始 socket 仍能够继续在以前的  socket 上监听,同时能够在新的 socket 描述符上进行数据传输操作。


数据传输


Send()recv()这两个函数用于面向连接的socket上进行数据传输。
   Send()函数原型为:
  

 int send(int sockfd, const void *msg, int len, int flags);


Sockfd
是您想用来传输数据的 socket 描述符; msg 是个指向要发送数据的指针; Len 是以字节为单位的数据的长度; flags 一般情况下置为 0 (关于该参数的用法可参照 man 手册)。
    Send() 函数返回实际上发送出的字节数,可能会少于您希望发送的数据。在程式中应该将 send() 的返回值和欲发送的字节数进行比较。当 send() 返回值和 len 不匹配时,应该对这种情况进行处理。
char *msg = "Hello!";
int len, bytes_sent;
……
len = strlen(msg);
bytes_sent = send(sockfd, msg,len,0);
……


    recv() 函数原型为:
    
int recv(int sockfd,void *buf,int len,unsigned int flags);


    Sockfd 是接受数据的 socket 描述符; buf  是存放接收数据的缓冲区; len 是缓冲的长度。 Flags 也被置为 0 Recv() 返回实际上接收的字节数,当出现错误时,返回 -1 并置相应的 errno 值。
Sendto()
recvfrom() 用于在无连接的数据报 socket 方式下进行数据传输。由于本地 socket 并没有和远端机器建立连接,所以在发送数据时应指明目的地址。
sendto()
函数原型为:
    
int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen);


  该函数比 send() 函数多了两个参数, to 表示目地机的 IP 地址和端口号信息,而 tolen 常常被赋值为 sizeof (struct sockaddr) Sendto  函数也返回实际发送的数据字节长度或在出现发送错误时返回 -1
    Recvfrom() 函数原型为:
    
int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);


from 是个 struct sockaddr 类型的变量,该变量保存源机的 IP 地址及端口号。 fromlen 常置为 sizeof (struct sockaddr) 。当 recvfrom() 返回时, fromlen 包含实际存入 from 中的数据字节数。 Recvfrom() 函数返回接收到的字节数或当出现错误时返回 -1 ,并置相应的 errno
假如您对数据报 socket 调用了 connect() 函数时,您也能够利用 send() recv() 进行数据传输,但该 socket 仍然是数据报 socket ,并且利用传输层的 UDP 服务。但在发送或接收数据报时,内核会自动为之加上目地和源地址信息。


传输结束


当任何的数据操作结束以后,您能够调用close()函数来释放该socket,从而停止在该socket上的任何数据操作:
close(sockfd);
  您也能够调用shutdown()函数来关闭该socket。该函数允许您只停止在某个方向上的数据传输,而一个方向上的数据传输继续进行。如您能够关闭某socket的写操作而允许继续在该socket上接受数据,直至读入任何数据。
  

 int shutdown(int sockfd,int how);


    Sockfd 是需要关闭的 socket 的描述符。参数  how 允许为 shutdown 操作选择以下几种方式:
    ·0------- 不允许继续接收数据
    ·1------- 不允许继续发送数据
    ·2------- 不允许继续发送和接收数据,
    · 均为允许则调用 close ()
    shutdown 在操作成功时返回 0 ,在出现错误时返回 -1 并置相应 errno

其他函数


1、 网络字节顺序及其转换函数
1) 网络字节顺序
每一台机器内部对变量的字节存储顺序不同,而网络传输的数据是一定要统一顺序的。所以对内部字节表示顺序与网络字节顺序不同的机器,
一定要对数据进行转换,从程序的可移植性要求来讲,就算本机的内部字节表示顺序与网络字节顺序相同也应该在传输数据以前先调用数据转换函数,
以便程序移植到其它机器上后能正确执行。真正转换还是不转换是由系统函数自己来决定的。
2) 有关的转换函数
* unsigned short int htons(unsigned short int hostshort):
主机字节顺序转换成网络字节顺序,对无符号短型进行操作4bytes
* unsigned long int htonl(unsigned long int hostlong):
主机字节顺序转换成网络字节顺序,对无符号长型进行操作8bytes
* unsigned short int ntohs(unsigned short int netshort):
网络字节顺序转换成主机字节顺序,对无符号短型进行操作4bytes
* unsigned long int ntohl(unsigned long int netlong):
网络字节顺序转换成主机字节顺序,对无符号长型进行操作8bytes
注:以上函数原型定义在netinet/in.h里
2、IP地址转换
有三个函数将数字点形式表示的字符串IP地址与32位网络字节顺序的二进制形式的IP地址进行转换
(1) unsigned long int inet_addr(const char * cp):该函数把一个用数字和点表示的IP地址的字符串转换成一个无符号长整型,如:struct sockaddr_in ina
ina.sin_addr.s_addr=inet_addr("202.206.17.101")
该函数成功时:返回转换结果;失败时返回常量INADDR_NONE,该常量=-1,二进制的无符号整数-1相当于255.255.255.255,这是一个广播地址,所以在程序中调用iner_addr()时,一定要人为地对调用失败进行处理。由于该函数不能处理广播地址,所以在程序中应该使用函数inet_aton()。
(2)int inet_aton(const char * cp,struct in_addr * inp):此函数将字符串形式的IP地址转换成二进制形式的IP地址;成功时返回1,否则返回0,转换后的IP地址存储在参数inp中。
(3) char * inet_ntoa(struct in-addr in):将32位二进制形式的IP地址转换为数字点形式的IP地址,结果在函数返回值中返回,返回的是一个指向字符串的指针。
3、字节处理函数
Socket地址是多字节数据,不是以空字符结尾的,这和C语言中的字符串是不同的。Linux提供了两组函数来处理多字节数据,一组以b(byte)开头,是和BSD系统兼容的函数,另一组以mem(内存)开头,是ANSI C提供的函数。





例子:

ndk:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<jni.h>
#include <sys/types.h> /* for open */
#include <sys/stat.h> /* for open */
#include <fcntl.h>     /* for open */
#include<signal.h>
#include <sys/mman.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>

#include "JNIHelp.h"
#include<android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "native-activity", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "native-activity", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "native-activity", __VA_ARGS__))
#ifndef NELEM
# define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
#endif

static char CLASS_NAME[] = "com/sailor/Socket";
static char CB_METHOD[] = "callBack";
static char CB[] = "result";
static jstring getHostByName(JNIEnv *env, jobject clazz, jstring name)
{
	const char *pName = (*env)->GetStringUTFChars(env,name, NULL);
	
	struct hostent *host;
	struct in_addr h_addr;
	
	if((host = gethostbyname(pName)) == NULL)
	{
		LOGE("gethostbyname FAILED");
		return NULL;
	}
	
	h_addr.s_addr= *((unsigned long *)host->h_addr_list[0]);
	
	(*env)->ReleaseStringUTFChars(env, name, pName);

	return (*env)->NewStringUTF(env, inet_ntoa(h_addr));
}

static jboolean TCPServer(JNIEnv *env, jobject clazz, jint port)
{
	jboolean bRet = JNI_FALSE;
	
	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htons(INADDR_ANY);
	server_addr.sin_port = htons(port);

	int server_socket = socket(PF_INET, SOCK_STREAM, 0);	
	if(server_socket < 0)
	{
		LOGE("SERVER SOCKET FAILED");
	}
	else
	{
		int opt = 1;
		setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
		
		if(bind(server_socket, (struct sockaddr*)&server_addr,sizeof(server_addr)))
		{
			LOGE("SERVER SOCKET bind FAILED");
		}
		else
		{
			if(listen(server_socket, SOMAXCONN))
			{
				LOGE("SERVER SOCKET listen FAILED");
			}
			else
			{
				while(1)
				{
					bRet = JNI_FALSE;
					struct sockaddr_in client_addr;
					int length = sizeof(client_addr);
					int new_socket = accept(server_socket, (struct sockaddr *)&client_addr, &length);
					if(new_socket < 0)
					{
						LOGE("SERVER SOCKET accept FAILED");
						continue;
					}
					
					char buffer[1024];
					memset(buffer, 0, sizeof(buffer));
					length = recv(new_socket, buffer, sizeof(buffer), 0);
					//callback
					jbyteArray array = (*env)->NewByteArray(env, sizeof(buffer));
			(*env)->SetByteArrayRegion(env, array, 0, sizeof(buffer), (char *)buffer);

					jclass jhandlerClass = (*env)->GetObjectClass(env, clazz);  
    jmethodID doActionMethodId = (*env)->GetMethodID(env, jhandlerClass, CB_METHOD, "([B)V");  
    (*env)->CallVoidMethod(env, clazz, doActionMethodId, array);  
					(*env)->ReleaseByteArrayElements(env, array, buffer, 0);
					if(send(new_socket,"finish", strlen("finish"), 0) < 0)
					{
						LOGE("send failed");
					}
					close(new_socket);
					bRet = JNI_TRUE;
					
				}
			}
		}
	}
	
	close(server_socket);

	return bRet;
}

static jboolean UDPServer(JNIEnv *env, jobject clazz, jint port)
{
	jboolean bRet = JNI_FALSE;
	int sockfd;
	struct sockaddr_in servaddr;
	
	sockfd = socket(PF_INET,SOCK_DGRAM, 0);

	memset(&servaddr, 0, sizeof(servaddr));

	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(port);

	bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

	int n;
	char recvline[1024];
	while(1)
	{
		
		struct sockaddr_in client_addr;
		int fromelen = sizeof(client_addr);
		int ret = -1;
		memset(recvline,0, sizeof(recvline));
		ret = recvfrom(sockfd,recvline, sizeof(recvline), 0, (struct sockaddr *)&client_addr, &fromelen);
		
		if(ret != -1)
		{
			LOGE("recv:%s", recvline);

			//callback
					jbyteArray array = (*env)->NewByteArray(env, sizeof(recvline));
			(*env)->SetByteArrayRegion(env, array, 0, sizeof(recvline), (char *)recvline);

					jclass jhandlerClass = (*env)->GetObjectClass(env, clazz);  
    jmethodID doActionMethodId = (*env)->GetMethodID(env, jhandlerClass, CB_METHOD, "([B)V");  
    (*env)->CallVoidMethod(env, clazz, doActionMethodId, array);  
					(*env)->ReleaseByteArrayElements(env, array, recvline, 0);

			ret = sendto(sockfd, "finish", strlen("finish")+1,
			0, (struct sockaddr *)&client_addr, sizeof(client_addr));
			if(ret == -1)
			{
				LOGE("send to failed");
			}
		}
		else
		{
			LOGE("receive to failed");
		}
	}
	close(sockfd);
	return bRet;
}

static jboolean TCPClient(JNIEnv *env, jobject clazz, jint port, jstring message)
{
	jboolean bRet = JNI_FALSE;

	struct sockaddr_in client_addr;
	memset(&client_addr, 0, sizeof(client_addr));
	client_addr.sin_family = AF_INET;
	client_addr.sin_addr.s_addr = htons(INADDR_ANY);
	client_addr.sin_port = htons(0);

	int client_socket = socket(AF_INET, SOCK_STREAM, 0);
	if(client_socket < 0)
	{
		LOGE("SOCKET FAILED");
	}
	else
	{
		if(bind(client_socket, (struct sockaddr *)&client_addr, sizeof(client_addr)))
		{
			LOGE("SOCKET bind FAILED");
		}
		else
		{
			struct sockaddr_in server_addr;
			struct sockaddr_in temp_addr;
			memset(&server_addr, 0, sizeof(server_addr));
			memset(&temp_addr, 0, sizeof(temp_addr));
			server_addr.sin_family = AF_INET;
			int namelen = sizeof(temp_addr);
			getsockname(client_socket, (struct sockaddr *)&temp_addr, &namelen); 
			server_addr.sin_addr =  temp_addr.sin_addr;
			LOGE("server ip:%s", inet_ntoa(server_addr.sin_addr));
			server_addr.sin_port = htons(port);
			int serverlen = sizeof(server_addr);
			if(connect(client_socket, (struct sockaddr *)&server_addr, serverlen) < 0)
			{
				LOGE("connect failed");
			}
			const char *pName = (*env)->GetStringUTFChars(env,message, NULL);
			send(client_socket,pName,strlen(pName),0);
			(*env)->ReleaseStringUTFChars(env, message, pName);
			char buffer[1024];
			memset(buffer, 0, sizeof(buffer));
			int length = recv(client_socket,buffer,sizeof(buffer),0);
			//callback
					jbyteArray array = (*env)->NewByteArray(env, sizeof(buffer));
			(*env)->SetByteArrayRegion(env, array, 0, sizeof(buffer), (char *)buffer);

					jclass jhandlerClass = (*env)->GetObjectClass(env, clazz);  
    jmethodID doActionMethodId = (*env)->GetMethodID(env, jhandlerClass, CB, "([B)V");  
    (*env)->CallVoidMethod(env, clazz, doActionMethodId, array);  
					(*env)->ReleaseByteArrayElements(env, array, buffer, 0);
			bRet = JNI_TRUE;
			
		}
	}
	return bRet;
}

static jboolean UDPClient(JNIEnv *env, jobject clazz, jint port, jstring message)
{
	jboolean bRet = JNI_FALSE;
	int sockfd;
	struct sockaddr_in servaddr;

	struct sockaddr_in client_addr;
	int fromelen = sizeof(client_addr);
	int ret = -1;
	char recvline[1024];
	sockfd = socket(PF_INET, SOCK_DGRAM, 0);

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(port);
	servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	
	const char *pName = (*env)->GetStringUTFChars(env,message, NULL);
	sendto(sockfd, pName, strlen(pName), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
	(*env)->ReleaseStringUTFChars(env, message, pName);
	
	
	memset(recvline,0, sizeof(recvline));
	ret = recvfrom(sockfd,recvline, sizeof(recvline), 0, (struct sockaddr *)&client_addr, &fromelen);
	
	jbyteArray array = (*env)->NewByteArray(env, sizeof(recvline));
			(*env)->SetByteArrayRegion(env, array, 0, sizeof(recvline), (char *)recvline);

					jclass jhandlerClass = (*env)->GetObjectClass(env, clazz);  
    jmethodID doActionMethodId = (*env)->GetMethodID(env, jhandlerClass, CB, "([B)V");  
    (*env)->CallVoidMethod(env, clazz, doActionMethodId, array);  
					(*env)->ReleaseByteArrayElements(env, array, recvline, 0);

	close(sockfd);
	return bRet;
}

static JNINativeMethod mehods[] = {
	
		{ "gethostbyname", "(Ljava/lang/String;)Ljava/lang/String;", 
			(void *) getHostByName },
		{ "TCPServer", "(I)Z", 
			(void *) TCPServer },
		{ "UDPServer", "(I)Z", 
			(void *) UDPServer },
		{ "TCPClient", "(ILjava/lang/String;)Z", 
			(void *) TCPClient },
		{ "UDPClient", "(ILjava/lang/String;)Z", 
			(void *) UDPClient }
		
};


static int registerNativeMethods(JNIEnv *env, const char* className,
                                 const JNINativeMethod* methods, int numMethods)
{
    int rc;
    jclass clazz;
    clazz = (*env)->FindClass(env, className);
    if (clazz == NULL) {
        LOGE("Native registration unable to find class '%s'\n", className);
        return -1;
    }
    if (rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods)) < 0) {
        LOGE("RegisterNatives failed for '%s' %d\n", className, rc);
        return -1;
    }
    return 0;
}


static int register_jni(JNIEnv *env)
{
	return registerNativeMethods(env, CLASS_NAME, mehods, NELEM(mehods));
}

JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
{
     JNIEnv* env = NULL;
     jint result = -1;    
 
     //获取JNI版本
     if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_4) != JNI_OK) 
     {
         LOGE("GetEnv failed!");
             return result;
     }
	
     InitHelp(env, NULL);
     if (register_jni(env) < 0) 
	{
	LOGE("register method failed!");
             return result;
     }
     return JNI_VERSION_1_4;
}

java类:

package com.sailor;

import android.util.Log;

public class Socket {
	static {
		// 加载动态库
		System.loadLibrary("JNISocket");
	}
	
	public native String gethostbyname(String name);
	public native boolean TCPServer(int port);
	public native boolean TCPClient(int port, String message);
	public native boolean UDPServer(int port);
	public native boolean UDPClient(int port, String message);
	public void result(byte[] buffer){
		Log.d("jacklam", "send result:" + new String(buffer));
	}
	
	public void callBack(byte[] buffer){
		Log.d("jacklam", "receive result:" + new String(buffer));
	}
}

调用:

public void getHostByName(View view) {
		Socket socket = new Socket();
		Log.d("jacklam", "ip:" + socket.gethostbyname("www.baidu.com"));
	}

	public void tcpserver(View view) {
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				Socket socket = new Socket();
				socket.TCPServer(10000);
			}
		});

		thread.start();

	}

	public void tcpclient(View view) {

		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				Socket socket = new Socket();
				socket.TCPClient(10000, "test tcp socket");
			}
		});

		thread.start();
		
	}
	
	
	public void udpserver(View view) {
		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				Socket socket = new Socket();
				socket.UDPServer(10001);
			}
		});

		thread.start();

	}

	public void udpclient(View view) {

		Thread thread = new Thread(new Runnable() {

			@Override
			public void run() {
				Socket socket = new Socket();
				socket.UDPClient(10001, "test udp socket");
			}
		});

		thread.start();
		
	}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值