如何使用SWIG将sockaddr_in C结构映射到Java [英] How to map sockaddr_in C Structure to Java using SWIG
问题描述
我有一个C函数,想通过SWIG使用Java调用,但是我不确定如何处理sockaddr_in C结构.任何人都有我如何处理sockaddr_in的示例吗?
I have a C function that I want to call using Java via SWIG but I'm unsure how to handle the sockaddr_in C structure. Anyone have any examples on how I can handle the sockaddr_in?
推荐答案
There's actually an article on wrapping sockaddr_in
on swig.org, although it looks slightly old now.
基本上,他们所做的就是编写一个函数,该函数为您创建一个新的 sockaddr_in
,并接受需要填充的值作为在Java中易于传递的东西的参数.这是链接文章的略微更新,修整的版本:
Basically what they did was write a function that creates a new sockaddr_in
for you, taking arguments for the values that need to be filled in as things that are easy to pass around in Java. This is a slightly updated, trimmed version of the linked article:
%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端会感觉更自然":
There's a nicer way of wrapping this with SWIG though, we can write a typemap to use java.net.InetSocketAddress
instead, which will feel far more "natural" on the Java side of the interface:
%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"
基本上,这将调用 getPort()
方法/docs/api/java/net/InetSocketAddress.html"rel =" nofollow> java.net.InetSocketAddress
并使用结果创建一个 struct sockaddr_in
进行通话.
Basically this calls the getAddress()
and getPort()
methods of java.net.InetSocketAddress
and uses the result to create a struct sockaddr_in
for the call.
注意:
- 我不是100%肯定我这里有字节顺序
- 我们也应该适当地支持AF_INET6-我们需要检查给定的
InetSocketAddress
,以查看它在类型映射表中属于哪个子类. - 没有
out
类型映射.基本上这是相反的过程,JNI代码将为我们创建新的Java对象. - 断言很难看.
- I'm not 100% sure I've got the byte order right here
- We ought to support AF_INET6 properly too - we'd need to inspect the given
InetSocketAddress
to see which sub-class it is in the typemap itself. - There's no
out
typemap. This is basically the reverse procedure, the JNI code will create new Java objects for us. - The asserts are pretty ugly.
为了完整起见,还有第三种包装方法,不涉及JNI,而是编写一些Java.我们要做的是像第一个示例一样,将SWIG包装为 struct sockaddr
,但随后使包装的使用 sockaddr
的函数返回一个 java.net.InetSocketAddress
对象,并提供一些代码以在两者之间进行转换.我将举一个带有输出"类型映射的示例,即从函数返回.
For completeness there's also a third possible way of wrapping this, which involves no JNI, but writing a little bit of Java. What we do is have SWIG wrap the struct sockaddr
as in the first example, but then have the wrapped functions that use sockaddr
return a java.net.InetSocketAddress
object still and supply some code for converting between the two. I'll give an example with an "out" typemap, i.e. for returning from functions.
给出:
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)
).我们也可以为typemap做类似的事情.这不能正确处理 AF_INET6
地址-我找不到与IPv6地址等效的 InetAddress.getByAddress()
,因此可能应该有一个断言/异常这种情况.
We've specified how to wrap a sockaddr_in
directly, but also instructed the return from the function itself to be the more appropriate Java type (%typemap(jstype)
) and provided a small amount of Java to perform the conversion (%typemap(javaout)
). We could do similar for an in typemap too. This doesn't handle AF_INET6
addresses properly - I can't find an equivalent of InetAddress.getByAddress()
for IPv6 addresses, so there should probably be an assert/exception for that case.
这篇关于如何使用SWIG将sockaddr_in C结构映射到Java的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!