리눅스와 윈도우 간에 소켓통신(파일 전송) -해결
볼수록매력
파일 전송을 하는데 보내는쪽은 윈도우고 받는쪽은 리눅스입니다.
보내는쪽(윈도우)은 버퍼출력스트림을 쓰고
toclientfile = new bufferedoutputstream(new dataoutputstream(socket.getoutputstream()) );
아래 소스로 파일을 전송합니다.
// 4k씩 보내는데 처음 3바이트의 첫번째는 그냥 0 , 두번째와 세번째는 파일의 패킷의 크기를 보냅니다.
// 그리고 파일에서 4093바이트씩 읽어서 보내는데, 파일 마지막에 4093이 안될경우 그냥 쓰레기값으로 4케이 채워서 보냅니다.
// 처음 3바이트 + 파일에서 읽은 4093바이트 해서 4096바이트씩 보냅니다.
//그리고 마지막에 3바이트만 보내 파일전송의 끝을 알립니다.
bufferedinputstream fromfile = new bufferedinputstream( new fileinputstream(sendfile));
int len = 0;
int buffersize = 4096;
byte[] buffer = new byte[buffersize];
buffersize -= 3;
while( (len = fromfile.read(buffer, 3, buffersize) ) != -1 ){
buffer[0] = (byte)0x00;
buffer[1] = (byte)((len0) & 0xff);
buffer[2] = (byte)((len8) & 0xff);
//system.out.println(size= +len); 파일 사이즈를 바이트로 변환
len = ((int)buffer[2]&0xff)8 | ((int)buffer[1]&0xff)0;
//system.out.println(check size= +len);잘 변환됫는지 확인
toclientfile.write(buffer,0, 4096);
toclientfile.flush();
}
//아래 부분 3바이트는 파일 전송이 완료됐다는걸 알리는 부분입니다.
buffer[0] = (byte)0x00;
buffer[1] = (byte)0x00;
buffer[2] = (byte)0x00;
toclientfile.write(buffer,0, 3);//000이 아니면 끝이 아님(패킷손실?)
toclientfile.flush();받는쪽은 리눅스인데..
//4k씩 받아서 처음 3바이트는 파일 크기를 알아내고 파일크기만큼 파일에 씁니다.
//파일전송중이면 4093바이트씩 파일에 씁니다.
//보내온 패킷이 4096이 안될경우는 처음 3바이트를 조사하여 0 0 0 이 되면 파일 끝
//
fromserverfile = new bufferedinputstream(new datainputstream(socket.getinputstream()));
tofile = new bufferedoutputstream(new fileoutputstream(file));
boolean isend = true;
int missingcount = 0; //exception이 날 경우 +1 된다.
while( isend ){
if((fromserverfile.read(buffer) ) == 4096){
len = ((int)buffer[2]&0xff)8 | ((int)buffer[1]&0xff)0;
//system.out.println(size: +len+ buffer: +buffer.length);
try{
tofile.write(buffer,3,len);
tofile.flush();
}catch (exception e) {
system.err.println([java]file recieve error: +
file.getname()+ size: +len);
e.printstacktrace();
if(missingcount5){
system.err.println([java]error network);
break;
}
missingcount++;
}
}else{
isend = !( (buffer[0] == (byte) 0x00) &&
(buffer[1] == (byte) 0x00) &&
(buffer[2] == (byte) 0x00) ) ;
system.out.println( buffer[0] + +buffer[1] + +buffer[2]+ +isend );
missingcount++;
if(missingcount7){
break;
}
}
}근데 윈도우에서 같은 프로그램을 실행시키면 잘 되는데..
리눅스-윈도우 간에 실행시키면 될때도 있고 안될때도 있네요-_-;;
에러가 날때는 파일 크기를 알려주는 byte[0], byte[1], byte[2]의 값이 이상한 값이 오는데..-_-;;
왜 그런건지 당체 모르겠습니다.
파일 전송의 끝을 보통 방식처럼 -1로 안한건 소켓연결유지상태서 여러 파일을 전송하기 위해서입니다.
조언 부탁드립니다.
-
게자리
흐;; 주말이니 좀 더 연구해봐야겠네요.
-
꽃짱아
OS마다 버퍼의 크기가 다르기 때문에 그렇습니다.
그리고 windows도 꼭, 4096으로 잘라서 보내지 않습니다.
( 네트워크 관련 책에 보면 나와 있지요. API에도 그렇게 적혀 있고.. )
그러니 시간이 되신다면 잠깐 짬을 내어 지금 고치시는것이 더 좋을듯 해 보입니다. ^^;;; -
든해솔
훈훈한글이네요 ㅎㅎ
-
데빌의눈물
찬님 말씀이 맞네요. 원인은 2번이 확실합니다.
if((fromServerFile.read(buffer) ) == 4096){ 이 부분을
if( (readCount= fromServerFile.read(buffer) ) == 4096){ 이렇게 변경하고 에러가 날때
readCount 를 출력하니 2896이 나오네요.
다음 패킷부터는 2897번째 비트부터 4096으로 짤라서 보내니 알 수 없는거 였습니다.
다른 환경에서는 어쩔지 모 -
홀림길
2. 송신측에서 4096으로 보낸다고 해서, 수신측에서 4096으로 받으라는 보장은 절대 없습니다.
그러므로 저렇게 해서는 문제가 발생할 가능성은 언제든지 존재합니다.
아마도 될때도 있고 안될때도 있고 하는 것은, 2번의 문제 때문에 발생하는것으로 보이네요.
꼭 4096만큼 읽어야 한다면,
그냥 readCount와 readBuffer를 두어서, 아직 도착한 데이터가 4096바이트 보다 작으면,
readBuffer에 쌓아 두셨다가, 쌓아둔 데이터가 4 -
흰양말
그리고 미치겟는건..아싸리 안된려면 계속 안되거나.. 되면 계속 되야되는데..될때도 있고 안될때도 있어서... ㅠ_ㅠ
-
가자
찬님 //1. 일단 VM이 틀립니다. ㅠ_ㅠ 임베디드라서 cee-j vm을 사용합니다.(일반 버전으론 1.42정도)
2. 수신부에 byte buffer[] = new byte[4096]; 이 부분이 빠져서 헷갈리셧는지도.. 송신측에서 파일전송시에는 무조건 4096으로 보내고 flush하기 때문에 받는쪽에서도 파일받을때는 무조건 4096씩 받는거라고 가정했습니다.
3. buffer[0]~[2]까지는 헤더부분이라 보낼때 그 부분엔 파일의 내용을 -
보늬
같은 java vm끼리면, 문제가 안 되지 않을까요? 잘 모르겠습니다. ^^
제가 궁금한건
받는 쪽 소스의
while( isEnd ){
if((fromServerFile.read(buffer) ) == 4096){
이 부분이 좀 이상해 보입니다.
formServerFile에서는 read를 하면 4096이 나올 수도 있고 안 나올 수도 있습니다.
( buffer에 읽어 들인 양을 반환하기 때문에 )
만약 4096이 안나온다고 해서 b -
오나미
감사합니다. 아 이제 저걸 어떻게 통일하냐가 문제군요.. nio에서는 바이트오더를 제어해주던데.. 임베디드라 제한되어있는 함수만 있으니..노력해봐야겠습니다+_+
-
솔관
이건 빅엔디안이냐 리틀엔디안이냐 문제네요. 네트웍으로 데이터를 전송할 때 CPU마다 byte stream방식이 틀려 생기는 문제입니다.