NDK 4 使用Socket与服务器通信

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);
}
简单的一个JNI,内容实现是通过socket连接到服务器,获取到数据,并且设置到DataHolder类中.


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开发,上面的程序非常简单。有很多地方还是需要改善的。











评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值