1

現在取り組んでいるセルラー モデム プロジェクトのクライアント/サーバー間のやり取りのトラブルシューティングについて、アドバイスと支援が必要です。クライアントとサーバーは Java で書かれています。

アドバイスが必要な質問は次のとおりです。

(1) 特にネットワークが予期せずドロップアウトする可能性があるセルラー ネットワークのコンテキストで、私が取っているアプローチが大きなファイル (コードに従う) に対応するかどうかについてアドバイスを求めています。〜1GBの大きなファイル。大きなファイルは、サーバーからクライアントに転送されるイメージを表します。これは、最悪のシナリオを表しています。基本ケースには、GPS データとタイムスタンプ情報を含む比較的小さなファイルが含まれています。これらのファイルは、KB から数 MB の範囲にある可能性が高く、頻繁に転送されます。

(2) クライアント/サーバー コードのトラブルシューティングに関するアドバイスが必要です。このアプローチが大きなファイルでは機能しない場合でも、近い将来に概念実証テストをサポートするために、基本ケースでコードを機能させたいと考えています。概念実証のためにソフトウェアの更新は必要ありません。

クライアント/サーバーのやり取りの背景。サーバーに接続するクライアント。サーバーは、クライアントを処理するために新しいスレッドを開始するクライアント要求を検出します。クライアントはシリアル化されたデータ パケットを送信します。データ パケットには、いくつかのヘッダー情報 (ファイル サイズ、crc、ファイル タイプ) とデータ ペイロードが含まれています。サーバーは、データ パケット オブジェクトを受信すると、crc とファイル サイズがヘッダーに含まれる値と一致することを確認します。サーバーは、送信が有効かどうかを示すデータ パケット オブジェクトで応答します。クライアントがサーバーから有効な応答を受信すると、クライアントはグッバイ パケットを送信してセッションを閉じます。サーバーからの応答が無効であった場合、クライアントはデータを再送信し、試行が x 回失敗すると最終的に終了します。最終的、

サーバーコードで発生しているエラーは次のとおりです。

Feb 16, 2013 7:36:40 AM noaa.logbook.server.ServerConnectionHandler run
SEVERE: null
java.io.EOFException
at
java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:2553)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1296)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at noaa.logbook.server.ServerConnectionHandler.run(ServerConnectionHandler.java:69)
    at java.lang.Thread.run(Thread.java:662)

データはサーバーとして到着し、次にオブジェクト入力ストリームでオブジェクトを読み取ろうとしたときに例外が発生したように見えます。これはさようならパケットです。

クライアントコード:

public static boolean clientTransmit(Socket sockToServer, String fileName, int dataPacketType, String id, String fileTimeStamp)    {
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
//TCPConnection tcpConn = null;
DataPacket packet = null;

File inputFile = new File(fileName);
boolean fileExists = inputFile.exists();

int size = 0;
int failedAttempts = 0;
String contents = null;
byte[] ref = null;
boolean success = false;
boolean bye = false;
try
{
  sockToServer.setSoTimeout(5000);

  if ((sockToServer.isConnected()) && (fileExists)) {
    System.out.println("LogBookClientCommunications: Connected to Server");
    System.out.print("Stage 0");
    contents = readFile(fileName);

    packet = LogBookUtilities.packageDataPacket(DataPacket.UPLOAD_DATA, contents,    LogBookClient.SOFTWARE_VERSION, LogBookClient.serialNumber);

    oos = new ObjectOutputStream(sockToServer.getOutputStream());
    oos.writeObject(packet);
    oos.flush();
    System.out.println("LogBookClientCommunications: Sending DataPacket");

    ois = new ObjectInputStream(sockToServer.getInputStream());

    while(!success && failedAttempts < 3) {
      Object object = ois.readObject();
      if (object instanceof DataPacket) {
        System.out.println("LogBookClientCommunications: Received a DataPacket Object");
        DataPacket inPacket = (DataPacket)object;
        byte[] compressedByteRef = inPacket.getDataArray();
        boolean sizeValid = verifySize(compressedByteRef, inPacket.getLength());
        boolean crcValid = verifyCRC(inPacket);
        if ((sizeValid) && (crcValid)) {
            System.out.println("LogBookClientCommunications: Size & CRC Valid");
            String uncompressed = new String(uncompress(compressedByteRef));
            String[] strRef = lookupResponsePairs(dataPacketType);

            if (uncompressed.equals(strRef[0])) {
                success = true;
                System.out.println("LogBookClientCommunications: File arrived uncorrupted");
                //tcpConn.disconnect();
            } else if (uncompressed.equals(strRef[1])) {
                success = false;
                failedAttempts++;
                System.out.println("LogBookClientCommunications: File arrived corrupted");
            }
        } else {
            success = false;
            failedAttempts++;
            if (sizeValid)
                System.out.println("LogBookClientCommunications: CRC InValid");
            else
                System.out.println("LogBookClientCommunications: Size InValid");
        }
      }//end if object instanceof
      else {
        System.out.println("LogBookClientCommunications: Not a DataPacket Object");
        failedAttempts++;
      }
    }//while
    //Close Connection by sending bye
    System.out.println("LogBookClientCommunications: Sending Good Bye...");
    DataPacket goodbye  = LogBookUtilities.packageDataPacket(DataPacket.RESPONSE, quit", LogBookClient.SOFTWARE_VERSION, LogBookClient.serialNumber);
    oos.writeObject(goodbye);
    oos.flush();
  }
  else
  {
    System.out.println("LogBookClientCommunications: Failed to Connect or File Did Not Exist");
    success = false;
  }
}
catch (ClassNotFoundException ex) {
  Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
  Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
} finally {
  try {
    oos.close();
    ois.close();
    sockToServer.close();
  } catch (IOException ex) {
    Logger.getLogger(LogBookUtilities.class.getName()).log(Level.SEVERE, null, ex);
  }
}
return success;
}

サーバー接続ハンドラ コード:

public void run()
{
ObjectInputStream ois = null;
ObjectOutputStream oos = null;
int failedAttempts = 0;
boolean success = false;
boolean sendResponse = false;
Socket soc = getSocket();
Object obj = new Object();
long time = System.currentTimeMillis();

DataPacket inPacket = null;
DataPacket outPacket = null;
try {
  System.out.println("Server Connection Handler: Receiving Connection From - " + soc.getRemoteSocketAddress());
  soc.setSoTimeout(15000);
  oos = new ObjectOutputStream(soc.getOutputStream());
  oos.flush();

  ois = new ObjectInputStream(soc.getInputStream());

  if (ois == null | oos == null) {
      System.out.println("Server Connection Handler: Successfull Opened Streams");
      if (ois == null) { System.out.println("Server Connection Handler: ObjectInputStream Failed to Open");}
      else {System.out.println("Server Connection Handler: ObjectOutputStream Failed to Open"); }
  }
  while (true) {
      inPacket = (DataPacket)ois.readObject();
      boolean validPacket = LogBookUtilities.isPacketValid(inPacket);
      if (validPacket) {
          if(inPacket.getField() == DataPacket.RESPONSE) {
              byte[] ref = inPacket.getDataArray();
              String data = LogBookUtilities.uncompress(ref);
              if (data.equalsIgnoreCase("bye")) {
                  System.out.println("Server Connection Handler: Bye....");
                  break;
              }
          }
          else if (inPacket.getField() == DataPacket.UPLOAD_DATA) {
              System.out.println("Server Connection Handler: Writing data to file");
              LogBookUtilities.processClientPacket(inPacket);
              System.out.println("Server Connection Handler: File Successfully Transfered");
              outPacket = LogBookUtilities.makeResponse(inPacket.getField(), true, LogBookServer.SOFTWARE_VERSION, LogBookServer.ID);
              sendResponse = true;
          }
      } 
      else {
          if (inPacket.getField() == DataPacket.UPLOAD_DATA) {
                sendResponse = true;
                outPacket = LogBookUtilities.makeResponse(inPacket.getField(), true, LogBookServer.SOFTWARE_VERSION, LogBookServer.ID);
          }
      }

      if (sendResponse) {
        oos.writeObject(outPacket);
        oos.flush();
      }

  }//end while


    }
    catch (ClassNotFoundException ex) {
      Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null,     ex);
    }
    catch (IOException ex) {
      Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null, ex);
    }
    finally {
      try {
        ois.close();
        oos.close();
        soc.close();
      }
      catch (IOException ex) {
        Logger.getLogger(ServerConnectionHandler.class.getName()).log(Level.SEVERE, null, ex);
      }
    }
    }

サーバーコード:

public class LogBookServer
{
public static final String ID = "666666";
public static final String SOFTWARE_VERSION = "0.02";
public static final String VFILE = "vFile";
public static final String DASH = "-";
public static final String DATEXT = ".dat";
public static final int FAILED_THRESHOLD = 3;
private int port = 6767;
private String ip = "";

public int getListeningPort() {
  return this.port;
}

public void setListeningPort(int port) {
  this.port = port;
}

public void run()
  throws Exception
{
Selector acceptSelector = SelectorProvider.provider().openSelector();

ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);

InetAddress lh = InetAddress.getLocalHost();
InetSocketAddress isa = new InetSocketAddress(lh, this.port);
ssc.socket().bind(isa);

SelectionKey acceptKey = ssc.register(acceptSelector, 16);

int keysAdded = 0;

while ((keysAdded = acceptSelector.select()) > 0)
{
  Set readyKeys = acceptSelector.selectedKeys();
  Iterator i = readyKeys.iterator();

  while (i.hasNext()) {
    SelectionKey sk = (SelectionKey)i.next();
    i.remove();

    ServerSocketChannel nextReady = (ServerSocketChannel)sk.channel();

    Socket s = nextReady.accept().socket();

    handleConnection(s);
  }
 }
}

void handleConnection(Socket socket)
{
  System.out.println("hadling connection....");
  ServerConnectionHandler connectionHandler = new ServerConnectionHandler(socket);
  new Thread(connectionHandler).start();
}
}
4

1 に答える 1

0

あなたのクライアントには(読みやすくするために差分行に分割されています):

DataPacket goodbye  = 
    LogBookUtilities.packageDataPacket(DataPacket.RESPONSE, 
                                       "quit", 
                                       LogBookClient.SOFTWARE_VERSION,
                                       LogBookClient.serialNumber);

次に、サーバーには次のものがあります。

if (data.equalsIgnoreCase("bye")) {

これらのうち、どれが他のものと似ていませんか? ;)

サーバーは「さようなら」パケットを読み取りますが、それを認識せず、再びループして閉じたソケットから読み取ろうとします。プレスト、IOException

「スケーラビリティ」についてのあなたの質問については...それは効率ほどではありません。ネットワークが自分の足元から抜け落ちてしまうのではないかと心配しているなら、シリアル化されたオブジェクトを送信するのはおそらく適切ではありません。再開する方法はありません-部分的な送信は完全に再送信する必要があり、あなたが述べたようにデータのギグである場合...それは悪いことです. 妥当なバッファ サイズでのwrite()メソッドを使用することをお勧めします。OutputStreamこれにより、送信されたデータを追跡し、ネットワークが回復したら転送を再開できます (これには、サーバーが既に受信したものを把握できるように、クライアントとサーバーの間に何らかのロジックを実装する必要があります)。ネットワーク障害の場合)。

于 2013-02-16T23:07:46.490 に答える