开发环境: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通信。

更多相关文章

  1. C语言函数的递归(上)
  2. Android(安卓)OkHttp的Cookie自动化管理
  3. Android(安卓)IPC机制(二)——利用Messenger实现跨进程通信
  4. Android判断手机中的应用是否具有某些权限(例如小米手机中是否具
  5. android activity 生命周期详解
  6. 通过JNI实现c/c++和Android的java层函数互调
  7. Android(安卓)6.0 HTTPS SSL 无法访问,提示Handshake failed(握手
  8. Android几个面试题解答
  9. Android中跨进程通信的IPC机制(Binder框架)

随机推荐

  1. android 原生系统服务定位实现
  2. 动态壁纸开发指南(一)概述介绍
  3. Android startActivity源码详解
  4. Android高手进阶教程(二)之----Android L
  5. Myeclipse 安装时候android adt, android
  6. Mediapipe框架在Android上的使用
  7. Mac上非常好用的免费的Android文件传输工
  8. android:ToolBar详解
  9. Android面试必备——AsyncTask源码解析
  10. Android(安卓)SDK Samples,学习Android的