|
예전의 ZMODEM이나 YMODEM, XMODEM, 커밋(?) 등은 TCP/IP라는 프로토콜 레이어단에서 작동 하던게 아니죠.
저도 지식이 미천하나마 제가 알고 있는 지식에서 UDP가 아닌 TCP/IP구조에서는 패킷 손실이나 패킷 전송 자체를
안정성을 보장 한다는 전제에서 만든 말그대로 테스트 프로그램입니다. 그래서 큰마음 먹고 올린다고 했죠 ^^;
사실은 님의 말씀처럼 좀 더 안전성이 보장된 소스를 강좌 형식으로 올리고 싶었지만 님께서 다른 방식의 파일전송을
원하시기에 이런류의 방식도 있다라고 제시 하고 싶은 마음에 좀 완성도가 떨어진 소스를 보내준 것 같네요. 하지만
나름대로 스레드블럭킹을 소개 한 것같아 조금은 낫지만 님의 말씀대로 패리티체크 개념을 넣으실려면 소스를 많이
변형 해야겠죠. 현재 스레드블럭킹은 데이타전송하는 역활만 하는데 그 패킷에 포함해서 처리 하려면
TWinSocketStream 에서 Read 해서 처리를 해야 할 것 같네요. 저는 단지 스레드블럭킹의 소개 정도로 생각 해주시면
님이 원하시는 답이 될것이라는 생각이였습니다. 주저리 주저리 말만 많이 적었는데 시간 나면 다시 한 번 정리 해서
올리도록 하죠. 다시 한 번 말씀드리지만 큰맘 먹었다는 얘기는 인심 크게 쓰겠다는 뜻이 아니고 제대로 준비는 덜 되었
지만 도움이 될거라는 생각에 적은것입니다. ^^;
굳이 덧붙인다면 저 예제 소스에서 조금 응용해서 현재도 실무에 잘쓰고 있답니다. 다시 한 번 시간이 허락 한다면
여러가지 보완된 소스를 정리 좀 해서 다시 올려 드릴께요. 그럼 즐코~ 하세요!
장성호 님이 쓰신 글 :
: 감사합니다
: NonBlocking ThreadBlocking 에 대해서는 많은 도움이 된것 같습니다.
:
: 그런데 님에 code에도 전송되는 Data에 전송중에 Data가 변형되거나 깨어지거나 하는 경우는 고려가 되어있지 않네요
:
: 1024Byte씩 전송하고 있는데 수신측에 Data가 송신측의 Data와 100% 항상 똑같다고 할수는 없잖아요?
:
: 제 경우 파일전송부분에 CheckSum을 추가했습니다.
: ------------------------------------------------------------------------------
:
: #define MAX_BUFFER_SIZE 1024
:
: void __fastcall TFileSendThread::Execute()
: {
: TFileStream* pStream;
: char pBuff[MAX_BUFFER_SIZE];
: int nCopySize;
: char chkSum;
: Main->Pb_Tx->Position = 0;
: String fname=ExtractFileName(TxFileName);
: int fsize,txsize=0;
: try
: {
: pStream = new TFileStream(TxFileName, fmOpenRead);
: fsize= pStream->Size;
: Main->Pb_Tx->Max = pStream->Size;
: Main->ClientSocket->Socket->SendText(fname + "," + IntToStr(pStream->Size)+"@");
: while (true)
: {
: nCopySize = pStream->Read(pBuff, MAX_BUFFER_SIZE);
: txsize+=nCopySize;
: chkSum=pBuff[0];
: for(int i=1;i<nCopySize;i++) chkSum=chkSum^pBuff[i]; //체크섬을 만든다.
:
: pBuff[nCopySize] =chkSum;
: pBuff[nCopySize+1] = '\0';
:
: if (nCopySize != 0)
: Main->ClientSocket->Socket->SendBuf(pBuff, MAX_BUFFER_SIZE+1); //1024+1 Byte씩 전송
: else
: break;
: }
:
: Application->ProcessMessages();
:
: if(Main->ErrPacket->Count>0)
: {
: int packet=StrToInt(Main->ErrPacket->Strings[0]);
: pStream->Seek(packet*1024,soFromBeginning );
: nCopySize = pStream->Read(pBuff, MAX_BUFFER_SIZE);
: chkSum=pBuff[0];
: for(int i=1;i<nCopySize;i++)
: chkSum=chkSum^pBuff[i];
:
: pBuff[nCopySize] =chkSum;
: pBuff[nCopySize+1] =packet/256;
: pBuff[nCopySize+2] =packet%256;
:
: pBuff[nCopySize+3] = '\0';
: Main->ClientSocket->Socket->SendBuf(pBuff, nCopySize+3); //1024+3Byte씩 전송
: Main->ErrPacket->Delete(0);
: }
: }
: __finally
: {
: delete pStream;
: }
:
: Main->ClientSocket->Socket->SendText("");
: Main->Memo_Tx->Lines->Add("파일송신 끝");
: Main->Memo_Tx->Lines->Add("파일Size:"+IntToStr(fsize));
: Main->Memo_Tx->Lines->Add("파일TxSize:"+IntToStr(txsize));
: }
: --------------------------------------------------------------------------
: ---------------------수신측에서는 -----------------------------------------
:
: 전체 수신Data에서 맨마지막 Data까지 XOR를 한후에 그것과 맨마지막 Byte와 비교합니다.
: 여기서 똑같지 않으며 다시 전송해달라고 요청하지요
: 송신측에서는 재전송요청 Message를 위에 code에서는 ErrPacket이라는 TStringList에 담아둡니다.
:
: -------------------------------------------------------------------------
: Error는 종종발생하더라구요
: 송수신측 모두 Local이거나 File크기가 작을때는 적게 나타나는데
: File 크기가 커질수록 자주 나타나더라구요
:
:
:
: 이점한 님이 쓰신 글 :
: : 사람들은 TServerSocket의 쓰레드블럭킹의 강력함을 잘 모르더군요.
: : 우리나라에서는 소스 조차 찾기 힘들고 외국 소스 몇개 참조 했는데
: : 제대로 정리해서 강좌식으로 올리려고 작년부터 마음 먹었었는데 시간이 안되
: : 못올리는군요. 아예 소스를 첨부 할테니 내용 참조 하세요.
: : TServerSocket의 쓰레드 블럭킹 예제입니다.
: : 소스 내의 디렉토리 몇개는 바꾸셔야 할것입니다. 다운 로드 폴더를 임의로 "C:\temp"로 했거든요.
: : 바로 쓰실려면 아마 "C:\temp"라는 디렉토리 만들어 두셔야 할 것입니다.
: : 현재 피시방 관리프로그램이랑 휴대폰 결제 프로그램에 응용해서 사용 되고 있는 루틴입니다.
: : Project1은 쓰레드블럭킹을 이용하는 서버구요. Project2는 클라이언트입니다.
: : 쓰레드에서 스트리밍 전송이 되기 때문에 여러 사용자 동시 다운로드도 가능합니다.
: : 보통 NonBlocking으로 하면 다운로드 중에 다른 사용자가 다운로드 시도하면 첫번째넘은 일시정지
: : 되는데 쓰레드 블럭킹은 전혀 그런것 없습니다.
: :
: : 일단 소스 첨부 해드릴테니깐 잘 참조 하세요. 생각외로 소스는 간단하답니다.
: :
: : 앞으로 시간이 되면 스레드블럭킹에 대한 자세한 강좌를 약속드리며....
: :
: : 참 구글 같은데서 "ClientSocket->"이거나 "TMyServerThread" 이거로 검색 하시면 제꺼와
: : 유사한 소스는 몇개 찾으실겁니다. 주로 일본이나 미국 볼랜드포럼 개발자 사이트가 많이 나오더군요.
: :
: :
: : 장성호 님이 쓰신 글 :
: : : 안녕하세요
: : : 소켓으로 파일 전송하고자 합니다.
: : : (참고할수 있는 자료나 책같은것이라도 소개 좀 부탁드립니다.)
: : :
: : : C++Builder의 TServerSocket과 TClientSocket을 쓰고있습니다.
: : :
: : : 맨처음 File Name과 File Size를 전송합니다.
: : :
: : : 그다음 File을 일정한 크기(1024BYte)씩 짤라서 전송합니다.
: : : 그런데 가끔 전송중간에 Error가 나는수 있더라구요
: : : 그것을 확인하기 위해 Data맨뒤에 CheckSum을 1Byte추가했습니다.
: : : CheckSum은 모든Data를 XOR했구요
: : :
: : : Data를 수신한후 CheckSum에 문제가 있으면
: : : 해당Packet을 다시 전송해달라고 송신측에 메세지를 보냅니다.
: : :
: : : 송신측에서는 재전송요청을 받으면
: : : 해당Packet의 Data+CheckSum+Packet번호 를 송신합니다.
: : : Packet번호는 2Byte입니다.
: : :
: : :
: : : 즉 일단 file을 모두 전송한후에
: : : 저쪽에서 error가 있다는 부분만 다시 전송해주는 구조입니다.
: : :
: : : [한번에 전송되는 data구조 1,2,3]
: : : 1 - FileName+FileSize ==> 맨처음에 file에 대한 정보를 전송한다.
: : : 2 - Data+CheckSum ==> 다음. 일정크기+1Byte =1025Byte 씩 data를 전송합니다.... File끝까지
: : : .
: : : .
: : : 3 - Data+CheckSum+Packet번호 ==>마지막으로 일정크기+1Byte+2Byte=1027Byte error packet을 전송합니다.
: : :
: : : 전송종료는 data를 모두 전송후에 일정시간(2초)이상 error패킷에 대해 재전송 요청이 없으면
: : : 전송을 마무리하구요
: : :
: : : 수신측에서는 Data를 완벽하게 수신했거나 에러packet이 있을경우 송신측에서 일정시간 전송해주시 않으면
: : : 그냥 수신실패한것으로 마무리 합니다.
: : :
: : :
: : : 문제점과 의문나는점은?
: : :
: : : 1) 재전송요청한 packet에서 계속반복해서 Error가 나는경우가 있구요
: : : 2) 처음 file전송시(2번)에는 data에 대한 packet번호를 수신측에서 차례대로 수신한다고 생각하고
: : : 함께 전송하지 않습니다.--> 그래도 되는지...?
: : : 3) 송신측에서 전송중에 재전송요청을 받았을때.. 그 부분부터 다시보내는것이 좋을런지...?
: : : 4) 보통 메신져(MSN이나 NateOn 같은데)에서는 어떻게 하는지?
: : : 5) CheckSum 만드는 더좋은 방법이 있으면 소개좀 부탁드립니다.
: : : 6) 마지막을 ZModem처음 전송되는 Packet의 크기를 가변적으로 하려면 어떻게 해야하죠?
: : : 에러가 없으면 점점 전송되는 packet의 크기가 커지는것으로 알고잇는데.... (너무 막연한 질문인가?)
: : :
: : : 목표
: : : 가능한한 최대한 빠르게 파일이 전송 되어야합니다.
: : : 그럴러면 전송되는 data에 Header가 적어야겠죠(반드시 그렇지는 않겠지만)
: : : 그리고 당연히 수신file에 1Byte라도 error는 없어야겠구요?
: : : 마지막으로 수신측에서도 Acknowledge같은것도 최대한 적게 보내야 합니다.
: : : XMODEM이나 YMODEM같은경우는 한번수신할때만다 Acknowledge를 보내는것으로 알고있습니다.(맞나?)
: : :
: : : 참고로 이 파일전송 부분은 직접구현해야합니다.
: : : FTP나 다른 컴포넌트를 이용할수 없습니다.
|