2011-04-29 5 views
1

C 서버와 통신하는 java TCP 클라이언트를 작성 중입니다. 둘 사이에서 송수신을 교대로해야합니다. 내 코드는 다음과 같습니다.Java TCP 클라이언트 전송이 차단 되었습니까?

  1. 서버는 클라이언트에게 이진 MSG (LEN)의 길이를 송신한다 (자바)
  2. 클라이언트
  3. 서버 바이너리 전송하고 클라이언트는 '길이 (len)의 바이트 배열을 할당하는 "OK"문자열을 보낸다 바이트를받습니다.
  4. 다시 "ok"를 보냅니다.

1 단계. 나는 "len"값을 얻는다. 그러나 클라이언트는 "전송 차단됨"을 수신하고 서버는 데이터 수신을 기다립니다.

누구든지 살펴볼 수 있습니까? try 블록에서

은 내가 정의 :

  Socket echoSocket = new Socket("192.168.178.20",2400); 
      OutputStream os = echoSocket.getOutputStream();  
      InputStream ins = echoSocket.getInputStream(); 
      BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 

      String fromPU = null; 


      if((fromPU = br.readLine()) != null){ 
      System.out.println("Pu returns as="+fromPU); 

      len = Integer.parseInt(fromPU.trim()); 
      System.out.println("value of len from PU="+len); 

      byte[] str = "Ok\n".getBytes(); 
      os.write(str, 0, str.length); 
      os.flush(); 

      byte[] buffer = new byte[len]; 
      int bytes; 
      StringBuilder curMsg = new StringBuilder(); 
      bytes =ins.read(buffer); 
      System.out.println("bytes="+bytes); 
      curMsg.append(new String(buffer, 0, bytes));    
      System.out.println("ciphertext="+curMsg); 
        os.write(str, 0, str.length); 
      os.flush(); 
      } 

업데이트 :

것은 여기 내 코드입니다. 현재, 어느 쪽에서도 recv 또는 send 차단이 없습니다. 그러나 Buffered Reader와 DataInput Stream reader 모두에서 ok msg를 보낼 수 없습니다. 서버 측에서는 ok 대신 2 바이트 대신 많은 수의 바이트를 얻습니다.

  Socket echoSocket = new Socket("192.168.178.20",2400); 
      OutputStream os = echoSocket.getOutputStream(); 
      InputStream ins = echoSocket.getInputStream(); 
      BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 
      DataInputStream dis = new DataInputStream(ins); 
      DataOutputStream dos = new DataOutputStream(os); 
      if((fromPU = dis.readLine()) != null){ 
      //if((fromPU = br.readLine()) != null){ 
      System.out.println("PU Server returns length as="+fromPU);  
      len = Integer.parseInt(fromPU.trim()); 
      byte[] str = "Ok".getBytes(); 
      System.out.println("str.length="+str.length); 
      dos.writeInt(str.length); 
      if (str.length > 0) { 
        dos.write(str, 0, str.length); 
       System.out.println("sent ok"); 
      } 
      byte[] buffer = new byte[len]; 
      int bytes; 
      StringBuilder curMsg = new StringBuilder(); 
      bytes =ins.read(buffer); 
      System.out.println("bytes="+bytes); 
       curMsg.append(new String(buffer, 0, bytes));    
       System.out.println("binarytext="+curMsg); 

      dos.writeInt(str.length); 
      if (str.length > 0) { 
        dos.write(str, 0, str.length); 
       System.out.println("sent ok"); 
      } 
+0

'클라이언트가 차단됨'이란 무엇을 의미합니까? 디버깅을 시도 했습니까? – hage

답변

3

스트림 주위에 BufferedReader를 사용하고 스트림에서 이진 데이터를 읽으려고하는 것은 잘못된 생각이다. 서버가 일 경우 실제로는이 모든 데이터를 한 번에 보냈고 BufferedReader은 이진 데이터와 반환 된 행을 읽었을 때 놀랄 일이 아닙니다.

프로토콜을 제어하고 있습니까? 그렇다면 데이터 길이를 바이너리 (예 : 고정 4 바이트)로 보내서 텍스트와 바이너리간에 전환하는 방법 (기본적으로 아픔)을 해결할 필요가 없도록 변경하는 것이 좋습니다.

할 수 없다면 \n을 나타내는 바이트가 나타날 때까지 한 번에 한 바이트 씩 읽은 다음 읽은 내용을 텍스트로 변환하고 구문 분석 한 다음 나머지는 청크로 읽습니다. 약간 비효율적입니다 (한 번에 한 번에 버퍼를 읽지 않고 한 번에 한 바이트 씩 읽음). 그러나 그 시점에서 읽혀지는 데이터의 양은 매우 적습니다.

+1

+1 : 또 다른 방법은 DataInputStream을 readLine() 및 readFully()와 함께 사용하는 것입니다. readLine()이 이상적이지는 않지만 OP가 원하는 것을 수행 할 수 있습니다. –

+0

@ 피터 : 아마도. 그것은 이유가있어 비추천이지만, 좋은 생각입니다. 개인적으로 필자는 프로토콜 디자이너가 텍스트와 바이너리를 이런 방식으로 혼합하는 것을 멈추길 바란다. (알려진 크기의 이진 블록 내에 텍스트가 캡슐화되어 있어도 괜찮습니다.) –

+0

IMHO, 자신이하는 일에 대한 명확한 아이디어가 없다면 반드시 혼합해서는 안됩니다. 즉, 텍스트 및 이진의 요구 사항을 완전히 이해하고 필요에 따라 프로토콜을 문서화 한 후에야 –

0

몇 가지 생각 :

 len = Integer.parseInt(fromPU.trim()); 

당신은 몇 가지 의미가 최대에 주어진 크기를 확인해야합니다. 서버가 클라이언트에 2 기가 바이트 메시지를 보내지 않을 것입니다. (어쩌면 가능 하겠지만 더 좋은 디자인이 될 수도 있습니다 :) 일반적으로 많은 양의 메모리를 원격 클라이언트에 할당하고 싶지는 않습니다. 에게 할당하도록 요청합니다. 원격 공격은 쉽게 원격 공격을받을 수 있습니다.

 BufferedReader br = new BufferedReader(new InputStreamReader(ins)); 
     /* ... */ 
     bytes =ins.read(buffer); 

아마 당신의 BufferedReader는 너무 많은 데이터에 빨려있다? 계속하기 전에 서버 Ok 인 경우을 대기합니까? BufferedReader 개체를 연결 한 후에 기본 InputStreamReader 개체를 읽을 수 있습니까?

TCP는 다음 2 주 동안 10 바이트 단위로 데이터를 전송할 수 있습니다. - 캡슐화, 하드웨어 차이 등으로 인해 결국 사용되는 패킷의 크기를 알 수 없으므로 두 동료 사이에서 대부분 특정 양의 데이터를 찾고있는 응용 프로그램은 대신 이와 비슷한 코드를 사용하여 버퍼를 채 웁니다 (유닉스 환경의 고급 프로그래밍에서 도난당한 우수한 책인 유감스럽게도 C 코드와 코드 자바에 있지만 원칙은 동일합니다) :

취할 수있는 점은 버퍼 채우기가 1 또는 read()으로 100 회 전화를 걸면 코드가 네트워크 기능의 미세한 변화에 대해 탄력 있어야합니다.

+0

감사합니다 sarnold. 일단이 버그가 수정되면 바이트 길이를 제한해야합니다. – pimmling