2014-05-23 3 views
0

Java Socket 프로그래밍에 관한 최근의 곤경이 지금 당장 3 일간 당황합니다. 나는 클라이언트에서 서버로 바이트를 전송하기 위해 NIO ByteBuffer와 Channel을 사용한다. 필자는 클라이언트가 두 개의 파일을 순서대로 전송하도록하여 코드를 테스트합니다. 첫 번째 파일은 항상 도착하지만 두 번째 파일은 항상 손실됩니다. 나는 tcpdump를했고 특정 주소와 포트에서 트래픽을 보았지만 pcap의 파일을 해독 할 수 없었다 (pcap 파일의 모든 구문을 읽는 방법을 이해함).Java Socket.read (ByteBuffer dst) 바이트가 없습니다.

어떻게 든 socketchannel.read (bytebuffer)는 두 번째 파일의 바이트를 읽지 않습니다. 첫 번째 파일은 괜찮습니다. 읽기 명령을 통과하고 파일을 수신하고 응답합니다. 두 번째 파일은 읽기 명령 및 응답에 적합합니다. socketchannel.read에 -1을받는 파일이 없습니다. 이것이 문제입니다.

도와주세요. 이것은 정말로 미친 문제입니다. 여기

public class ServerMain 
{ 

    public static void main(String[] args) 
    { 
     ServerSocketChannel listener = null; 
     ServerSocket serverMain = null; 

     try 
     { 
      listener = ServerSocketChannel.open(); 
      serverMain = listener.socket(); 
      serverMain.setReuseAddress(true); 
      serverMain.bind(new InetSocketAddress("192.168.1.12",9999)); 

      while (true) 
      { 
       new ServersThread(serverMain.accept()).start(); 
      } 

     } 
     catch (Exception e) 
     { 
      logger.error("Exception ", e); 
      e.printStackTrace(System.err); 
     } 
     finally 
     { 
      try 
      { 
       listener.close(); 
      } 
      catch (IOException e) 
      { 
       logger.error("IOException ", e); 
       e.printStackTrace(System.err); 
      } 
     } 
    } 
} 

:

public class ServersThread implements Runnable 
{ 
    private Socket socket; 

    public ServersThread(Socket socket) 
    { 
     this(); 
     this.socket = socket; 
    } 

    public void run() 
    { 
     try 
     { 
     InputStreamReader isr = new InputStreamReader(socket.getInputStream()); 
     BufferedReader br = new BufferedReader(isr); 
     PrintStream ps = new PrintStream(socket.getOutputStream(), true); 

     String orderFromClient = br.readLine(); // first read command from client 

     String filename = orderFromClient.split(":")[0] 
     long fileSize = Long.parseLong(orderFromClient.split(":")[1]); 

     File destFile = new File(filename);   
     destFile.setReadable(true); 
     destFile.setWritable(true); 

     FileOutputStream inFile = new FileOutputStream(destFile); 
     FileChannel inChannel = inFile.getChannel(); 


     SocketChannel sc = socket.getChannel(); 
     ByteBuffer dst = ByteBuffer.allocate(65536); 
     dst.clear(); 

     // this receiving binary file part that is questionable. 
     // it always run okay for the first file 
     // the second file is created but always has size 0 
        // The second file will enter into while-loop start and end but it won't enter sc.read(dst) 

     logger.debug(AUDIT,"while-loop start"); 
     start = System.currentTimeMillis(); 
     while (sc.read(dst) != -1) 
     { 
      dst.flip(); 
      logger.debug(AUDIT,"dst flip and ask remaining: {} at position {}",dst.hasRemaining(),dst.position()); 
      while (dst.hasRemaining()) 
      { 
       temp = inChannel.write(dst); 
       curnset += temp; 
       logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp, fileSize); 
      } 
      dst.clear(); 
     } 
     end = System.currentTimeMillis(); 
     logger.debug(AUDIT,"while-loop end"); 

     if (curnset == fileSize) 
      ps.println("SUCCESS"); 
     else 
      ps.println("FAIL"); 

     } 
     catch(Exception e) 
     { 
      e.printStackTrace(System.err); 
      logger.error("Exception ",e); 
     } 
     finally 
     { 
      try 
      { 
       inChannel.close(); 
       inFile.close(); 
       sc.close(); 
       ps.close(); 
       isr.close(); 
       br.close(); 
       socket.close(); 
      } 
      catch(IOException e) 
      { } 
     } 
    } 
} 

가있는 ServerThread가 ServersThread에 유일한 serversocket.accept()를 통과 다른 클래스 ServerMain (소켓 socket) 여기서

의해 실행 가능한 것을 되 호출을 구현하는 ServerMain 클래스 클라이언트 클래스입니다

public class ClientCallable 
{ 

    public static void process(String serverAddr,int serverPort,File file,String command) 
    { 
     SocketChannel sc = null; 
     PrintStream ps = null; 
     BufferedReader br = null; 
     int timeout = 10 * 1000; 
     try 
     { 
      sc = SocketChannel.open(); 
      sc.configureBlocking(true); 

      if (!sc.connect(new InetSocketAddress(serverAddr, serverPort))) 
       return ClientMain.ERROR_UNABLE_TO_CONNECT; 
      sc.socket().setSoTimeout(timeout); 

     } 
     catch (Exception e) 
     { 
      logger.error("Exception ", e); 
      e.printStackTrace(System.err); 
      return; 
     } 

     long maxCount = 8192 * 1024; 
     long curnset = 0l; 
     long temp = 0l; 
     long filesize = 0l; 
     long startTime = 0l; 
     long endTime = 0l; 
     String serverResp = null; 
     FileInputStream fis = null; 
     FileChannel fc = null; 
     try 
     { 
      ps = new PrintStream(sc.socket().getOutputStream()); 
      br = new BufferedReader(new InputStreamReader(sc.socket() 
        .getInputStream())); 
      fis = new FileInputStream(file); 
      fc = fis.getChannel(); 
      filesize = fc.size(); 

      // send command to server 
      ps.print(command); 

      // send binary file 
      ByteBuffer dst = ByteBuffer.allocate(65536); 
      dst.clear(); 
      startTime = System.currentTimeMillis(); 
      while (fc.read(dst) != -1) 
      { 
       dst.flip(); 
       while (dst.hasRemaining()) 
       { 
        temp = sc.write(dst); 
        curnset += temp; 
        logger.debug(AUDIT, "c {} | t {} | size {}", curnset, temp, 
          filesize); 
       } 
       dst.clear(); 
      } 
      sc.shutdownOutput(); 
      endTime = System.currentTimeMillis(); 

      // read server respond 
      serverResp = br.readLine(); 
      logger.debug(AUDIT,"server responds {}",serverResp); 
     } 
     catch (Exception e) 
     { 
      logger.error("Exception ", e); 
      e.printStackTrace(System.err); 
     } 

     try 
     { 
      if (fis != null) 
       fis.close(); 
      if (fc != null) 
       fc.close(); 
      if (ps != null) 
       ps.close(); 
      if (br != null) 
       br.close(); 
      if (sc != null) 
       sc.close(); 
     } 
     catch (Exception e) 
     { 
      logger.error("Exception ", e); 
      e.printStackTrace(System.err); 
     } 

    } 

    public static void main(String[] args) 
    { 
     String serverAddr = "192.168.1.12" 
     int serverPort = 9999; 
     File file1 = new File("file1.fpt"); 
     File file2 = new File("file2.fpt"); 
     String command = "somecommandtoserver"; 
     process(serverAddr,serverPort,file1,command); 
     process(serverAddr,serverPort,file2,command); 
    } 

} 
+0

클라이언트가 데이터를 보내고 서버가 계획대로 바이트를 수신했음을 tcpdump 및 wireshark를 사용하여 확인했습니다. 나는 wireshark와 pcap 파일의 ACK, PSH ACK, SYN, FIN ACK를 연구했다. 그러나 자바의 수준에서 sc.read (dst)! = 1 여전히 일어나고 있습니다! 매우 당혹 스럽네! 누구 제안? 나는 지금 재치있는 끝이다. – Spring

답변

0

이러한 문제로 약 12 ​​일을 소비 한 후에 마침내 문제가 발생하는 이유를 설명 할 수는 없지만 마침내 문제를 해결했습니다. 거의 모든 시간에 문제가 발생하기 때문에 문제는 까다 롭습니다. 일관성없는 파일 배달.

응용 프로그램의 프로토콜이 변경됩니다.

2. 서버의 응답 서버의 응답 3. 보내기를 수신하는 클라이언트 1. 보내기 문자열 순서 2에 대한

새로운 프로토콜을 수신 실제 파일 3. 보내기 클라이언트 1. 보내기 문자열 주문

원래 프로토콜 실제 파일 4. 서버 수신 확인

새 프로토콜로 인해 전송 파일이 일관성있게 유지됩니다.

아무튼 고마워요.

0

첫 번째 업로드를 읽을 때 요 두 번째 파일을 모두 포함하여 스트림이 끝날 때까지 읽는 중입니다. 그래서 두 번째 파일을 읽으려고 할 때 아무것도 남아 있지 않습니다. 파일 앞에 파일 길이를 보내고 그 많은 바이트 만 읽어야합니다.

+0

클라이언트의 주 방법이 보이면 하나의 파일을 보내고 끝납니다 (모든 소켓을 닫음). 클라이언트와 서버 측에서 프로세스를 다시 시작하여 다른 파일을 보냅니다. 두 번째 실행 서버는 여전히 명령과 응답을 읽고 응답 할 수 있습니다. 그러나 항상 빈 sc.read (dst)가 나오므로 어떤 파일도 쓰여지지 않습니다. – Spring

+0

파일 끝까지 소켓 채널을 읽는 중입니다. 피어가 연결을 닫을 때만 발생합니다. – EJP