1

我正在编写一个连接到测量设备的应用程序。该设备可以通过串行和网络连接进行连接。我完成的串行端并捕获使用SerialPortEvent.

现在我正在尝试使用socket. 我的连接正常,我可以从设备发送/接收数据。问题是我强制 Thread.sleep 等待所有数据准备好。但现在我想像使用SerialPortEvent.

这是一个两部分的问题:

  1. a 有类似的事件socket吗?还是在这种情况下更可取的自定义解决方案?如果是这样,请添加说明。
  2. 如何完成DATA_AVAILABLE一个套接字

下面是 的代码片段(仅是必要的捕获部分)SerialEventPort,作为我也想用套接字完成的参考:

@Override
public void serialEvent(SerialPortEvent event)
{

if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE)
{
  try
  {
    int available = inputStream.available();
    byte[] readBuffer = new byte[available];

    if (available > 0)
    {
      inputStream.read(readBuffer);
    }

  }

}

4

1 回答 1

1

在这个SO 答案中,Sorrow 声明如下:

我推荐使用与 Selector 和 SelectionKey 连接的 java.nio.channels.SocketChannel。这个解决方案有点基于事件,但比普通的套接字更复杂。

如果您决定采用该解决方案,您将在链接答案中找到代码示例。

但是,如果你在谈论java.net.Socket那时,不,没有事件。我喜欢JTeagle对类似问题的回答:

这通常是通过为客户端生成一个单独的线程来完成的,该线程不断地从流中对 read() 进行阻塞调用——这样,一旦数据可用,read() 调用就会解除阻塞并可以对其接收到的内容进行操作(“事件触发'),然后它返回阻塞等待下一个事件。

而且根据我的经验,这主要是在 Java 中处理套接字的方式。我写了一个基于事件的套接字的实现。由于读取是可阻塞的,因此很可能不需要线程来阻止您的主程序:

public class ObservableSocket extends Thread {
    private final Socket socket;
    private final ArrayList<ObservableSocketListener> listeners;
    private volatile boolean isReading;
    private int BUFFER_SIZE = 1024;

    public ObservableSocket(String host, int port) throws UnknownHostException, IOException {
        this.socket = new Socket(host, port);
        this.listeners = new ArrayList<ObservableSocketListener>(1);
        isReading = true;
        this.start();
    }

    public void addListener(ObservableSocketListener l) {
        if (!listeners.contains(l)) {
            listeners.add(l);
        }
    }

    public void removeListener(ObservableSocketListener l) {
        if (!listeners.contains(l)) {
            listeners.remove(l);
        }
    }

    public void die() {
        isReading = false;
        try {
            this.join();
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public void write(byte[] data) throws IOException {
        socket.getOutputStream().write(data);
        socket.getOutputStream().flush();
    }

    private byte[] getData(byte[] buffer, int red) {
        byte[] redData = new byte[red];
        System.arraycopy(buffer, 0, redData, 0, red);
        return redData;
    }

    @Override
    public void run() {
        byte[] buffer = new byte[BUFFER_SIZE];
        int red;
        ObservableSocketEvent event;
        try {
            while (isReading && (red = socket.getInputStream().read(buffer)) > -1) {
                event = new ObservableSocketEvent(this, getData(buffer, red));
                for (ObservableSocketListener l : listeners) {
                    l.dataAvailable(event);
                }
            }
        } 
        catch (Exception exception) {
            event = new ObservableSocketEvent(this, exception);
            for (ObservableSocketListener l : listeners) {
                l.errorOccured(event);
            }
        } 
        finally {
            if (socket != null) {
                try {
                    socket.close();
                    for (ObservableSocketListener l : listeners) {
                        l.closed(new ObservableSocketEvent(this));
                    }
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }   
}

这是您需要实现的侦听器类:

public interface ObservableSocketListener extends EventListener {
    public void dataAvailable(ObservableSocketEvent event);
    public void errorOccured(ObservableSocketEvent event);
    public void closed(ObservableSocketEvent event);
}

和事件类:

public class ObservableSocketEvent extends EventObject {
    private final byte[] data;
    private final Exception exception;

    public ObservableSocketEvent(Object source) {
        super(source);
        this.data = null;
        this.exception = null;
    }

    public ObservableSocketEvent(Object source, byte[] data) {
        super(source);
        this.data = data;
        this.exception = null;
    }

    public ObservableSocketEvent(Object source, Exception exception) {
        super(source);
        this.data = null;
        this.exception = exception;
    }

    public byte[] getData() {
        return data;
    }

    public Exception getException() {
        return exception;
    }      
}

我制作了一个服务器来生成一些随机数据来测试这段代码,这就是我在客户端的类主方法中使用它的方式:

    ObservableSocket observableSocket = new ObservableSocket("localhost", 3339);
    observableSocket.addListener(new ObservableSocketListener() {

        @Override
        public void dataAvailable(ObservableSocketEvent event) {
            System.out.println("data received: "+new String(event.getData()));
        }

        @Override
        public void closed(ObservableSocketEvent event) {
            System.out.println("closing socket");
        }

        @Override
        public void errorOccured(ObservableSocketEvent event) {
            System.out.println("error occured");
            event.getException().printStackTrace();
        }


    });
    Thread.currentThread().sleep(10000);
    observableSocket.die();

它输出:

data received: data 0
data received: data 1
data received: data 2
data received: data 3
data received: data 4                        
closing socket                              // thread is alive here
BUILD SUCCESSFUL (total time: 10 seconds)  // thread dies here

就我的测试而言,sleep需要 in 客户端,因为该die方法:

  • 退出阅读循环(通过设置为 false 的标志)
  • 并等待线程死亡(Thread.join

没有睡眠,测试客户端立即完成(die 方法有效)。如果没有 die 方法,ObservableSocket 线程在测试结束后仍然存在。

使用此代码时,您应该注意两件事:

  • 实例化后ObservableSocket立即Socket连接并Thread启动 a。
  • 您必须die从不是ObservableSocket线程的线程调用该方法(例如,不要从该类中调用该方法)
于 2013-04-11T16:08:47.240 回答