1

Wifi 経由でアプリにデータをストリーミングするハードウェア デバイスと接続しています。データは問題なくストリーミングされています。データには、新しいレコードが開始されたことを示す文字ヘッダー (DATA:) が含まれています。問題は、受信したデータが必ずしもヘッダー境界に収まるとは限らないため、キャプチャしたデータにヘッダーが含まれるまでデータをキャプチャする必要があることです。次に、ヘッダーの前にあるものはすべて前のレコードに入り、その後にあるものはすべて新しいレコードに入ります。私はこれを機能させていますが、以前にこれを行ったことがあり、問題を解決するための優れたコンピューターサイエンスの方法があるかどうか疑問に思いました.

これが私がすることです:

  1. 現在の読み取りの NSData を NSString に変換します

  2. NSString をプレースホルダー文字列に追加します

  3. ヘッダー (DATA:) のプレースホルダー文字列を確認します。ヘッダーがない場合は、次の読み取りを待ちます。

  4. ヘッダーが存在する場合は、その前にあるものを前のレコード プレースホルダーに追加し、そのプレースホルダーを完全なレコードとして配列に渡して、さらにフィールドに解析できるようにします。

  5. ヘッダーの後に表示されるものは何でも取得し、レコードのプレースホルダーに配置して、次の読み取りで追加できるようにします。手順 3 ~ 5 を繰り返します。

これに欠陥がある場合、またはより良い方法の提案がある場合はお知らせください。

これにはいくつかの設計パターンがあるはずですが、思いつきません。

ありがとう。

更新: ここに少しのコードがあります:

uint8_t buf[1024];
unsigned int len = 0;
len = [(NSInputStream *)stream read:buf maxLength:1024];
if(len) {    
    [data appendBytes:(const void *)buf length:len];
    int bytesRead;
    bytesRead += len;
} else {
    NSLog(@"No data.");
}

有限状態マシンを実装するには、このコードをどのように変更しますか?

4

2 に答える 2

1

それは私がそれを行う方法のようです。私が別の方法で行う唯一のことは、文字列に変換するオーバーヘッドを節約するためにNSData、線形検索を行うカテゴリを作成することです。DATA:するのもそれほど難しいことではありません。何かのようなもの:

@interface NSData (Search)

- (NSRange) rangeOfData:(NSData *)aData;

@end

@implementation NSData (Search)

- (NSRange) rangeOfData:(NSData *)aData {
  const void * bytes = [self bytes];
  NSUInteger length = [self length];

  const void * searchBytes = [aData bytes];
  NSUInteger searchLength = [aData length];
  NSUInteger searchIndex = 0;

  NSRange foundRange = {NSNotFound, searchLength};
  for (NSUInteger index = 0; index < length; index++) {
    if (bytes[index] == searchBytes[searchIndex]) {
      //the current character matches
      if (foundRange.location == NSNotFound) {
        foundRange.location = index;
      }
      searchIndex++;
      if (searchIndex >= searchLength) { return foundRange; }
    } else {
      searchIndex = 0;
      foundRange.location = NSNotFound;
    }
  }
  return foundRange;
}

@end

次に、次を使用できます。

NSData * searchData = [@"DATA:" dataUsingEncoding:NSUTF8StringEncoding];
while(receivingData) {
  if ([receivedData rangeOfData:searchData].location != NSNotFound) {
    //WOOO!
  }
}

(警告: ブラウザで入力)

于 2010-03-16T23:50:28.830 に答える
1

これは古典的な有限状態マシンの問題です。ストリーム ベースの多くのデータ プロトコルは、有限ステート マシンで記述できます。

基本的に、状態と遷移があります。Boost には有限のステート マシン ライブラリがありますが、やり過ぎになる可能性があります。スイッチとして実装できます。

while(stream.hasData) {
char nextInput = stream.get();
switch(currentState) {
  case D: {
     if(nextInput == A)
       currentState = A;
     else
       currentState = D; //die 
  } case A: {
    //Same for A
  }
}
}

要求された詳細:
基本的に下の図を見てください...これは有限状態マシンです。任意の時点で、マシンは正確に 1 つの状態にあります。文字がステート マシンに入力されるたびに遷移が行われ、現在のステートが移動します。(元の状態に戻る可能性があります)。したがって、ネットワーク化されたデータを有限状態マシンとしてモデル化し、そのマシンを実装するだけです。あなたのためにそれをレイアウトするライブラリがあり、あなたがしなければならないことは、各遷移で何が起こるかを正確に実装することだけです. おそらく、データのバイトを解釈または保存することを意味します。解釈は、どのトランジションかによって異なります。遷移は、現在の状態と現在の入力に依存します。FSM の例を次に示します。

代替テキスト http://www.freeimagehosting.net/uploads/b1706f2a8d.png
文字 DATA: が入力された場合、状態は最後の円に移動することに注意してください。他のシーケンスでは、最初の 5 つの状態のいずれかで状態が維持されます。(上段)分割も可能です。したがって、FSM は決定を下すことができるため、DATA2: のようなシーケンスを取得した場合、そのマシンから data2: 部分に分岐し、マシンのまったく異なる部分で異なる解釈を行うことができます。

于 2010-03-16T23:51:02.150 に答える