10
votes

Utilisation d'une prise Java du code Jni / C ++

J'ai une application Java qui crée une prise pour parler à un processus serveur, par exemple un nouveau java.net.socket (hôte de chaîne, Port Int). Cette application inclut un groupe de code Legacy C ++ qui doit sucer des gousses de données de ce serveur et le traiter. Ceci est actuellement mis en œuvre par le code natif crée sa propre prise et connectez-vous au serveur, par exemple:

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));


0 commentaires

6 Réponses :


1
votes

Pour votre première question, si vous avez un java.net.sockt référence d'objet dans votre code JNI, vous pouvez invoquer des méthodes dessus, afin de pouvoir lire et écrire des données via la prise.


0 commentaires

0
votes

Votre deuxième question -

Vous pouvez toujours "lier" à l'interface locale que vous souhaitez (avez-vous simplement besoin de l'adresse IP pour elle)

Vide public Bind (SocketAddress Addr) Jette SocketExceptionBinds ce datagramperSocket sur une adresse et un port spécifiques


2 commentaires

Appeler Bind in Java ne sonne pas vraiment utile - il choisit déjà la meilleure interface. Mais obtenir l'adresse locale de la prise Java puis appeler la liaison sur le côté natif pour utiliser la même interface ressemble à une approche raisonnable.


Ben, c'est en fait ce que j'avais fait, mais j'ai un rapport de la prise natif omis de se connecter au serveur (après la liaison à la même adresse locale que la prise Java). Je n'ai pas compris pourquoi cela échoue, c'est pourquoi je voulais voir la mise en œuvre de Java.



10
votes

Pour répondre à votre première question: S'il est possible de réutiliser la prise de Java au sein du code natif - Oui, c'est possible, mais je ne le recommanderais pas (vous ne les recommanderais pas aux internes d'une implémentation / version spécifique); Mais si vous devez vraiment: utiliser la réflexion pour accéder à java.io.filedescriptor sur le java.net.socketImpl puis utilisez Sun.Misc. JavaOfileDedescriptorAccess's Obtenir la méthode pour obtenir le descripteur de socket natif. Checkout DualstackplansocketImpl.java )

Pour répondre à votre deuxième question: quel est l'algorithme de Java pour trouver l'interface par défaut sur Windows - Checkout getDefaultiPv6Interface méthode dans NET_UTIL_MD.C (Ne laissez pas le V6 vous tromper - je crois qu'il est utilisé pour V4 aussi ).

Je vous conseillerais d'ouvrir et d'utiliser la prise à partir du code C (JNI) ou du code Java, de préférence, de préférence, comme vous constaterez que le nettoyage et la gestion des erreurs sont mieux gérés dans le code qui gère la prise. L'idée d'ouvrir la prise en Java et des tampons d'octets de passage de C (JNI) est parfaitement sain d'esprit et vous ne devez trouver aucun problème avec le tas sur des tailles de tampon raisonnables et une distribution appropriée dans le code JNI.

Pensez aux serveurs d'applications Java qui gèrent d'énormes quantités de données sans attelage.


4 commentaires

Merci Zoran, je vais jeter un coup d'oeil.


-1 pour suggérer la mise en attente dans les détails de la mise en œuvre de la JVM privée. Il est possible de le faire sans recourir à de telles atrocités


Avez-vous lu la question et ma réponse à ce sujet? Vous souhaitez peut-être fournir une solution sans accéder aux détails de la mise en œuvre privés de la JVM?


Le référentiel de "net_util_md.c" n'est plus disponible.



1
votes

Méfiez-vous des solutions qui piquent dans des spécificités de mise en œuvre JVM, elles sont susceptibles de casser à l'avenir ou d'un différents fournisseurs VM. Il y a un moyen de faire cela de manière portant en utilisant java.nio API. Il existe des méthodes de communication avec des canaux de code natif sans copier des tampons à / vers le tas Java.

L'idée de base consistera à créer un java.nio.socketchannel dans votre code Java pour ouvrir la connexion. Ensuite, dans l'utilisation C ++ NEWDIRECBYTEBUFFER Pour créer un Java.NIO.BYTEBuffer L'instance peut être transmise au Lire / écrire Méthodes de l'instance de canal.

regarder Améliorations de la JNI introduites dans la version 1.4 du Java 2 SDK et Nouveau API d'E / S pour les détails.


0 commentaires

0
votes

Je ne peux pas penser à une raison pour laquelle Java choisirait une interface locale "meilleure" que le code en cours. Tout ce qu'il fait est appeler le code natif, très similaire à ce que vous avez vous-même. Vous voyez peut-être quelque chose qui est dépendant de l'ordre plutôt que de Java-dépendant.


2 commentaires

Je peux penser à quelques raisons, mais je n'ai aucun moyen de dire quelles étaient les raisons initiales. Néanmoins, le comportement est différent, comme indiqué par Zoran. Le code Java appelle Wsaioctl avec siO_ROUTING_INTERFACE_QUERY pour obtenir l'interface. À ce stade, je vous appelle à vous débarrasser du code de prise native de toute façon.


Yepp, tout vient des prises Berkeley.



0
votes

Vous pouvez fournir une sous-classe SocketMIMPL avec propre fichier FileDescriptor en fonction de fonctions JNI qui exposent la prise natif. Comme vous l'êtes en JNI, vous devez toute façon tenir compte de la plate-forme (-Bstraction), mais vous êtes indépendant de la mise en œuvre Java, qui, selon la réponse acceptée, est le principal risque.

Votre classe SocketImpl est déployée par Socket.SetsCocketImplactory () avec usine appropriée.


0 commentaires