Android与ok6410板子tcp通信
16lz
2021-01-24
开发环境: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 PORT1234#define MAX_QUE_CONN_NM5#define MAX_SOCK_FDFD_SETSIZE#define BUFFER_SIZE1024//缓存区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 PORT1234#define BUFFER_SIZE 20typedef 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);//创建socketif ((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通信。
更多相关文章
- C语言函数的递归(上)
- Android(安卓)OkHttp的Cookie自动化管理
- Android(安卓)IPC机制(二)——利用Messenger实现跨进程通信
- Android判断手机中的应用是否具有某些权限(例如小米手机中是否具
- android activity 生命周期详解
- 通过JNI实现c/c++和Android的java层函数互调
- Android(安卓)6.0 HTTPS SSL 无法访问,提示Handshake failed(握手
- Android几个面试题解答
- Android中跨进程通信的IPC机制(Binder框架)