套接字连接的SerialPortEvent的等效项 [英] Equivalent of a SerialPortEvent for a socket connection

查看:101
本文介绍了套接字连接的SerialPortEvent的等效项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个与测量设备连接的应用程序. 该设备可以通过串行和网络连接进行连接. 我已经完成了串行操作,并捕获了使用SerialPortEvent发送的数据.

I'm writing a application that has a connection to a measuring device. This device can be connected by serial and networkconnection. The serial side I'm done with and catches the data that is send by using a SerialPortEvent.

现在,我正在尝试使用socket完成相同的操作.我的连接正常工作,并且可以从设备发送/接收数据.问题是我强制Thread.sleep等待所有数据准备就绪.但是现在我想像SerialPortEvent一样自动捕获接收的数据.

Now I'm trying to accomplish the same thing with a socket. I have the connection working, and I can send/and receive data from the device. Problem with this is that I force a Thread.sleep to wait for all data to be ready. But now I want to automatically catch the receiving data like it did with the SerialPortEvent.

这是一个两部分的问题:

This is a 2 part question:

  1. socket是否有类似事件?还是在这种情况下最好使用自定义解决方案?如果是这样,请添加说明.
  2. 如何完成套接字的DATA_AVAILABLE
  1. Is there a similar Event for a socket? Or is a custom solution preferable in this situation? If so, please add explanation.
  2. How to accomplish DATA_AVAILABLE for a socket

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

Below here is a snippet of the code (only the neccesary catching part) for the SerialEventPort, as a reference to what I also want to accomplish with a socket:

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

  }

}

推荐答案

在此

In this SO answer Sorrow states the following:

我建议使用与Selector和SelectionKey连接的java.nio.channels.SocketChannel.该解决方案某种程度上是基于事件的,但是比普通的套接字要复杂得多.

I recommend using java.nio.channels.SocketChannel connected with Selector and SelectionKey. This solution is somewhat event-based, but is more complicated than just plain sockets.

如果您决定采用哪种解决方案,您将在链接的答案中找到代码示例.

If you decide for that solution you will find the code examples in the linked answer.

但是,如果您正在谈论 JTeagle的答案:

But, if you are talking about java.net.Socket then, no, there are no events. I like JTeagle's answer on a similar question:

这通常是通过为客户端生成一个单独的线程来完成的,该线程连续地阻止从流中对read()的调用-这样,一旦数据可用,read()调用便会立即解除阻止并可以对接收到的内容进行操作(事件触发"),然后返回到阻止等待下一个事件.

This is often done by spawning a separate thread for the client that continuously makes blocking calls to read() from the stream - that way, as soon as data becomes available the read() call unblocks and can act on what it received ('the event fires'), then it goes back to blocking waiting for the next event.

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

And in my experience also, that's mostly how sockets are handled in Java. I wrote an implementation of event based socket. Since reading is blockable, a thread is most probably needed not to block your main program:

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

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

This is the listener class you'll need to implement:

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

我让服务器生成一些随机数据来测试此代码,这是我如何使用它形成客户端的类main方法的方法:

I made a server generating some random data for testing this code, this is how I used it form my client's class main method:

    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

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

In terms of my test, the sleep in client is needed because the die method:

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆