【问题标题】:Reliable data transfer over an UnReliable Channel通过不可靠通道进行可靠的数据传输
【发布时间】:2013-08-26 17:08:40
【问题描述】:

我有一个数据通道,可以通过它传输一些数据,该通道是我自己实现的无线系统,由于物理限制,可靠性较低90%和非常low bandwidth

为了克服这个问题,我打算用一个应该使用一些数据正确方法的系统来包装整个数据通道,并在数据损坏时发送重新发送请求(将使用校验和检查损坏) .

每当其中一个包装器接收到错误数据时,它都会发送resend request,并在堆栈中为未知数据保留内存中的位置。当可靠性下降时,堆栈将快速增长,因为每一方都会启动互相发送resend request,因为它还没有收到最后一个resend request。即使可靠性恢复正常,它也会尝试重新发送所有resend requests,直到堆栈变空。

这会影响带宽,因为大部分请求不会是数据,而是resend requests。此外,该系统将在 RAM 非常有限的微控制器上运行,只有几个字节,这可能会导致堆栈溢出罕见的情况。

有什么建议吗?

这是一个描述数据通道的Java 模型

public interface DataChannel {

    abstract void send(String s);
    abstract void setOnDataListener(OnDataListener l);

    interface OnDataListener {
        abstract void onData(String s);
    }

}

这是一个 DataChannel 的抽象类,用于简化稍后的实现

public abstract class AbstractReliableChannel implements DataChannel,OnDataListener {

    protected DataChannel mUnReliable;
    private OnDataListener mUnDataListener;

    public AbstractReliableChannel(DataChannel unReliableChannel){
        mUnReliable = unReliableChannel;
    }

    @Override
    public abstract void send(String s);

    @Override
    final public void setOnDataListener(OnDataListener l) {
        mUnDataListener = l;
    }

    /*
     * Should be called by the implimanting class
     */
    final protected void notifiyListenerThatDataReceived(String s){
        mUnDataListener.onData(s);
    }

    /**
     * should be called by the implanting class
     */
    final protected void sendOverUnreliableChannel(String s){
        mUnReliable.send(s);
    }

}

这是 UnReliable 频道的实现

public class UnReliableChannel extends AbstractReliableChannel {

    public ReliableChannel(DataChannel unReliableChannel) {
        super(unReliableChannel);
    }

    @Override
    public void send(String s) {
        if( new Random().nextInt(10) % 5 == 0 )
            s = ModifyStringRandomly(s);

        sendOverUnreliableChannel(s);
    }

    @Override
    public void onData(String s) {
        if( new Random().nextInt(10) % 5 == 0 )
            s = ModifyStringRandomly(s);

        notifiyListenerThatDataReceived(s);
    }

}

这是一个可靠的通道实现,我之前描述过

public class ReliableChannel extends AbstractReliableChannel implements Runnable {

    public static String DATA = "D";
    public static String RESEND = "R";
    public static String OK = "O";
    private Thread mThread;

    public ReliableChannel(DataChannel unReliableChannel) {
        super(unReliableChannel);
        mThread = new Thread(this);
        mThread.start();
    }

    private Stack<String> mSend;

    @Override
    public void send(String s) {
        mSend.add(s);
    }

    @Override
    public void onData(String s) {
        if(isDataValid(s)){
            if(s.equals(RESEND)){
                String toResend = mSend.pop();
                mSend.push(toResend);
                mThread.notify();
            } else if (s.equals(OK) ) {
                mSend.pop();
                mThread.notify();
            } else if(s.startsWith(DATA)){
                notifiyListenerThatDataReceived(s.substring(1));
                mSend.push(OK);
            }
        } else {
            mSend.add(RESEND);
            mThread.notify();
        }
    }

    private void sendOverUnreliableChannelWithCheckSum(String s){
        // ADD checkSUM
        sendOverUnreliableChannel(RESEND);
    }

    @Override
    public void run() {
        while(true){
            while(mSend.isEmpty())
                ;
            sendOverUnreliableChannelWithCheckSum(mSend.pop());
            mThread.wait();
        }
    }


    private boolean isDataValid(String s){
        // SHOULD BE SOME CHECKSUM IMPLEMINTATION
        return true;
    }


}

【问题讨论】:

  • 有趣。本质上类似于基于 IP 的 TCP,但基于 Java 和通用目的。我也有同样的需求。
  • 这是一个独立的项目,它与网络无关,这里的java代码只是为了说明问题。代码本身是在arduino上运行的,实际比特率在附近30 bps,可靠性为 10%。它必须传递一些基本的数据和控制消息,效果很差,我不得不重新实现通道。

标签: java data-transfer reliability


【解决方案1】:

问题出在您低效的协议设计,而不是编程。要在有损通道中获得可靠的链接,只需使用 tcp 连接或定义类似于 tcp 的协议。基本上,在 Tx 为每个数据包编号。在 Rx 中,当您收到一个坏包时,只需将其丢弃以节省内存。您可以通过检查所有数据包是否具有连续编号来检查数据包的完整性。通过保持适当的滑动窗口,您将获得良好的有效带宽和负担得起的内存使用量。

【讨论】:

  • 我的理解是,您建议跟踪所有收到的数据在口袋里,并且只要有一个坏字节,就在内存中保留一个位置......但是你的小姐关于重试机制,我应该如何获取损坏的字节?我描述的重新发送请求将使用大量带宽,并且需要内存中的位堆栈。只是发送数据几次不会增加太多的可靠性。注意 BW 非常有限。在最佳条件下高达 5 波特。是不是死路一条?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-06
  • 2011-05-10
  • 2012-02-27
  • 1970-01-01
  • 2010-12-26
  • 1970-01-01
相关资源
最近更新 更多