네트워크

[네트워크] 프로토콜 적용 파일 클라

program-yam 2025. 4. 22. 14:37

프로토콜이 적용된 파일 클라를 작성해보자.

 

if (::connect(hSocket,
	(SOCKADDR*)&svraddr, sizeof(svraddr)) == SOCKET_ERROR)
{
	ErrorHandler("서버에 연결할 수 없습니다.");
}		

//서버로부터 파일 리스트를 수신한다.
GetFileList(hSocket);

//전송받을 파일을 선택하고 수신한다.
GetFile(hSocket);

 

클라에서는 서버와 연결이 성공하면 서버로부터 파일 목록을 수신하고,

파일을 선택하여 서버로부터 파일을 수신한다.

 

GetFileList

void GetFileList(SOCKET hSocket)
{
    //서버에 파일 리스트를 요청한다.
    MYCMD cmd = { CMD_GET_LIST, 0 };
    ::send(hSocket, (const char*)&cmd, sizeof(cmd), 0);

    //서버로부터 파일 리스트를 수신한다.
    ::recv(hSocket, (char*)&cmd, sizeof(cmd), 0);
    if (cmd.nCode != CMD_SND_FILELIST)
    {
        ErrorHandler("서버에서 파일 리스트를 수신하지 못했습니다.");
    }		

    SEND_FILELIST filelist;
    ::recv(hSocket, (char*)&filelist, sizeof(filelist), 0);

    //수신한 리스트 정보를 화면에 출력한다.
    FILEINFO fInfo;
    for (unsigned int i = 0; i < filelist.nCount; ++i)
    {
        ::recv(hSocket, (char*)&fInfo, sizeof(fInfo), 0);
        printf("%d\t%s\t%d\n",
            fInfo.nIndex, fInfo.szFileName, fInfo.dwFileSize);
    }
}

 

서버에 파일 목록을 수신받는다.

 

GetFile

void GetFile(SOCKET hSocket)
{
    int nIndex;
    printf("수신할 파일의 인덱스(0~2)를 입력하세요.: ");
    fflush(stdin);
    scanf_s("%d", &nIndex);

    //1. 서버에 파일 전송을 요청
    BYTE *pCommand = new BYTE[sizeof(MYCMD) + sizeof(GETFILE)];
    memset(pCommand, 0, sizeof(MYCMD)+sizeof(GETFILE));

    MYCMD *pCmd = (MYCMD*)pCommand;
    pCmd->nCode = CMD_GET_FILE;
    pCmd->nSize = sizeof(GETFILE);

    GETFILE *pFile = (GETFILE*)(pCommand + sizeof(MYCMD));
    pFile->nIndex = nIndex;
    //두 헤더를 한 메모리에 묶어서 전송한다!
    ::send(hSocket,
        (const char*)pCommand, sizeof(MYCMD) + sizeof(GETFILE), 0);
    delete [] pCommand;

    //2. 전송받을 파일에 대한 상세 정보 수신.
    MYCMD cmd = { 0 };
    FILEINFO fInfo = { 0 };
    ::recv(hSocket, (char*)&cmd, sizeof(cmd), 0);
    if (cmd.nCode == CMD_ERROR)
    {
        ERRORDATA err = { 0 };
        ::recv(hSocket, (char*)&err, sizeof(err), 0);
        ErrorHandler(err.szDesc);
    }
    else
    {
        ::recv(hSocket, (char*)&fInfo, sizeof(fInfo), 0);    
    }
		

    //3. 파일을 수신한다.
    printf("%s 파일 수신을 시작합니다!\n", fInfo.szFileName);
    FILE *fp = NULL;
    errno_t nResult = fopen_s(&fp, fInfo.szFileName, "wb");
    if (nResult != 0)
    {
        ErrorHandler("파일을 생성 할 수 없습니다.");
    }		

    char byBuffer[65536]; //64KB
    int nRecv;
    DWORD dwTotalRecv = 0;
    while ((nRecv = ::recv(hSocket, byBuffer, 65536, 0)) > 0)
    {
        fwrite(byBuffer, nRecv, 1, fp);
        dwTotalRecv += nRecv;
        putchar('#');

        if (dwTotalRecv >= fInfo.dwFileSize)
        {
            putchar('\n');
            puts("파일 수신완료!");
            break;
        }
    }

    fclose(fp);
}

 

서버로부터 받은 파일 목록 중에서 원하는 파일을 선택하고,

기본 헤더와 CMD_GET_FILE을 동적할당 받은 메모리에 쓰고 서버로 전송한다.

 

이후 서버로부터 파일 정보를 헤더로 받고, 파일을 서버로부터 수신한다.