使用JNI / C ++代码中的java套接字

时间:2010-02-05 14:36:59

标签: java c++ sockets java-native-interface

我有一个java应用程序,它创建一个与服务器进程通信的套接字,例如new java.net.Socket(String host,int port)。这个应用程序包含一堆遗留的c ++代码,需要从该服务器吸取大量数据并对其进行处理。这是通过让本机代码创建自己的套接字并连接到服务器来实现的,例如:

sock = socket(AF_INET, SOCK_STREAM, 0);
struct hostent* hp = gethostbyname(host);
if (!hp)
{
  unsigned long addr = inet_addr(host);
  hp = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET);
}

struct sockaddr_in name;
name.sin_family = AF_INET;
memcpy(&name.sin_addr, hp->h_addr, hp->h_length);
name.sin_port = htons(port);

connect(sock, (sockaddr*)&name, sizeof(name));

在具有多个NIC(例如有线和wifi或VPN连接)的Windows vista / 7计算机上,这两个套接字最终可能会有不同的本地地址。 java代码似乎选择了“更好”的界面(有线Gb enet =更高的MTU?),本机(天真?)代码获得“默认”界面(坚持在USB设备中,它成为您的默认设置 - yuck)

这给我带来了一些问题,我不认为细节是相关的。两个问题:

  1. 我是否可以从JNI代码中重用java套接字(可移植?假设是Sun JDK)。这样可以完全避免这个问题,但到目前为止,我没有看到任何与JNI /本机代码中的java.net.Socket内容交互的方法。

  2. 由于第一个问题的答案可能是NO,java如何创建该套接字(选择接口)?代码片段受到欢迎。我在openjdk的东西中四处寻找并找不到我要找的东西。

  3. 谢谢, 克里斯

6 个答案:

答案 0 :(得分:10)

回答你的第一个问题:如果可以在本机代码中重用Java的套接字 - 是的,这是可能的,但我不推荐它(你会把自己绑在特定实现/版本的内部);但如果你真的必须:使用反射来访问java.net.SocketImpl上的java.io.FileDescriptor,那么使用sun.misc。 JavaIOFileDescriptorAccess的获取本机套接字描述符的get方法。结帐DualStackPlainSocketImpl.java

回答你的第二个问题:在Windows上找到默认界面的Java算法是什么 - net_util_md.c中的checkout getDefaultIPv6Interface方法(不要让v6欺骗你 - 我相信它也用于v4)

我建议您打开并使用C(JNI)代码或Java代码(最好是后者)中的套接字,因为您会发现清理和错误处理最好在管理代码的代码中处理插座。在Java中打开套接字并从C(JNI)传递字节缓冲区的想法是完全正确的,你不应该在合理的缓冲区大小和JNI代码中正确的释放中找到堆的任何问题。

思考处理大量数据的Java应用程序服务器。

答案 1 :(得分:1)

对于您的第一个问题,如果您的JNI代码中有java.net.Socket对象引用,则可以在其上调用方法,这样您就可以通过套接字读取和写入数据。

答案 2 :(得分:1)

要注意在JVM实现细节中徘徊的解决方案,它们将来可能会破坏或与不同的供应商VM发生冲突。有一种方法可以使用java.nio API移植。有一些方法可以从本机代码与通道进行通信,而无需将缓冲区复制到java堆中。

基本思路是在java代码中创建java.nio.SocketChannel以打开连接。然后在C ++中使用NewDirectByteBuffer创建一个java.nio.ByteBuffer实例,该实例可以传递给通道实例的read / write方法。

查看JNI Enhancements Introduced in Version 1.4 of the Java 2 SDKNew I/O APIs了解详情。

答案 3 :(得分:0)

你的第二个问题 -

你总是可以'绑定'到你想要的本地接口(只需要它的IP地址)

public void bind(SocketAddress addr)           抛出SocketException将此DatagramSocket绑定到特定地址&端口

答案 4 :(得分:0)

我想不出为什么Java会选择一个''更好'的本地接口而不是其他代码。它只是调用本机代码,与你自己的代码非常相似。您可能会看到依赖于顺序而非依赖于Java的内容。

答案 5 :(得分:0)

您可以基于 JNI 函数提供带有自己的 FileDescriptor 的 SocketImpl 子类,该函数公开本机套接字。由于您在 JNI 中,您无论如何都必须考虑平台(-抽象),但您独立于 Java 实现,根据公认的答案,这是主要风险。

您的 SocketImpl 类由 Socket.setSocketImplFactory() 和合适的工厂部署。