C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[44289] 파일 수신시 패킷 오류 관련(스레드 서버 소켓)
mani [] 1319 읽음    2006-03-27 18:06
클라이언트가 파일을 보내면 서버가 받아서 저장하는 프로그램을 만들고 있습니다.
서로 주고 받는 것은 구조체 형태로 받고 있고요
구조는
#pragma pack(1)
typedef struct  {
    unsigned long  Length ; //Packet 총 길이에서 Packet Header 길이 제외
    unsigned long  File_TotLength ;//요청한 파일의 total length
    unsigned long  SentLength ; //현재까지 수신한 파일의 length

} SendHeader ;

#pragma pack(1)
typedef struct  {
    char FileStream[4096] ; //MP3 Stream Data

} SendFile ;

이렇게 헤더와 바디를 따로 구분해서 보내고 받습니다.

근데 수신을 받다 보면 패킷이 이상하게 들어 옵니다.
헤더가 안들어 오고 바로 바디가 들어 오네요....

보내는 로직
       SendHeader  sSendHeader  ;
SendFile sSendFile ;
        filestream = new TFileStream(Filename ,fmOpenRead) ;

        filestream->Seek( 0 , soFromBeginning) ;
        FileLength = filestream->Size ;
        Cnt = (FileLength / 4096) + 1 ;

        for (int Loop1 = 0 ; Loop1 < Cnt ; Loop1 ++)
        {
            if (SendGo == false)
            {
                ClientSocket1->Active = false ;
                break ;
            }
            memset(&sSendHeader , 0 , sizeof(sSendHeader)) ;

            if (FileLength - (Loop1 * 4096) > 4096)
                SendLength = 4096 ;
            else
                SendLength = FileLength - (Loop1 * 4096) ;

            filestream->Read(&sSendFile.FileStream ,SendLength ) ;
            sSendMP3Header.Length = SendLength ;
            sSendMP3Header.File_TotLength = FileLength ;
            sSendMP3Header.SentLength = ((Loop1 * 4096) +SendLength)  ;
            ClientSocket1->Socket->SendBuf(&sSendHeader , sizeof(sSendHeader)) ;
            ClientSocket1->Socket->SendBuf(&sSendFile , sizeof(sSendFile)) ;

            if (Loop1 != Cnt-1)
                filestream->Seek(0 , soFromCurrent) ;
            Sleep(1) ;
        }
    }

클라이언트에서 이렇게 보냅니다.

서버에서는 파일 길이를 다 받을 때까지 루프를 돌면서 헤더와 바디를 구분합니다.
클라이언트가 3개 정도 붙으면 문제가 안되는데 4개 이상붙으면 헤더값이 이상한게 들어 오는 넘들이 있습니다.
아래 소스 보시면 아시겠지만

                if (RcvLength <= 0 || RcvLength > 4096)
                {
                    SocketWrite_Log("[패킷 오류]" , 1) ;       //  RcvLength 가 4096 이상이 될 수가 없슴          
                    RecieveEnd = true ;
                    break ;
                }

RcvLength 는 4096이 넘을 수 없습니다.
근데 패킷을 받다보면 터무니 없는 값(억단위가 넘는 값이죠..-_-)이 들어 옵니다.
그래서 확인한 결과 바디에 와야 할 내용이 헤더로 들어 오고 있다는 것을 알게 되었습니다.

근데 지금까지 받은 바디 사이즈 그리고 전체 패킷 사이즈를 기록해 봤는데
패킷오류가 나는 시점에서도 사이즈는 정상 입니다.
예를 들면 바디사이즈는 4096으로 나누면 값이 딱 떨어 집니다.
전체 패킷 값도 4108 로 나누면 나머지가 12가 남습니다
여기서 12는 헤더 정보를 받아 온 후이기 때문에 12가 남는것은 당연한 것이구요...

혹시 제가 발견하지 못한 오류나 아니면 생각지도 못했더 로직상의 오류가 있는지 모르겠네요...

며칠째 이거 가지고 씨름하다가 이렇게 글을 올립니다.

고수님들의 도움 부탁 드립니다.

서버에서는 아래와 같이 받아 옵니다.

       String sFilename ;
      sFilename = "c:\a.txt" ;

        if (!FileExists(sFilename))
            sFileHandle = FileCreate(sFilename) ;

        RecieveEnd = false ;
        SocketWrite_Log("[수신시작" , 1) ;
        RcvYn = "N" ;

       SendFile sSendFile ;
       SendHeader sSendHeader ;

    int fFileSize = 0 ;
    int NowLength ;
    int TotalRcvPackLen = 0 ;
    char *tmpBuffer      ;
    tmpBuffer =  new char[sizeof(sSendHeader )+1] ;
    char tmpBuffer3[sizeof(sSendHeader )] ;
    char tmpBuffer4[sizeof(sSendFile)] ;
    char *tmpBuffer2 ;
    tmpBuffer2 = new char[sizeof(sSendFile)+1] ;

    while (!RecieveEnd)
    {
        try
        {
            memset(tmpBuffer3, 0x0, 12);
            memset(&sSendHeader , 0x0 , 12) ;
            memset(tmpBuffer , 0x0 , 13) ;
            NowLength = 0 ;
            LoopCnt = 1 ;
            try
            {
                while ( NowLength < sizeof(sSendHeader ))
                {
                    try
                    {
                        BufferSize = pStream->Read(tmpBuffer, (sizeof(sSendHeader ) - NowLength)) ;
                    }
                    catch(Exception &E)
                    {
                        ClientSocket->Close();
                        RecieveEnd = true ;
                        break ;
                    }

                    if( BufferSize == 0)   // 입력된 값이 없으면 종료
                    {
                        if (LoopCnt == 1000)
                        {
                            ClientSocket->Close();
                            RecieveEnd = true ;
                            break ;
                        }
                        LoopCnt+= 1 ;

                        try
                        {
                            WaitForSingleObject((HANDLE)Handle , 10) ; //약간의 Sleep을 주기 위해 사용
                        }
                        catch(...)
                        {
                            ::Sleep(10) ;
                        }
                        continue ;
                    } else
                    {

                        memcpy((void *)&tmpBuffer3[NowLength] , (void *)&tmpBuffer[0] , BufferSize) ;
                        NowLength = NowLength  + BufferSize ;
                        if ( NowLength == 12)
                            break ;
                        try
                        {
                            WaitForSingleObject((HANDLE)Handle , 2) ;
                        }
                        catch(...)
                        {}
                    }

                }
                if (RecieveEnd)
                {
                    break ;
                }
                TotalRcvPackLen = TotalRcvPackLen + 12 ;
                Move(tmpBuffer3 , &sSendHeader , 12) ;

                SaveFileLenth = sSendHeader.SentLength ;
                RcvLength = sSendHeader.Length ;
                TotalLength = sSendHeader.File_TotLength ;

                if (RcvLength <= 0 || RcvLength > 4096)
                {
                    SocketWrite_Log("[패킷 오류]" , 1) ;       //  RcvLength 가 4096 이상이 될 수가 없슴          
                    RecieveEnd = true ;
                    break ;
                }
            }
            catch(Exception &E)
            {
                RecieveEnd = true ;
                break ;
            }

            NowLength = 0 ;
            LoopCnt = 1 ;
            memset(&sSendFile , 0x0 , sizeof(sSendFile)) ;
            memset(tmpBuffer4 , 0x0 , sizeof(sSendFile)) ;
            memset(tmpBuffer2, 0x0, sizeof(sSendFile)+1);
            try
            {
                while ( NowLength < RcvLength)
                {
                    try
                    {
                        BufferSize = pStream->Read(tmpBuffer2, RcvLength - NowLength) ;
                    }
                    catch(Exception &E)
                    {
                        ClientSocket->Close();
                        RecieveEnd = true ;
                        break ;                       
                    }
                    if ( BufferSize == 0)
                    {
                        if (LoopCnt == 1000)
                        {
                            ClientSocket->Close();
                            RecieveEnd = true ;
                            break ;
                        }
                        LoopCnt+= 1 ;

                        try
                        {
                            WaitForSingleObject((HANDLE)Handle , 10) ;
                        }
                        catch(...)
                        {
                            ::Sleep(10) ;
                        }
                        continue ;

                    }
                    else
                    {

                        memcpy((void *)&tmpBuffer4[NowLength] , (void *)&tmpBuffer2[0] , BufferSize) ;
                        fFileSize = fFileSize + BufferSize ;
                        NowLength = NowLength + BufferSize ;
                        if ( NowLength ==  RcvLength)
                            break ;
                        //::Sleep(10) ;
                        try
                        {
                            WaitForSingleObject((HANDLE)Handle , 1) ;
                        }
                        catch(...)
                        {}
                    }
                }
            }
            catch(Exception &E)
            {
                RecieveEnd = true ;
                break ; 
            }
            TotalRcvPackLen = TotalRcvPackLen + NowLength ;
            Move(tmpBuffer4 , &sSendFile , NowLength) ;
            try
            {
                FileSeek(sFileHandle,0,2);
                FileWrite(sFileHandle, sSendFile.FileStream , RcvLength ) ;
            }
            catch(Exception &E)
            {
                RecieveEnd = true ;
            }
           
            if (FileLength == fFileSize )
            {
                RecieveEnd = true ;
            }
            try
            {
                WaitForSingleObject((HANDLE)Handle , 10) ;
            }
            catch(...)
            {
                ::Sleep(10) ;
            }           

        }
        catch ( Exception &except )
        {
            ClientSocket->Close();
            ErrorCode = "4" ;
            RecieveEnd = true ;
        }
    }
    FileClose(sFileHandle);

+ -

관련 글 리스트
44289 파일 수신시 패킷 오류 관련(스레드 서버 소켓) mani 1319 2006/03/27
44299     [자답]파일 수신시 패킷 오류 관련(스레드 서버 소켓)... 그러나 또 다른 문제...-_- Mani 1498 2006/03/28
44291     Re:파일 수신시 패킷 오류 관련(스레드 서버 소켓)- 좀더 자세한 원인 발견... Mani 1176 2006/03/27
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.