2011-11-15 58 views
1

我有一個C函數,我想通過SWIG使用Java調用,但我不確定如何處理sockaddr_in C結構。任何人都有關於如何處理sockaddr_in的例子?如何使用SWIG將sockaddr_in C結構映射到Java

+0

你想讓它與現有的'java.net.InetAddress'類兼容,或者只是用一個可用的接口包裝'sockaddr_in'? – Flexo

+0

我想用一個可用的界面來包裝它... – c12

回答

2

實際上,有在包裝上swig.orgsockaddr_in的一篇文章,雖然它現在看起來略顯陳舊。

基本上他們所做的就是編寫一個函數,爲您創建一個新的sockaddr_in,爲需要填充的值提供參數,這些值很容易在Java中傳遞。這是一個稍微更新,修剪鏈接的文章的版本:

%module sock   // Name of our module 
%{ 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <arpa/inet.h> 
#include <netdb.h> 

/* Set some values in the sockaddr_in structure */ 
struct sockaddr *new_sockaddr_in(short family, unsigned long hostid, int port) { 
     struct sockaddr_in *addr; 
     addr = (struct sockaddr_in *) malloc(sizeof(struct sockaddr_in)); 
     bzero((char *) addr, sizeof(struct sockaddr_in)); 
     addr->sin_family = family; 
     addr->sin_addr.s_addr = hostid; 
     addr->sin_port = htons(port); 
     return (struct sockaddr *) addr; 
} 
%} 

// Add these constants 
enum {AF_UNIX, AF_INET, SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, 
     IPPROTO_UDP, IPPROTO_TCP, INADDR_ANY}; 

#define SIZEOF_SOCKADDR sizeof(struct sockaddr) 

// Wrap these functions 
struct sockaddr *new_sockaddr_in(short family, unsigned long, int port); 

有雖與SWIG包裝這一個更好的方式,我們可以寫一個類型映射使用java.net.InetSocketAddress代替,這將感覺更爲「自然」上的接口的Java方面:

%typemap(jni) sockaddr_in *ADDR "jobject" 
%typemap(jtype) sockaddr_in *ADDR "java.net.InetSocketAddress" 
%typemap(jstype) sockaddr_in *ADDR "java.net.InetSocketAddress" 

%typemap(in) (sockaddr_in *ADDR) { 
    $1 = new sockaddr_in; 
    $1->sin_family = AF_INET; 
    jclass inetsockaddr = jenv->FindClass("java/net/InetSocketAddress"); 
    assert(inetsockaddr); 
    // TODO: check return 
    jmethodID pmid,addrmid,ipbytemid; 
    pmid = jenv->GetMethodID(inetsockaddr, "getPort", "()I"); 
    assert(pmid); 
    jint port = jenv->CallIntMethod($input, pmid); 
    $1->sin_port = htons(port); 
    jclass inetaddr = jenv->FindClass("java/net/InetAddress"); 
    assert(inetaddr); 
    addrmid = jenv->GetMethodID(inetsockaddr, "getAddress", "()Ljava/net/InetAddress;"); 
    assert(addrmid); 
    jobject addrobj = jenv->CallObjectMethod($input, addrmid); 
    assert(addrobj); 
    ipbytemid = jenv->GetMethodID(inetaddr, "getAddress", "()[B"); 
    assert(ipbytemid); 
    jbyteArray barr = static_cast<jbyteArray>(jenv->CallObjectMethod(addrobj, ipbytemid)); 
    assert(barr); 
    jbyte *bytes = jenv->GetByteArrayElements(barr, 0); 
    assert(bytes); 
    memcpy(&$1->sin_addr.s_addr, bytes, 4); 
    $1->sin_addr.s_addr = htonl($1->sin_addr.s_addr); 
    jenv->ReleaseByteArrayElements(barr, bytes, JNI_ABORT); // No changes copied back 
} 

%typemap(freearg) (sockaddr_in *ADDR) { 
    delete $1; 
} 

%typemap(javain) sockaddr_in *ADDR "$javainput" 

基本上這調用的java.net.InetSocketAddressgetAddress()getPort()方法,並使用結果來創建用於呼叫的struct sockaddr_in

注:

  1. 我不是100%肯定我明白了這裏的字節順序
  2. 我們應該支持AF_INET6正確太 - 我們就需要檢查給定的InetSocketAddress看哪個子類在類型映射本身中。
  3. 沒有out typemap。這基本上是相反的過程,JNI代碼將爲我們創建新的Java對象。
  4. 斷言是非常醜陋的。

爲了完整這裏還有這個包裹,不涉及的JNI,但編寫Java的一點點的第三種可能的方式。我們所做的是SWIG將第一個示例中的struct sockaddr包裝起來,但是然後使用sockaddr包裝的函數返回java.net.InetSocketAddress對象,並提供一些代碼用於在兩者之間進行轉換。我將用一個「out」類型圖給出一個例子,即從函數返回。

考慮:

sockaddr_in *make_stuff(); 

我們可以把它包:

%typemap(jstype) sockaddr_in *make_stuff "java.net.InetSocketAddress" 
%typemap(javaout) sockaddr_in *make_stuff { 
    long cPtr = $jnicall; 
    sockaddr_in s = new sockaddr_in(cPtr, true); 
    byte[] bytes = new byte[4]; 
    for (int i = 0; i < 4; ++i) { 
    bytes[i] = (byte)s.getAddr(i); 
    } 
    java.net.InetAddress addr = null; 
    try { 
    addr = java.net.InetAddress.getByAddress(bytes); 
    } 
    catch (java.net.UnknownHostException e) { 
    return null; 
    } 
    return new java.net.InetSocketAddress(addr, s.getPort()); 
} 

%immutable; 
struct sockaddr_in{ 
    %rename(family) sin_family; 
    short sin_family; 
    %extend { 
    unsigned short getPort() const { 
     return ntohs($self->sin_port); 
    } 
    char getAddr(int byte) const { 
     const char *ptr = reinterpret_cast<const char*>(&$self->sin_addr.s_addr); 
     return ptr[byte]; 
    } 
    } 
}; 
%mutable; 

void do_stuff(sockaddr_in *ADDR); 

我們指定了如何直接裹sockaddr_in,而且還指示從函數本身的回報是更適當的Java類型(%typemap(jstype))並提供少量的Java來執行轉換(%typemap(javaout))。我們也可以在類型圖中做類似的工作。這不正確地處理AF_INET6地址 - 我無法找到IPv6地址的InetAddress.getByAddress()的等效項,所以應該可能存在針對該情況的斷言/例外。

+0

儘管如此,我會盡量做到這一點。 – Flexo

+0

謝謝你。 – c12

+0

@ c12我有一個更好的方法,我會嘗試找到時間充實 – Flexo

-1

使用java.net.InetSocketAddress。

+0

這並不能真正解決swig包裝問題。 – Flexo

1

我相信有更好的答案,我期待着看到它。但這似乎最初起作用。

在你module.i:

%include "stdint.i" 

%{ 
#include <arpa/inet.h> 
%} 

struct in_addr { 
    uint32_t s_addr; 
}; 

struct sockaddr_in { 
    uint16_t sin_port; 
    struct in_addr sin_addr; 
}; 
相關問題