4

JNA を使用して、BSD のような C ソケット API を Java にラップする必要があります。標準の BSD ソケット API と基本的に同じ機能を持っています。

ラッピングは、その引数に必要な構造体と、sを処理するために必要なマスキング関数 (マクロ)select()のために問題があります。ヘッダー ファイル (Ubuntu 8.04 の sys/select.h など) をクロールしようとしましたが、定義はそれほど単純ではありません。特に、JNA の InvocationMapper でラップするときに必要な -macrosの実装を見つけるのが難しいことがわかりました。fd_setFD_*fd_setFD_*

注: 標準の TCP または unix-socket API をラップしようとしているのではなく、カスタムの API をラップしようとしています。このように、Java の組み込みソケットは条件に適合しません。

4

2 に答える 2

0

fd_set 構造体にバイト配列を使用し、いくつかの算術演算を使用して、配列内の正しいバイト位置を見つけます。

private static final int FD_SETSIZE = 1024;
private static final boolean isBigEndian = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;

private static interface Libc extends Library {
   int select (int nfds, byte[] readfds, byte[] writefds, byte[] errfds, TimeVal timeout);
   //...
   }

private static class FdSet {
   byte[] a;
   FdSet() {
      a = new byte[FD_SETSIZE / 8]; }
   void set (int fd) {
      a[getBytePos(fd)] |= getBitMask(fd); }
   boolean isSet (int fd) {
      return (a[getBytePos(fd)] & getBitMask(fd)) != 0; }
   private static int getBytePos (int fd) {
      if (fd < 0 || fd >= LibcDefs.FD_SETSIZE) {
         throw new RuntimeException("File handle out of range for fd_set."); }
      if (isBigEndian) {
         return (fd / 8 / Native.LONG_SIZE + 1) * Native.LONG_SIZE - 1 -
               fd / 8 % Native.LONG_SIZE; }
       else {
         return fd / 8; }}
   private static int getBitMask (int fd) {
      return 1 << (fd % 8); }}

private static class TimeVal extends Structure {
   public NativeLong  tv_sec;
   public NativeLong  tv_usec;
   TimeVal (int ms) {
      set(ms); }
   void set (int ms) {
      tv_sec.setValue(ms / 1000);
      tv_usec.setValue(ms % 1000 * 1000); }
   @Override protected List<?> getFieldOrder() {
      return Arrays.asList("tv_sec", "tv_usec"); }}

public boolean waitInputReady (int timeoutMs) throws IOException {
   TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
   FdSet rxSet = new FdSet();
   FdSet errorSet = new FdSet();
   rxSet.set(fileHandle);
   errorSet.set(fileHandle);
   int rc = libc.select(fileHandle + 1, rxSet.a, null, errorSet.a, timeVal);
   checkSelectErrors(rc, errorSet);
   if (rc == 0) {
      return false; }
   if (!rxSet.isSet(fileHandle)) {
      throw new RuntimeException("rxSet bit is not set after select()."); }
   return true; }

public boolean waitOutputReady (int timeoutMs) throws IOException {
   TimeVal timeVal = (timeoutMs < 0) ? null : new TimeVal(timeoutMs);
   FdSet txSet = new FdSet();
   FdSet errorSet = new FdSet();
   txSet.set(fileHandle);
   errorSet.set(fileHandle);
   int rc = libc.select(fileHandle + 1, null, txSet.a, errorSet.a, timeVal);
   checkSelectErrors(rc, errorSet);
   if (rc == 0) {
      return false; }
   if (!txSet.isSet(fileHandle)) {
      throw new RuntimeException("txSet bit is not set after select()."); }
   return true; }

private void checkSelectErrors (int rc, FdSet errorSet) throws IOException {
   if (rc == -1) {
      throw new IOException("Error in select(), errno=" + Native.getLastError() + "."); }
   boolean error = errorSet.isSet(fileHandle);
   if (!(rc == 0 && !error || rc == 1 || rc == 2 && error)) {
      throw new RuntimeException("Invalid return code received from select(), rc=" + rc + ", error=" + error + "."); }
   if (error) {
      throw new IOException("Channel error state detected"); }}
于 2015-08-07T01:11:34.097 に答える
0

FD_*特に、JNA の InvocationMapper でラップするときに必要な -macrosの実装を見つけるのが難しいことがわかりました。

C プリプロセッサcppは、マクロがどのように展開されるかを調べるのに役立ちます。関連するマクロを使用するダミー プログラムを作成し (字句的には正しいはずですが、コンパイルする必要はありません)、実行してcpp何が起こるかを観察します。

于 2009-08-20T10:00:33.387 に答える