http://blog.csdn.net/birdsaction/article/details/17095459
Android是基于Linux内核的,NDK提供的头文件基本都是 posix 协议的。
如果熟悉Linux环境下的开发,其实做NDK会非常容易。
下面主要演示 通过JNI Socket获取服务器响应数据 并显示在UI上面。LINUX下的C 之前接触过,不过长时间不用 又生疏了。
开发工具这次使用的是:IntelliJ Community IDE
比eclipse稍微智能些。大家可以用一下。TCP服务器用的是apache mina。
首先创建项目,编写基本类.
- package com.birds.android.ndk.socket;
- /**
- * Created with IntelliJ IDEA.
- * To change this template use File | Settings | File Templates.
- */
- public class SocketJNI {
- public native static void doConnect(String ip, int port);
- }
- public class DataHolder {
- public DataHolder(){
- }
- public void putData(String json) { //Native 回调,显示数据给TextView
- MainActivity.act.updateStatus(json);
- }
- }
- public class MainActivity extends Activity implements View.OnClickListener {
- private TextView status;
- private volatile boolean isCon;
- public static MainActivity act;
- static {
- System.loadLibrary("network-jni");
- }
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- findViewById(R.id.connect).setOnClickListener(this);
- status = (TextView) findViewById(R.id.status);
- act = this;
- }
- @Override
- public void onClick(View view) {
- if (!isCon) {
- isCon = true;
- status.setText("start connect..");
- t.start();
- }
- }
- Thread t = new Thread() {
- @Override
- public void run() {
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- connect();
- }
- };
- private void connect() {
- int port = 9001;
- String ip = "172.28.151.110";
- SocketJNI.doConnect(ip, port);
- }
- public void updateStatus(final String text) {
- Log.d("updateStatus", "get network data.....");
- isCon = false;
- runOnUiThread(new Runnable() {
- @Override
- public void run() {
- status.setText(text);
- }
- });
- }
- }
下面是主要的C实现的socket客户端代码,之前要生成好头文件,用javah 命令
首先编写一个socket独立的程序文件
- common.h
- void release();
- const char* connectRemote(const char*,const int);
- common.c
- #include "common.h"
- #include <string.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <android/log.h>
- #define LOG_TAG "birds_socket2"
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- #define MAXSIZE 4096
- struct sockaddr_in sock_add;
- struct sockaddr_in server_addr;
- int sockfd = 0;
- void release(){
- close(sockfd);
- }
- const char* connectRemote(const char* addr,const int port) {
- sockfd = socket(AF_INET, SOCK_STREAM, 0); //ipv4,TCP数据连接
- LOGI("step1");
- if (sockfd < 0) {
- return "socket error";
- }
- //remote server address
- bzero(&server_addr,sizeof(server_addr));
- server_addr.sin_family = AF_INET;
- server_addr.sin_port = htons(port);
- LOGI("step2");
- if( inet_pton(AF_INET, addr, &server_addr.sin_addr) < 0){ //set ip address
- return "address error";
- }
- socklen_t server_addr_length = sizeof(server_addr);
- int connfd = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); //连接到服务器
- LOGI("step3");
- if (connfd < 0) {
- return "connect error";
- }
- // send data
- char *msg = "i send a data to server. \n";
- int sdf = send(sockfd, msg , strlen(msg), 0); //发送一行数据到服务器
- LOGI("step4.");
- char buff[4096];
- int n = recv(sockfd, buff, MAXSIZE ,0); //这地方应该需要循环获取数据,目前服务器只响应了一条很短的字符串。
- buff[n] = 0;
- LOGI("step5.");
- return buff;
- }
下面是主JNI程序
- 这里不贴出生成的头文件了,直接C源码
- #include "conn_socket.h"
- #include "common.h"
- #include <android/log.h>
- #define LOG_TAG "birds_socket"
- #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
- const char* getSocketData(jstring addr,jint port) { //没写,这地方占时无用
- return 0;
- }
- JNIEXPORT void JNICALL Java_com_birds_android_ndk_socket_SocketJNI_doConnect
- (JNIEnv *env, jclass jcz, jstring addr, jint port) {
- jclass jclz = (*env)->FindClass(env,"com/birds/android/ndk/socket/DataHolder");
- if (jclz) {
- jmethodID ins = (*env)->GetMethodID(env,jclz,"<init>","()V");
- jobject holdObj = (*env)->NewObject(env,jclz,ins);
- jmethodID method1 = (*env)->GetMethodID(env,jclz,"putData","(Ljava/lang/String;)V");
- jstring msg = (*env)->NewStringUTF(env,"has entering."); //只是个提示而已
- (*env)->CallVoidMethod(env, holdObj,method1,msg);
- LOGI("connect socket.");
- const char* response = connectRemote("172.28.151.110",9001); //,直接hardcode,这地方没有转比较简单。
- release();
- LOGI("connect socket end.");
- msg = (*env)->NewStringUTF(env,response);
- (*env)->CallVoidMethod(env, holdObj,method1,msg);//数据回调给DataHolder方法中
- }
- }
android.mk
- LOCAL_PATH := $(call my-dir)
- include $(CLEAR_VARS)
- LOCAL_MODULE := network-jni
- LOCAL_SRC_FILES := conn_socket.c \
- common.c
- LOCAL_LDLIBS += -llog
- include $(BUILD_SHARED_LIBRARY)
如果熟悉Linux开发,上面的程序非常简单。有很多地方还是需要改善的。