본문 바로가기

공부/컴퓨터

서버 만들때 읽어 볼 글 - 하나의 데이터는 나누어 들어 올 수 있다.

>
> {소켓 통신시 패킷의 제한이 있나요}
> {양웅직(twist), twist@orgio.net}
>
> InputStream fromWapClient;
> OutputStream toWapClient;
>
>
> fromWapClient = new BufferedInputStream(sock.getInputStream());
> toWapClient = new BufferedOutputStream(sock.getOutputStream());
>
>
> byte[] buf1 = new byte[10000];
> 위처럼 버퍼를 잡아주고
> 파일의 끝까지 오는 것을
> int count;
> while((count = fromWapClient.read(buf1)) != -1)
> {
>                                         
>    num = new String(buf1,0,4);
>    sourdt = new String(buf1,4,12);
>    total_size = new String(buf1,28,8);
>    ....
>   뭐 이런식을 받아서  
>
>    System.out.println("num="+num);
>    System.out.println("sourdt="+sourdt);
>    System.out.println("total_size="+total_size);
>    System.out.println(count+"byte 복사되었습니다");
>
> }
>
> 이렇게 찍어보면 2번 찍힐 때가 있습니다
> 내용의 앞부분이 찍히고
> 그 다음에 나머지 부분이 찍히고
>
> 그래서 잘 살펴보니 2048byte가 넘을때는 꼭 이렇게 2번에 거쳐서 날아옵니다
> 예를 들어서 3048byte을 보낼때는 2048에 해당하는 byte가 먼저찍히고
> 다음에 1000byte에 해당하는 byte가 찍히고 말입니다
> 그래서 버퍼를 크게 잡아주어도
> 물론 한글의 경우는 운좋으면 잘 나오고 아님 이상한 글자로 나올때도 있구요
> 보낼때는 잘 한번에 가는 것 같은데요
> 그래서 버퍼의 크기도 크게 해보고 또 BufferedInputStream을 사용도 해봤는데
> 똑 같은 결과가 나옵니다
>
> packet에 크기의 한계가 있어서 그런것인지
> 아님 프로그램에 문제가 있는 것인지
>
> 답변 꼭 부탁드립니다

네, 나누어서 날아 옵니다. TCP/IP가 그렇게 동작하는 듯 합니다. 따라서, 여러번 받으셔야
합니다. 한번에 날아오는 byte 의 량은 N/W 환경에 따라 다르더군요.
때론, 2048 byte  만큼, 때론 1460 byte 씩, 때론 384 byte씩 날아오고 있네요.

아래의 함수가 도움이 될런지요...

  /* InputStream으로 부터 EOF를 만날 때까지 모든 데이타를 읽어들임 */
  private static byte[] read_data(InputStream in) throws Exception {
    java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
    int bcount = 0;
    byte[] buf = new byte[2048];
    while( true ) {
      int n = in.read(buf);
      if (n == -1) break;
      //System.out.println(n);
      bcount += n;
      bout.write(buf,0,n);
    }
    bout.flush();
    //return bout.toString();
    return bout.toByteArray();
  }
  /* 주어진 길이만큼만 읽어들임 */
  private static byte[] read_data(InputStream in, int len) throws Exception {
    java.io.ByteArrayOutputStream bout = new java.io.ByteArrayOutputStream();
    int bcount = 0;
    byte[] buf = new byte[2048];
    while( bcount < len ) {
      int n = in.read(buf,0, len-bcount < 2048 ? len-bcount : 2048 );
      if (n == -1) break;
      //System.out.println(n);
      bcount += n;
      bout.write(buf,0,n);
    }
    bout.flush();
    //return bout.toString();
    return bout.toByteArray();
  }

NOTE: 위 메소드는 넘어오는 모든 데이타를 ByteArrayInputStream에 임시로 담아둔 후
이를 다시 응용어플리케이션에 넘겨주는 구조이기 때문에, 대량데이타를 전송하고자
할 때는 사용하시면 안됩니다. 위 예제에서 언급하고자 했던 것은 단지 여러번에 나뉘어
날아올 수 있으므로, 필요한 데이타가 모두 올 때까지 끝까지 받으라는 것을 강조하고자
했으며, 하나의 샘플을 제공한 것에 지나지 않습니다.
예를 들어 1MB의 데이타를 위와 같은 메소드를 이용해 동시에 같이 여러 Thread가
받는다고 가정하면, 메모리가 남아 나지 않겠지요.

NOTE: 또한, 위 메소드는 방화벽을 사이에 두고 통신할 경우, 경우에 따라 영원히
blocking 될 가능성이 있습니다. while loop 내에서 retry 할 횟수의 제한을 두는 것도
한가지 방법일 듯 합니다.

-------------------------------------------------------  
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:019-310-7324
================================================


제목 : Java Socket Utilities API : SocketUtil.java
글쓴이: 이원영(javaservice)   2002/06/06 08:33:45  조회수:792  줄수:126
  
다시 정리했습니다. 유용하게 사용하시길 바랍니다.


-------------8><------------------------------------------------------------------
package org.jsn.jdf.util;

/**
* @(#) SocketUtil.java
* Copyright 1999-2002 by  Java Service Network Community, KOREA.
* All rights reserved.  http://www.javaservice.net
*
* NOTICE !      You can copy or redistribute this code freely,
* but you should not remove the information about the copyright notice
* and the author.
*
* @author  WonYoung Lee, javaservice@hanmail.net
*/
import java.io.IOException;
import java.io.ByteArrayOutputStream;
public class SocketUtil {

    public static final int INTPUTSTREAM_READ_RETRY_COUNT = 10;

    private SocketUtil() {}


    /**
     * The <code>read_data</code> method of <code>SocketUtil</code> reads the
     * specified length of bytes from the given input stream.
     *
     * @param      in   an inputstream
     * @param      len  the number of bytes read.
     * @return     The specified number of bytes read until the end of
     *             the stream is reached.
     * @exception  IOException  if an I/O error or unexpected EOF occurs
     */
    private static final byte[] read_data(InputStream in, int len) throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        int bcount = 0;
        byte[] buf = new byte[2048];
        int read_retry_count = 0;
        while( bcount < len ) {
            int n = in.read(buf,0, len-bcount < 2048 ? len-bcount : 2048 );
            if ( n > 0 ) { bcount += n; bout.write(buf,0,n); }
            // What would like to do if you've got an unexpected EOF before
            // reading all data ?
            //else if (n == -1) break;
            else if ( n == -1 ) throw
                 new IOException("inputstream has returned an unexpected EOF");
            else  { // n == 0
                if (++read_retry_count >= INTPUTSTREAM_READ_RETRY_COUNT)
                    throw new IOException("inputstream-read-retry-count( " +
                        INTPUTSTREAM_READ_RETRY_COUNT + ") exceed !");
            }
        }
        bout.flush();
        return bout.toByteArray();
    }

    /**
     * The <code>read_data</code> method of <code>SocketUtil</code> reads all
     * the bytes from the given inputstream until the given input stream
     * has not returned an EOF(end-of-stream) indicator.
     *
     * @param      in   an inputstream
     * @return     all bytes read if the end of the stream is reached.
     * @exception  IOException  if an I/O error occurs
     */
    private static final byte[] read_data(InputStream in) throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        int bcount = 0;
        byte[] buf = new byte[2048];
        int read_retry_count = 0;
        while( true ) {
            int n = in.read(buf);
            if ( n > 0 ) { bcount += n; bout.write(buf,0,n); }
            else if (n == -1) break;
            else  { // n == 0
                if (++read_retry_count >= INTPUTSTREAM_READ_RETRY_COUNT)
                    throw new IOException("inputstream-read-retry-count( " +
                        INTPUTSTREAM_READ_RETRY_COUNT + ") exceed !");
            }
        }
        bout.flush();
        return bout.toByteArray();
    }
  
    /**
     * Read a line of text.  A line is considered to be terminated by a line
     * feed ('\n') or a carriage return followed immediately by a linefeed.
     *
     * @return     A String containing the contents of the line, not including
     *             any line-termination characters, or null if the end of the
     *             stream has been reached
     *
     * @exception  IOException  If an I/O error occurs
     */
    private static final String read_line(InputStream in) throws IOException {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        boolean eof = false;
        while( true ) {
            int b = in.read();
            if (b == -1) { eof = true; break;}
            if ( b != '\r' && b != '\n' ) bout.write((byte)b);
            if (b == '\n') break;
        }
        bout.flush();
        if ( eof && bout.size() == 0 ) return null;
        //Or return ""; ? what's fit for you?
        return bout.toString();
    }        
}
-------------8><------------------------------------------------------------------

PS: 아래의 ByteUtil.java도 함께 참조 하세요.
18   parse int and long type from byte[]
http://www.javaservice.net/~java/bbs/read.cgi?m=devtip&b=javatip&c=r_p&n=953537896

-------------------------------------------------------  
  본 문서는 자유롭게 배포/복사 할 수 있으나 반드시
  이 문서의 저자에 대한 언급을 삭제하시면 안됩니다
================================================
  자바서비스넷 이원영
  E-mail: javaservice@hanmail.net
  PCS:011-898-7904
================================================