我有一个C函数,我想通过SWIG使用Java调用,但我不确定如何处理sockaddr_in C结构。任何人都有关于如何处理sockaddr_in的例子吗?
答案 0 :(得分:2)
实际上有一篇关于在swig.org上包裹sockaddr_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.InetSocketAddress
的getAddress()
和getPort()
方法,并使用结果为调用创建struct sockaddr_in
。
注意:
InetSocketAddress
以查看它在typemap本身中的哪个子类。out
类型地图。这基本上是相反的过程,JNI代码将为我们创建新的Java对象。为了完整性,还有第三种可能的方法来包装它,它不涉及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()
,所以对于那种情况应该有一个断言/异常。
答案 1 :(得分: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;
};
答案 2 :(得分:-1)
使用java.net.InetSocketAddress。