libcurl主要功能就是用不同的协议连接和沟通不同的服务器~也就是相当封装了的sockPHP 支持libcurl(允许你用不同的协议连接和沟通不同的服务器)。, libcurl当前支持http, https, ftp, gopher, telnet, dict, file, 和ldap 协议。libcurl同样支持HTTPS证书授权,HTTP POST, HTTP PUT, FTP 上传(当然你也可以使用PHP的ftp扩展), HTTP基本表单上传,代理,cookies,以及用户认证。
PHP具备curl扩展,但是java却不具备curl功能。此文章介绍如何在linux系统下,通过jni封装curl,供java进行调用
在Ubuntu下面,首先安装libcurl库
sudo aptitude install libcurl4-openssl-dev
如果需要使用最新的libcurl库,那么就需要自行下载源码来编译安装了,为了简单,采用apt方式安装也没什么。
libcurl的API就不多做介绍了,初始化以及清理curl都是通过native来进行调用的,因此要进行一个封装
public Curl() {
if (!INIT) {
curlGlobalInit(CurlConstant.CURL_GLOBAL_DEFAULT);
}
}
public static void curlGlobalInit(int flags) {
if (INIT) {
return;
}
CurlCode code = CurlCode.fromValue(curlGlobalInitNative(flags));
if (code != CurlCode.CURLE_OK) {
throw new IllegalStateException("curlGlobalInit fail: " + code);
}
INIT = true;
}
private native static int curlGlobalInitNative(int flags);
private native static void curlGlobalCleanupNative();
public void curlEasyInit() throws CurlException {
// Log.v(TAG, "curlEastInit");
handle = curlEasyInitNative();
if (handle == 0) {
throw new CurlException("curl init native fail");
}
}
private native long curlEasyInitNative();
public void curlEasyCleanup() {
// Log.v(TAG, "curlEastCleanup: " + handle);
if (handle != 0) {
curlEasyCleanupNative(handle);
}
handle = 0;
}
private native void curlEasyCleanupNative(long handle);
/**
*
* @param opt
* {@link OptLong}
* @param value
* @return
*/
public CurlCode curlEasySetopt(OptLong opt, long value) {
// Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
return CurlCode.fromValue(curlEasySetoptLongNative(handle,
opt.getValue(), value));
}
private native int curlEasySetoptLongNative(long handle, int opt, long value);
public CurlCode curlEasySetopt(OptFunctionPoint opt, WriteCallback callback) {
// Log.v(TAG, "curlEastSetopt: " + opt + "=" + callback);
return CurlCode.fromValue(curlEasySetoptFunctionNative(handle,
opt.getValue(), callback));
}
private native int curlEasySetoptFunctionNative(long handle, int opt,
Callback callback);
public CurlCode curlEasySetopt(OptObjectPoint opt, String value) {
// Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
return CurlCode.fromValue(curlEasySetoptObjectPointNative(handle,
opt.getValue(), value));
}
private native int curlEasySetoptObjectPointNative(long handle, int opt,
String value);
public CurlCode curlEasySetopt(OptObjectPoint opt, byte[] value) {
// Log.v(TAG, "curlEastSetopt: " + opt + "=" + value);
return CurlCode.fromValue(curlEasySetoptObjectPointBytesNative(handle,
opt.getValue(), value));
}
private native int curlEasySetoptObjectPointBytesNative(long handle,
int opt, byte[] value);
public CurlCode curlEasySetopt(OptObjectPoint opt, String[] values) {
// Log.v(TAG, "curlEastSetopt: " + opt + "=" + values);
return CurlCode.fromValue(curlEasySetoptObjectPointArrayNative(handle,
opt.getValue(), values));
}
private native int curlEasySetoptObjectPointArrayNative(long handle,
int opt, String[] value);
/**
*
* @param multiParts
* @return
*/
public CurlFormadd setFormdata(List multiParts) {
if (multiParts != null && multiParts.size() > 0) {
return CurlFormadd.fromValue(setFormdataNative(handle,
multiParts.toArray(new MultiPart[multiParts.size()])));
} else {
return CurlFormadd.CURL_FORMADD_NULL;
}
}
private native int setFormdataNative(long handle, MultiPart[] multiArray);
public CurlCode curlEasyPerform() {
return CurlCode.fromValue(curlEasyPerformNavite(handle));
}
private native int curlEasyPerformNavite(long handle);
进入到bin/class目录
使用如下命令生成头文件
javah -o curldroid.h com.netbirdtech.libcurl.Curl
生成头文件之后,需要在使用C++来实现Curl.java中的native方法:
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlGlobalInitNative
(JNIEnv * env, jclass cls, jint flag) {
curl_global_init((int) flag);
}
JNIEXPORT void JNICALL Java_com_netbirdtech_libcurl_Curl_curlGlobalCleanupNative
(JNIEnv * env, jclass cls) {
curl_global_cleanup();
}
JNIEXPORT jlong JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyInitNative
(JNIEnv * env, jobject obj) {
CURL* curl = curl_easy_init();
if (curl != 0) {
Holder* holder = new Holder(curl);
return (long) holder;
}
return 0;
}
JNIEXPORT void JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyCleanupNative
(JNIEnv * env, jobject obj, jlong handle) {
if (handle != 0) {
Holder* holder = (Holder*) handle;
curl_easy_cleanup(holder->getCurl());
delete holder;
holder = 0;
}
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptLongNative
(JNIEnv *env, jobject obj, jlong handle, jint opt, jlong value) {
Holder* holder = (Holder*) handle;
return (int) curl_easy_setopt(holder->getCurl(), (CURLoption) opt, (long) value);
}
JNIEXPORT int JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptFunctionNative
(JNIEnv * env, jobject obj, jlong handle, jint opt, jobject cb) {
Holder* holder = (Holder*) handle;
CURL * curl = holder->getCurl();
jobject cb_ref = 0;
switch (opt) {
case CURLOPT_HEADERFUNCTION:
//LOGV("setopt CURLOPT_HEADERFUNCTION");
curl_easy_setopt(curl, (CURLoption) opt, &write_callback);
cb_ref = env->NewGlobalRef(cb);
holder->addGlobalRefs(cb_ref);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, (void *)cb_ref);
break;
case CURLOPT_WRITEFUNCTION:
// see http://curl.haxx.se/libcurl/c/CURLOPT_WRITEFUNCTION.html
curl_easy_setopt(curl, (CURLoption) opt, &write_callback);
cb_ref = env->NewGlobalRef(cb);
holder->addGlobalRefs(cb_ref);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)cb_ref);
break;
case CURLOPT_READFUNCTION:
curl_easy_setopt(curl, (CURLoption) opt, &read_callback);
cb_ref = env->NewGlobalRef(cb);
holder->addGlobalRefs(cb_ref);
curl_easy_setopt(curl, CURLOPT_READDATA, (void *)cb_ref);
break;
default:
// no-op
;
}
return (int) CURLE_OK;
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointNative
(JNIEnv * env, jobject obj, jlong handle, jint opt, jstring value) {
const char *str;
int result;
Holder* holder = (Holder*) handle;
CURL * curl = holder->getCurl();
jstring value_ref;
str = env->GetStringUTFChars(value, 0);
if (str == 0) {
return 0;
}
result = (int) curl_easy_setopt(curl, (CURLoption) opt, str);
switch(opt) {
case CURLOPT_POSTFIELDS:
// this field not copy data
// see http://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html
value_ref = (jstring) env->NewGlobalRef(value);
holder->addStringGlobalRefs(value_ref, str);
break;
default:
// free
env->ReleaseStringUTFChars(value, str);
}
return result;
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointBytesNative
(JNIEnv * env, jobject obj, jlong handle, jint opt, jbyteArray bytes) {
int result;
Holder* holder = (Holder*) handle;
CURL * curl = holder->getCurl();
jbyte* str = env->GetByteArrayElements(bytes, JNI_FALSE);
int content_length = env->GetArrayLength(bytes);
if (str == NULL) {
return 0;
}
result = (int) curl_easy_setopt(curl, (CURLoption) opt, str);
switch(opt) {
case CURLOPT_POSTFIELDS:
// this field not copy data
// see http://curl.haxx.se/libcurl/c/CURLOPT_POSTFIELDS.html
// release after perform
holder->addByteArrayGlobalRefs(env->NewGlobalRef(bytes), (const char*)str);
break;
default:
// free
env->ReleaseByteArrayElements(bytes, str, 0);
}
return result;
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasySetoptObjectPointArrayNative
(JNIEnv *env, jobject obj, jlong handle, jint opt, jobjectArray values) {
Holder* holder = (Holder*) handle;
CURL * curl = holder->getCurl();
const char *str;
struct curl_slist *slist = 0;
int nargs = env->GetArrayLength(values);
for (int i = 0; i < nargs; i++) {
jstring value = (jstring) env->GetObjectArrayElement(values, i);
str = env->GetStringUTFChars(value, 0);
if (str == 0) {
return 0;
}
//LOGV("append slist");
slist = curl_slist_append(slist, str);
env->ReleaseStringUTFChars(value, str);
}
holder->addCurlSlist(slist);
//LOGD("set slist option=%d, size=%d", opt, nargs);
return curl_easy_setopt(curl, (CURLoption) opt, slist);
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_setFormdataNative
(JNIEnv* env, jobject obj, jlong handle, jobjectArray multi_array) {
Holder* holder = (Holder*) handle;
if (holder == NULL) {
return 0;
}
CURL* curl = holder->getCurl();
struct curl_httppost* post = holder->getPost();;
struct curl_httppost* last = NULL;
// clear all
if (post != NULL) {
//LOGD("clear previous form.");
curl_formfree(post);
post = NULL;
}
if (multi_array != NULL) {
CURLFORMcode code;
int len = env->GetArrayLength(multi_array);
//LOGD("set name/parts size=%d", len);
for (int i = 0; i < len; i++) {
//LOGV(".");
jobject part = env->GetObjectArrayElement(multi_array, i);
jstring name = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_name);
jstring filename = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_filename);
jstring content_type = (jstring) env->CallObjectMethod(part, MID_MultiPart_get_content_type);
jbyteArray content = (jbyteArray) env->CallObjectMethod(part, MID_MultiPart_get_content);
jbyte* bytes = env->GetByteArrayElements(content, 0);
int content_length = env->GetArrayLength(content);
holder->addByteArrayGlobalRefs(env->NewGlobalRef(content), (const char*)bytes); // release after perform
const char* name_str = env->GetStringUTFChars(name, 0);
// content_type and filename may be null
if (content_type == NULL && filename == NULL) {
code = curl_formadd(&post, &last,
CURLFORM_COPYNAME, name_str,
CURLFORM_BUFFER, "file.dat",
CURLFORM_BUFFERPTR, bytes,
CURLFORM_BUFFERLENGTH, content_length,
CURLFORM_END);
} else if (content_type == NULL) {
const char* filename_str = env->GetStringUTFChars(filename, 0);
code = curl_formadd(&post, &last,
CURLFORM_COPYNAME, name_str,
CURLFORM_BUFFER, filename_str,
CURLFORM_BUFFERPTR, bytes,
CURLFORM_BUFFERLENGTH, content_length,
CURLFORM_END);
env->ReleaseStringUTFChars(filename, filename_str);
} else if (filename == NULL) {
const char* content_type_str = env->GetStringUTFChars(content_type, 0);
code = curl_formadd(&post, &last,
CURLFORM_COPYNAME, name_str,
CURLFORM_BUFFER, "file.dat",
CURLFORM_CONTENTTYPE, content_type_str,
CURLFORM_BUFFERPTR, bytes,
CURLFORM_BUFFERLENGTH, content_length,
CURLFORM_END);
env->ReleaseStringUTFChars(content_type, content_type_str);
} else {
const char* filename_str = env->GetStringUTFChars(filename, 0);
const char* content_type_str = env->GetStringUTFChars(content_type, 0);
code = curl_formadd(&post, &last,
CURLFORM_COPYNAME, name_str,
CURLFORM_BUFFER, filename_str,
CURLFORM_CONTENTTYPE, content_type_str,
CURLFORM_BUFFERPTR, bytes,
CURLFORM_BUFFERLENGTH, content_length,
CURLFORM_END);
env->ReleaseStringUTFChars(filename, filename_str);
env->ReleaseStringUTFChars(content_type, content_type_str);
}
env->ReleaseStringUTFChars(name, name_str);
}
if (code != CURL_FORMADD_OK) {
////LOGW("curl_formadd error %d", code);
curl_formfree(post);
// TODO return fromadd error or setopt error?
return (int) code;
}
}
if (post != NULL) {
//LOGV("set_opt CURLOPT_HTTPPOST");
holder->setPost(post);
return curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
}
return 0;
}
JNIEXPORT jint JNICALL Java_com_netbirdtech_libcurl_Curl_curlEasyPerformNavite
(JNIEnv *env, jobject obj, jlong handle) {
Holder* holder = (Holder*) handle;
CURL * curl = holder->getCurl();
return (int) curl_easy_perform(curl);
}
这个基本上得认真看看libcurl的API了
代码写好之后,就是进行编译了
为了方便,写了一个Makefile文件
jni:
@echo "编译之前,请务必指定jni.h以及jni_md.h的实际运行目录"
g++ curldroid.cpp -I /usr/lib/jdk/include -I /usr/lib/jdk/include/linux -lcurl -fPIC -shared -o libcurl4java.so
install:
@echo "执行install(安装so文件)操作之前,请务必指定java.library.path目录,通过System.getProperty(\"java.library.path\")可以获取"
cp -f libcurl4java.so /usr/lib/libcurl4java.so
uninstall:
@echo "执行uninstall(卸载so文件)操作之前,请务必指定java.library.path目录,通过System.getProperty(\"java.library.path\")可以获取"
rm -f /usr/lib/libcurl4java.so
clean:
@echo "删除所有的链接文件以及所有的目标文件,可能需要root权限"
rm -f *.o
rm -f *.so
rm -f /usr/lib/ibcurldroid.so
在linux系统下面,安装jdk的时候,务必要记下jdk的安装地址,需要指定jni.h的头文件路径
否则会编译失败。
执行make就可以生成so文件
执行make install之前修改install这个target的路径
cp -f libcurl4java.so /usr/lib/libcurl4java.so
如何获取已经说明了。
通过如下代码可以简单的测试功能:
CurlResult result = CurlHttp.newInstance().addParam("ip", "202.108.67.57")
.getUrl("http://ip.taobao.com/service/getIpInfo.php").perform();
int status = result.getStatus();
String statusLine = result.getStatusLine();
String body = result.getBodyAsString();
byte[] binaryData = result.getBody();
String binaryStr = new String(binaryData, "UTF-8");
// byte[] binaryDecodedDate = result.getDecodedBody(); // if gzipped
String header = result.getHeader("ContentType"); // ignore header
Map headers = result.getHeaders();
System.out.println("status=" + status);
System.out.println("statusLine=" + statusLine);
System.out.println("body=" + body);
System.out.println("binaryStr=" + binaryStr);
System.out.println("header=" + header);
for(int i=0;i
在android平台下,正确的编译了libcurl,同样能够在android上运行。
代码有空再上传,睡觉去咯