레이블이 TCP/IP인 게시물을 표시합니다. 모든 게시물 표시
레이블이 TCP/IP인 게시물을 표시합니다. 모든 게시물 표시

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);
}