其實這個標題沒什麼意思;但是想來想去,自己(新手)查了很多資料才調通,就打算在此一寫。
android-jni的socket編程,就是調用底層linux的socket編程。android平台,一般只需要關心用戶端代碼,如下:(從華清遠見嵌入式linux應用開發教材上copy的,手頭沒好點的例子)
/*client.c*/#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <netdb.h>#include <sys/types.h>#include <netinet/in.h>#include <sys/socket.h>#define SERVPORT 8591#define MAXDATASIZE 100main(int argc,char *argv[]){ int sockfd,sendbytes; char buf[MAXDATASIZE]; struct hostent *host; struct sockaddr_in serv_addr; if (argc < 2) { fprintf(stderr,"Please enter the server's hostname!\n"); exit(1); } /*位址解析函數*/ if ((host=gethostbyname(argv[1]))==NULL) { perror("gethostbyname"); exit(1); } printf("%s",host->h_name); /*建立socket*/ if ((sockfd=socket(AF_INET,SOCK_STREAM,0))== -1) { perror("socket"); exit(1); } /*設定sockaddr_in 結構體中相關參數*/ serv_addr.sin_family=AF_INET; serv_addr.sin_port=htons(SERVPORT); serv_addr.sin_addr=*((struct in_addr *)host->h_addr); bzero(&(serv_addr.sin_zero),8); /*調用connect函數主動發起對伺服器端的串連*/ if (connect(sockfd,(struct sockaddr *)&serv_addr,\ sizeof(struct sockaddr))== -1) { perror("connect"); exit(1); } /*發送訊息給伺服器端*/ if ((sendbytes=send(sockfd,"hello",5,0))== -1) { perror("send"); exit(1); } close(sockfd);}
然後可以參照android-ndk的sample把它改成jni方式調用。
接收訊息,可以採用如下方式:(參考APUE)
long ReceiveMessage(BYTE *buf,UINT bufSize,UINT *recvbufLen,UINT nTimeOut){LOGI("ReceiveMessage");long lRet = -1;int recvbytes;uint startTime = GetTickCount(),endTime;do{endTime = GetTickCount();if ((recvbytes=recv(sockfd, buf, bufSize, MSG_DONTWAIT)) == -1){lRet = -1;//LOGI("recv error");//LOGII(errno,"recv errno",__LINE__); // 11 : Resource temporarily unavailable}else{lRet = 0;break;}}while(lRet == -1 && endTime - startTime < nTimeOut);*recvbufLen = recvbytes;if(recvbytes > 0)LOGArr((unsigned char*)buf,recvbytes);return lRet;}
上例中用指標傳輸出參數而不是引用,是因為是在.c檔案中編譯jni,不支援c++特性。而jni-c++這一部分還沒完全搞清楚,等搞清楚了再寫一篇。
需要說明的最重要的一點是,工程目錄下的AndroidManifest.xml需要添加網路許可權支援才能調通:
<!-- 增加jni socket支援--><uses-permission android:name="android.permission.INTERNET" />