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)

数据作为服务器到达,下次我尝试读取 objectinputstream 上的对象时出现异常,这是再见数据包。

客户代码:

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 回答