기본 구조에 대한 설명
client 의 운영체제 의 수신속도 (kernel -> application ) 가 application 의 read 속도 보다 빠르면 장애가 날 확률이 높다.
파일 송신 서버 제작 (프로토콜이 없는 파일 송신)
//파일송신
char byBuffer[65536]; //64KB
int nRead, nSent, i = 0;
while ((nRead = fread(byBuffer, sizeof(char), 65536, fp)) > 0)
{
//파일에서 읽고 소켓으로 전송한다.
//전송에 성공하더라도 nRead와 nSent 값은 다를 수 있다!!!
nSent = send(hClient, byBuffer, nRead, 0);
printf("[%04d] 전송된 데이터 크기: %d\n", ++i, nSent);
fflush(stdout);
}
send 시에 1024 * 64 = 65536 (64KB) 만큼 전송했지만 이게 수신쪽에서 위에서 언급한것처럼 제대로 처리를 빠르게 못해서 다 안갈 수 있도 있다.
100을 보내도 50은 못보내는 경우도 있다.
파일 수신 클라이언트 제작
//수신할 파일을 생성한다.
puts("*** 파일 수신을 시작합니다. ***");
FILE *fp = NULL;
errno_t nResult = fopen_s(&fp, "Sleep away.zip", "wb");
if (nResult != 0)
ErrorHandler("파일을 생성 할 수 없습니다.");
//서버가 전송하는 데이터를 반복해 파일에 붙여 넣는다.
char byBuffer[65536]; //64KB
int nRecv;
while ((nRecv = ::recv(hSocket, byBuffer, 65536, 0)) > 0)
{
//서버에서 받은 크기만큼 데이터를 파일에 쓴다.
fwrite(byBuffer, nRecv, 1, fp);
putchar('#');
}
압축파일을 송수신 하게 되면 압축파일이 내부적으로 crc 체크를 해서 송수신간에 오류가 생겼는지 확인하게 된다.
마치 MD5 해쉬 값을 보내서 이 파일이 중간 손상되었는지 받은쪽에서 파일을 해쉬해서 게산한 해쉬값하고 받은 해쉬값하고 비교를 하게 된다.
보통의 경우 recv 가 write보다 항상 빠르다. network 속도 vs hdd(ssd) 속도의 차이이다.
Win32 API 기반 파일 송/수신
//파일송신
if ( ::TransmitFile(
hClient, //파일을 전송할 소켓 핸들.
hFile, //전송할 파일 핸들.
0, //전송할 크기. 0이면 전체.
65536, //한 번에 전송할 버퍼 크기.
NULL, //비동기 입/출력에 대한 OVERLAPPED 구조체.
&tfb, //파일 전송에 앞서 먼저 전송할 데이터.
0 //기타 옵션.
) == FALSE )
ErrorHandler("파일을 전송할 수 없습니다.");
//클라이언트가 연결을 끊을 끊기를 대기한다.
::recv(hClient, NULL, 0, 0);
puts("클라이언트가 연결을 끊었습니다.");
기존에 file read -> send 의 2가지 동작이 TransmitFile에 다 들어있다.
tfb는 파일명 , 사이즈 같은 미리 어떤 데이터를 송신할것인지 일종의 header처럼 보내게 된다.
//수신할 파일명, 크기 정보를 먼저 받는다.
MY_FILE_DATA fData = { 0 };
if (::recv(hSocket, (char*)&fData, sizeof(fData), 0) < sizeof(fData))
ErrorHandler("파일 정보를 수신하지 못했습니다.");
//수신할 파일을 생성한다.
puts("*** 파일 수신을 시작합니다. ***");
HANDLE hFile = ::CreateFileA(
fData.szName,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS, //파일을 생성한다.
0,
NULL);
if (hFile == INVALID_HANDLE_VALUE)
ErrorHandler("전송할 파일을 개방할 수 없습니다.");
수신하는쪽에서는 header를 먼저 읽어서 파일을 먼저 생성한 후에 실제 데이터를 읽어드리게 된다.
대표적인 TCP 장애 유형과 연결에 대한 정의
- Packet Loss = 패킷이 유실된 경우
- TCP Out of Order = 패킷의 순서가 뒤바뀐 경우
- Retransmission 과 Dup Ack
- Zero-window = 수신측 버퍼에 여유공간이 하나도 없는 경우
Zero window는 application이 빠르게 처리하지 못해서 발생하는 문제로 개발자가 해결해야하는 영역이고
나머지 위에4개는 network영역에서 해결해야하는 문제이다.
client측 os 에서 window 가 zero가고있다고 server에게 알려준다.
TCP 연결이라는 착각
- 재전송 타이머의 기본 근사 값은 대략 3초이나 대다수 운영체제들은 1초미만
- 재전송 타이머 만료시 세그먼트를 재전송하고 RTO(Retransmission Time-Out) 값은 두배로 증가
- 예를 들어 1초 > 2초 > 4초 > 8초 > 16초 간격으로 재전송
- 보통 최대 5회 재전송을 시도하고 5회 이상 모두 실패할 경우 보통 전송 오류가 발생
'Network > Windows 소켓 프로그래밍 입문에서 고성능 서버까지!' 카테고리의 다른 글
서버 성능 개선 (0) | 2023.11.28 |
---|---|
파일 송/수신과 프로토콜 설계 (0) | 2023.11.27 |
TCP 채팅 서버 - 성능 개선 (0) | 2023.11.22 |
TCP 채팅 서버 - 기본 이론 (0) | 2023.11.20 |
소켓 옵션과 필수 이론 (0) | 2023.11.19 |