Android与ok6410板子tcp通信

开发环境:ubuntu10.10 32位

服务端:ok6410 烧入linux系统

客户端:android手机

在ok6410上编写tcp服务端程序是用c语言编写,android的应用程序是用java语言编写的,因此要想实现与linux c语言的通信则必须通过JNI来实现,在本次设计中,tcp客户端程序是用c语言写的,通过NDK编译生成库文件,在android的应用程序中调用c语言程序来实现与linux c的通信,目前本程序只是实现了简单的通信。

1.服务端程序

/* net_select.c */

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netinet/in.h>

#define PORT				1234
#define MAX_QUE_CONN_NM			5
#define MAX_SOCK_FD			FD_SETSIZE
#define BUFFER_SIZE			1024	//缓存区
struct user_info
{
	char userName[20];
	char userPasswd[20];
	char serverIP[20];
};
int main()
{
	struct sockaddr_in server_sockaddr, client_sockaddr;
	int sin_size, count;
	fd_set inset, tmp_inset;
	int sockfd, client_fd, fd;
	char buf[BUFFER_SIZE];
	char clientIP[20];
	struct user_info userInfo;
	
	if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	{
		perror("socket");
		exit(1);
	}//建立socket链接,流式socket,IPv4协议
	
	server_sockaddr.sin_family = AF_INET;
	server_sockaddr.sin_port = htons(PORT);
	server_sockaddr.sin_addr.s_addr = INADDR_ANY;//0.0.0.0不确定地址
	bzero(&(server_sockaddr.sin_zero), 8);//填充0以保持与struct sockaddr同样大小
	
	int i = 1;/* 允许重复使用本地地址与套接字进行绑定*/
	setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
	if (bind(sockfd, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr)) == -1)
	{
		perror("bind");
		exit(1);
	}
	printf("bind success!\n");
	if(listen(sockfd, MAX_QUE_CONN_NM) == -1)
	{
		perror("listen");
		exit(1);
	}
	printf("listening....\n");
	
	/*将调用socket()函数的描述符作为文件描述符*/
	FD_ZERO(&inset);	//清空inset文件描述集
	FD_SET(sockfd, &inset);	//将sockfd加入inset文件描述集
	
	while(1)
	{
		tmp_inset = inset;
		sin_size=sizeof(struct sockaddr_in);
		memset(buf, 0, sizeof(buf));	//初始化buf缓存区
		
		/*调用select()函数*/
		if (!(select(MAX_SOCK_FD, &tmp_inset, NULL, NULL, NULL) > 0))
		{
			perror("select");
			close(sockfd);
			exit(1);
		}
		
		for (fd = 0; fd < MAX_SOCK_FD; fd++)
		{
			if (FD_ISSET(fd, &tmp_inset) > 0) 
			{
				if (fd == sockfd)
				{ /* 服务端接收客户端的链接请求 */
					if ((client_fd = accept(sockfd, (struct sockaddr *)&client_sockaddr, &sin_size))== -1)
					{
						perror("accept");
						exit(1);
					}
					memset(clientIP, 0 ,sizeof(clientIP));
					inet_ntop(AF_INET, (void *)(&client_sockaddr.sin_addr), clientIP, sizeof(clientIP));
					FD_SET(client_fd, &inset);
					printf("New connection from %d(socket)\n", client_fd);
					printf("the client IP is :%s\n",clientIP);
				}
				else /* 处理从客户端发来的消息*/
				{
					if ((count = recv(fd, &userInfo, sizeof(struct user_info), 0)) > 0)
					{
						printf("Received a message from %d\n", fd);
						printf("%s,%s,%s\n",userInfo.serverIP, userInfo.userName, userInfo.userPasswd);		
						strcpy(buf, "success");			
						send(fd, buf, strlen(buf), 0);
					}
					else		
					{
						close(fd);
						FD_CLR(fd, &inset);
						printf("Client %d(socket) has left\n", fd);
					}						
				}		
			} /* end of if FD_ISSET*/ 
		} /* end of for fd*/
	} /* end if while while*/
	
	close(sockfd);
	exit(0);
}

在服务端中,是用select方式来实现多路复用的,即实现多个客户端连接服务端,程序中定义了user_info结构体用来存放从客户端传入的数据,这是因为以后要用到sqlite数据库,因此才定义的这个结构体,另外,在服务端中,我们通过客户端的socket连接来获取客户端的ip地址,也可以在客户端获取本地ip,将ip发送给服务端,服务端接收到数据后即发送“success”字符串给客户端。

客户端:

/*client.c*/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <jni.h>
#include <android/log.h>

#define PORT	1234
#define BUFFER_SIZE 20

typedef struct
{
	char userName[20];
	char userPasswd[20];
	char serverIP[20];
} user_info;

char* Jstring2CStr(JNIEnv*   env, jstring jstr)  
{  
     char*   rtn   =   NULL;  
     jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");  
     jstring   strencode   =   (*env)->NewStringUTF(env,"GB2312");  
     jmethodID   mid   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B");  
     jbyteArray   barr=   (jbyteArray)(*env)->CallObjectMethod(env,jstr,mid,strencode); // String .getByte("GB2312");  
     jsize   alen   =   (*env)->GetArrayLength(env,barr);  
     jbyte*   ba   =   (*env)->GetByteArrayElements(env,barr,JNI_FALSE);  
     if(alen   >   0)  
     {  
      rtn   =   (char*)malloc(alen+1);         //new   char[alen+1]; "\0"  
      memcpy(rtn,ba,alen);  
      rtn[alen]=0;  
     }  
     (*env)->ReleaseByteArrayElements(env,barr,ba,0);  //释放内存  
  
     return rtn;  
}  

jint 
Java_com_videoclient_forlinx_VideoMonitor_LoginFromJNI(JNIEnv *env, 
		jobject thiz, jstring serverIP, jstring userName, jstring userPasswd)
{
	int sockfd, sendbytes, recvbytes;
	char buf[BUFFER_SIZE];
	struct hostent *host;
	struct sockaddr_in serv_addr;
	user_info userInfo;
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "call success");
	memset(buf, 0, sizeof(buf));
	strcpy(userInfo.serverIP, Jstring2CStr(env, serverIP));
	strcpy(userInfo.userName, Jstring2CStr(env, userName));
	strcpy(userInfo.userPasswd, Jstring2CStr(env, userPasswd));
	__android_log_print(ANDROID_LOG_INFO, "Project Name", userInfo.serverIP);
	__android_log_print(ANDROID_LOG_INFO, "Project Name", userInfo.userName);
	__android_log_print(ANDROID_LOG_INFO, "Project Name", userInfo.userPasswd);
	__android_log_print(ANDROID_LOG_INFO, "Project Name", userInfo.userIP);
	//创建socket
	if ((sockfd = socket(AF_INET,SOCK_STREAM,0)) == -1)
	{
		perror("socket");
		exit(1);
	}
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "create socket success");
	//设置socketaddr_in结构体中相关参数
	serv_addr.sin_family = AF_INET;
	serv_addr.sin_port = htons(PORT);
	serv_addr.sin_addr.s_addr = inet_addr(userInfo.serverIP);
	bzero(&(serv_addr.sin_zero), 8);
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "set serv_addr param");
	
	//调用connect函数主动发起对服务器端的连接
	if(connect(sockfd,(struct sockaddr *)&serv_addr, sizeof(struct sockaddr))== -1)
	{
		perror("connect");
		exit(1);
	}
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "connect success");
	//发送消息给服务端
	if ((sendbytes = send(sockfd, &userInfo, sizeof(user_info), 0)) == -1)
	{
		perror("send");
		exit(1);
	}
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "send success");
	memset(buf, 0, sizeof(buf));
	if(recvbytes = recv(sockfd, buf, BUFFER_SIZE, 0) < 0)
	{
		perror("recv");
		exit(1);
	}
	__android_log_print(ANDROID_LOG_INFO, "Project Name", "recv success");
	printf("Recvived a result:%s\n", buf);
	sleep(3);
	close(sockfd);
	if(strncmp(buf, "success",7) == 0)
	{
		return 1;
	}
	else
	{
		return 0;
	}
	return 0;
}

在客户端中,同样定义了user_info结构体,在LoginFromJNI函数中用到了前面提到的java与c之间的数据传递,这里传递的是string类型的数据,用到Jstring2CStr这个函数将java中的string数据转成c语言中的string数据,直接使用的话,数据是乱码,suer_info中的数据是从java的应用程序中传递过来的。

3. android 应用程序端

static 
	{
		try
		{
			System.loadLibrary("client");
		}
		catch(UnsatisfiedLinkError ulink)
		{
			Log.i("client", "can not be loaded");
			ulink.printStackTrace();
		}
	}

加载生成的库。

public native int LoginFromJNI(String serverIP, String userName, String userPasswd, String userIP);
public int Login()
{
	return this.LoginFromJNI(this.serverIP, this.userName, this.userPasswd, this.userIP);
}

声明函数,调用该函数。最后为应用程序添加访问internet权限,至此,即可实现android与ok6410通信。

你可能感兴趣的:(Android与ok6410板子tcp通信)