我对 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"); }}