开发环境: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); }
客户端:
/*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; }
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); }