파일 전송시 버퍼 질문입니다,
글쓴이: 익명 사용자 / 작성시간: 월, 2011/09/19 - 1:30오후
프로토콜중 파일전송 프로토콜이 있습니다.
sync등을 하여 파일전송 준비를 하고 보내고 받고 하는 부분인데
파일 전송은 정상적으로 됩니다.(파일전송 -> 서버 파일받는곳 -> 클라이언트 )
파일 전송 write 다하게 되면 서버는 바로 다 보냈다는 end프로토콜을 날립니다.
근데 클라이언트 측에서는 파일전송의 마지막 버퍼와 end 프로토콜이 합쳐진 값이 들어와서 파일이 깨지게 됩니다.
하지만 파일 전송 완료 후 sleep(1)을 주게 되면 문제가 없습니다.
이를 미루어 서버측에서는 순차적으로 잘 보내나 클라이언트 측에서 받을때 버퍼가 밀려있을경우 합쳐서 받는것 같은데..
제가 생각하고 있는게 맞나요? 또한 이 문제를 해결하려면 어떻게 처리를 해야되나요?
함수는 write와 read를 사용하였습니다.
Forums:
파일 전송전에 파일의 크기를 따로 전송한 후 내용을
파일 전송전에 파일의 크기를 따로 전송한 후 내용을 전송하고, 받는 쪽에서 그 크기만큼 받는 것으로 완료되었다고 약속하는 것이 낫습니다.
그렇게 처리 하였습니다. 제 질문을 자세히
그렇게 처리 하였습니다.
제 질문을 자세히 읽어보시면 받는쪽에서는 순차적으로 패킷을 보내는데 파일 끝까지
보내는 측에서는 그걸 순차적으로 차례차례 받는건 아닌것 같습니다.
마지막에도 마지막 파일 크기 까지만 보내주지만 받는측에서 찍어보면 마지막 파일 크기 + 파일 전송 종료 패킷을 합한 것이
한번의 read에 들어옵니다..
TCP가 원래 그렇습니다. 파일 길이에 맞게 받은
TCP가 원래 그렇습니다. 파일 길이에 맞게 받은 데이터를 잘 나눠서 처리해주시면 됩니다.
TCP를 사용하고 계시겠지요? TCP는 데이터 스트림 서비스를 제공한다고들 합니다. 반면 UDP는 데이터그램 서비스를 제공한다고 하구요.
그래서 UDP에서는 데이터를 send 하면 그 덩어리 그대로 상대에게 전달됩니다. 받는 쪽에서 recv 하면 그 덩어리를 통째로 받거나 아무 것도 못 받거나 합니다.
반면 TCP에서는 그런 전달 단위가 없습니다. 바이트와 바이트가 줄을 지어서 상대에게 전달될 뿐입니다. (즉 전달 단위가 바이트입니다.) 따라서 보내는 쪽에서 10바이트씩 두 번 send를 했더라도 받는 쪽에서는 한 번의 recv로 20바이트 모두를 받을 수도 있고 두 번의 recv로 10바이트씩 받을 수도, 두 번의 recv로 15바이트와 5바이트씩 받을 수도, 스무 번의 recv로 1바이트씩 받을 수도 있습니다.
그럼 주고받는 항목의 경계를 (지금 경우라면 파일 데이터의 끝을) 어떻게 구별할까요? 그래서 TCP를 사용할 때는 bugiii님 말씀처럼 데이터의 길이를 미리 보내는 경우가 많습니다. 받는 쪽에서는 그 길이만큼만 recv 하고서 그 데이터를 마무리 합니다. recv로 뭔가를 더 수신했다면 그건 다음 항목의 데이터(지금 경우라면 end 메시지)입니다.
그런데 지금 익명 사용자님은 받는 길이(read()에서 세 번째 인자)를 딱히 제한하고 계신 것 같지 않네요. 그러면 파일 데이터의 끝과 end 메시지를 한 번에 읽어들이게 될 수도 있습니다. 그럼 어떡해야 할까요? 앞서 파일의 총 길이(file_len)를 받아뒀으니까 지금까지 수신한 파일 데이터의 총 길이(recv_tot_len)를 계산해뒀다면 남은 파일 데이터의 길이를 알 수 있을 겁니다. 그러면 read()로 읽은 데이터 가운데 앞쪽의 (file_len - recv_tot_len) 바이트만 파일 데이터이고 뒷쪽은 다른 데이터(end 메시지)가 되겠지요.
$PWD `date`
read의 세번째 인자는 넘겨주는 write쪽에서 의
read의 세번째 인자는 넘겨주는 write쪽에서 의 크기와 같은 인자로 적용하였습니다.
그렇다면 read의 세번째 인자 크기(읽어올 최대크기) 를 total-현재받은size 로 해야된다는 건가요?
그리고 보내는측에서 순차적으로 각각 보내주는건데 받는측에서는 receive 버퍼가 밀려있어서 합쳐져서 들어오기도 한다는건가요?
네, 합쳐져서 들어올 수 있습니다. 말씀드린 것처럼
네, 합쳐져서 들어올 수 있습니다.
말씀드린 것처럼 TCP에서는 바이트 덩어리가 아니라 바이트의 흐름으로 데이터가 전달됩니다. 10B write 하고 2B write 했다고 받는 쪽에서도 10B read 하고 2B read 하게 되는 것이 아닙니다. 패킷 전달 타이밍이나 네트워크 상태, 커널 네트워킹 동작 옵션, 수신 호스트의 동작 상태 등에 따라 한 번에 12B를 읽을 수도 있고 다양한 방식으로 나눠서 읽게 될 수도 있습니다. 더 받아야 할 길이를 계산해서 그만큼만 받거나, 나눠 받은 걸 적당히 합치거나, 한꺼번에 받은 걸 적당히 나누거나 하는 일을 TCP를 이용하는 프로그램에서 해줘야 합니다.
$PWD `date`
음 그런데... 보내는측에서 파일을 읽어와서
음 그런데...
보내는측에서 파일을 읽어와서 받는측으로 보내줍니다 여러패킷 나누어서
그런데 보내는측에서 말씀하신 바와 같이 read( , , 토탈사이즈 - 여지껏 받은사이즈 ) 로 읽게되면
read 처음 하자마자 -1 뱉으면서 죽습니다.
아마 저장하는 버퍼 사이즈 보다 세번째 인자값이 커서 그런거 같은데요
이를 버퍼 사이즈보다 작을때만 저렇게 처리하자니 코드가 너무 지저분하네요
즉 , 말씀하신 방법처럼 하면 안되는데 제가 잘못 구현한건가요
코드가 지저분하게 느껴지더라도 필요한 로직은
코드가 지저분하게 느껴지더라도 필요한 로직은 넣어주셔야 합니다. 더 이상 뺄 코드가 없을 때 프로그램 구현이 끝나다고도 하지만 일단 필요한 코드는 다 있을 때의 얘기입니다. :-)
개념적인 부분에 대해선 제가 아는 만큼 말씀드린 것 같고, 구체적인 코딩 수준까지 들어가는 건 폐를 끼치는 게 될 것 같아 도망갑니다~
$PWD `date`
read용 버퍼를 만들어서, while 루프를 돌면서
read용 버퍼를 만들어서, while 루프를 돌면서 버퍼 사이즈만큼 계속 읽으세요.
데이터가 많으면 여러번에 나뉘어 읽을테고, 데이터가 적으면 알아서 데이터만큼 읽게 됩니다.
read 함수 반환값 확인해보시면 됩니다.
댓글 달기