2014년 11월 13일 목요일

CAsyncSocket의 OnReceive 함수에서 패킷을 받을 때 주의사항

 Socket 통신을 이용해서 프로그래밍을 할때, 패킷 정보에 앞에 헤더(id, 패킷의 길이)를 넣어서 많이 사용한다. 처음에는 패킷을 받을 OnReceive 함수에서 Receive를 두번 호출하여, 먼저 헤더를 받고, 헤더에서 패킷길이 만큼 받게 사용하였다. 이렇게 했을 경우 10ms에 한번 패킷을 보내면, 100000번 내외에서 랜덤하게 패킷을 못받게 되는 현상이 발생한다. OnReceive가 CAsyncSocket 클래스의 가상함수 인데, 여기서 Receive를 두번이상 호출 하면 안정성 보장이 안된다고 한다.
 이렇게 사용 안하려면, 패킷을 받기전에 패킷의 길이 부터 파악할 수 있어야 하는데, afxsock.h에서는  패킷의 길이를 파악할 수 있는 함수(IOCtl)를 제공한다. 실제 사용은 아래와 같이 하면된다.
[-] Collapse
void CClientSocket::OnReceive(int nErrorCode)
{
    // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
    //Receive를 분할 수신하면... 랜덤하게 100000번 내외에서 못받음 현상발생
    DWORD dwReadLen;
    IOCtl(FIONREAD, &dwReadLen); //패킷 길이를 먼저 파악하고
    char* szReceBuff = new char[dwReadLen];
    int nReadLen = 0;
    nReadLen = Receive( szReceBuff, dwReadLen ); //한번에 다받아야 한다..

    int header[2];
    memcpy(header,szReceBuff,sizeof(int)*2); //한번에 받고나서 헤더를 분리하고

    if(header[0]==Command::Grab) //헤더의 내용(id,길이)에 따라..
    {
        memcpy(&GrabInfo,&szReceBuff[2*sizeof(int)/sizeof(char)],header[1]);
        //받은후 작업 추가.
    }
    delete szReceBuff;
    CAsyncSocket::OnReceive(nErrorCode);
}

댓글 4개:

  1. 감사감사~~~ 꾸벅~~~
    패킷길이를 알고 싶었는디....^^

    답글삭제
  2. 혹시 .. 해당현상이 발생됬을때, 이후에 오는 Packet에 대해서도 처리를 못하던가요?

    답글삭제
    답글
    1. 오래 되서 기억이 잘 나지 않지만.. 패킷이 아예 안날라 오는것은 아니엇고, 잘린 후에 다시 날라왔던거 같습니다. 만약 잘린 패킷과 이전에 받은 패킷을 연결하는 걸 만들면 되겠지만.. 복잡해서.. 한꺼 번에 받아 왔었습니다.. 제가 했던게 문자열 몇줄 받는 목적의 통신이라.. 참고하세요.

      삭제