socket 프로 그래 밍 22: socket 프로 그래 밍 파일 전송 기능 구현

4651 단어 사물 인터넷
이 절 은 저희 가 완성 하 겠 습 니 다. socket 파일 전송 프로그램, 이것 은 매우 실 용적 인 예 이다.구현 할 기능 은 클 라 이언 트 가 server 에서 파일 을 다운로드 하여 로 컬 로 저장 하 는 것 입 니 다.이 프로그램 을 작성 하려 면 두 가지 문 제 를 주의해 야 합 니 다. 1) 파일 크기 가 확실 하지 않 습 니 다. 버퍼 보다 훨씬 클 수 있 습 니 다. write () / send () 함 수 를 한 번 호출 하면 파일 내용 의 전송 을 완성 할 수 없습니다.데 이 터 를 받 을 때 도 같은 상황 이 발생 한다.이 문 제 를 해결 하려 면 while 순환 을 사용 할 수 있 습 니 다. 예 를 들 어:

//Server   
int nCount;
while( (nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0 ){
send(sock, buffer, nCount, 0);
}

//Client   
int nCount;
while( (nCount = recv(clntSock, buffer, BUF_SIZE, 0)) > 0 ){
fwrite(buffer, nCount, 1, fp);
}

서버 엔 드 의 코드 에 대해 파일 끝 에 읽 으 면 free ad () 는 0 으로 돌아 가 순환 을 끝 냅 니 다.클 라 이언 트 엔 드 코드 에 있어 서 중요 한 문 제 는 파일 전송 이 끝 난 후에 recv () 를 0 으로 되 돌려 주 고 while 순환 을 끝 내 는 것 입 니 다.
메모: 버퍼 에 있 는 데 이 터 를 읽 은 recv () 는 0 으로 돌아 가지 않 고 버퍼 에 다시 데이터 가 있 을 때 까지 차단 되 어 있 습 니 다.
2) 클 라 이언 트 측은 파일 수신 이 끝 났 는 지, 즉 위 에서 언급 한 문제 인 while 순환 이 언제 끝 났 는 지 판단 합 니 다.가장 간단 한 while 순환 을 끝 내 는 방법 은 당연히 파일 수신 이 끝 난 후에 recv () 함 수 를 0 으로 되 돌려 주 는 것 입 니 다. 그러면 어떻게 recv () 를 0 으로 되 돌려 줍 니까?recv () 가 0 으로 돌아 가 는 유일한 시 기 는 FIN 가방 을 받 았 을 때 입 니 다.FIN 패 키 지 는 데이터 전송 이 완료 되 었 음 을 의미 합 니 다. 컴퓨터 가 FIN 패 키 지 를 받 은 후에 상대방 이 더 이상 자신 에 게 데 이 터 를 전송 하지 않 을 것 임 을 알 게 되 었 습 니 다. read () / recv () 함 수 를 호출 할 때 버퍼 에 데이터 가 없 으 면 0 으로 돌아 가 'socket 파일 의 끝' 을 읽 었 음 을 의미 합 니 다. 여기 서 우 리 는 shutdown () 을 호출 하여 FIN 패 키 지 를 보 냅 니 다. server 단 에서 close () / closesocket ()출력 버퍼 의 데 이 터 를 무효 화 할 수 있 습 니 다. 파일 내용 은 전송 이 완료 되 지 않 고 연결 이 끊 길 수 있 습 니 다. shutdown () 을 호출 하면 출력 버퍼 의 데이터 전송 이 끝 날 때 까지 기다 릴 수 있 습 니 다. 이 절 은 Windows 를 예 로 들 어 파일 전송 기능 을 보 여 줍 니 다. Linux 는 이와 유사 합 니 다. 더 이상 군말 하지 않 습 니 다. 아래 의 완전한 코드 를 보십시오. 서버 서버 서버. cpp:

#include 
#include 
#include 
#pragma comment (lib, "ws2_32.lib") //   ws2_32.dll

#define BUF_SIZE 1024

int main(){
//         
char *filename = "D:\\send.avi"; //   
FILE *fp = fopen(filename, "rb"); //          
if(fp == NULL){
printf("Cannot open file, press any key to exit!
"); system("pause"); exit(0); } WSADATA wsaData; WSAStartup( MAKEWORD(2, 2), &wsaData); SOCKET servSock = socket(AF_INET, SOCK_STREAM, 0); sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(1234); bind(servSock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); listen(servSock, 20); SOCKADDR clntAddr; int nSize = sizeof(SOCKADDR); SOCKET clntSock = accept(servSock, (SOCKADDR*)&clntAddr, &nSize); // , char buffer[BUF_SIZE] = {0}; // int nCount; while( (nCount = fread(buffer, 1, BUF_SIZE, fp)) > 0 ){ send(clntSock, buffer, nCount, 0); } shutdown(clntSock, SD_SEND); // , , FIN recv(clntSock, buffer, BUF_SIZE, 0); // , fclose(fp); closesocket(clntSock); closesocket(servSock); WSACleanup(); system("pause"); return 0; }

클 라 이언 트 코드:

#include 
#include 
#include 
#pragma comment(lib, "ws2_32.lib")

#define BUF_SIZE 1024

int main(){
//      ,          
char filename[100] = {0}; //   
printf("Input filename to save: ");
gets(filename);
FILE *fp = fopen(filename, "wb"); //        (  )  
if(fp == NULL){
printf("Cannot open file, press any key to exit!
"); system("pause"); exit(0); } WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); SOCKET sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in sockAddr; memset(&sockAddr, 0, sizeof(sockAddr)); sockAddr.sin_family = PF_INET; sockAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); sockAddr.sin_port = htons(1234); connect(sock, (SOCKADDR*)&sockAddr, sizeof(SOCKADDR)); // , char buffer[BUF_SIZE] = {0}; // int nCount; while( (nCount = recv(sock, buffer, BUF_SIZE, 0)) > 0 ){ fwrite(buffer, nCount, 1, fp); } puts("File transfer success!"); // , shutdown() fclose(fp); closesocket(sock); WSACleanup(); system("pause"); return 0; }

D 디스크 에 send. avi 파일 을 준비 하고 server 를 실행 한 다음 client: Input filename to save: D: \ \ \ recv. avi 를 실행 합 니 다.↙ //잠시 후 File transfer success! D 디스크 를 열 면 recv. avi 를 볼 수 있 습 니 다. 크기 는 send. avi 와 같 고 정상적으로 재생 할 수 있 습 니 다. server. cpp 42 줄 코드 에 주의 하 십시오. recv () 는 client 엔 드 의 데 이 터 를 받 지 못 했 습 니 다. client 엔 드 에서 closessocket () 을 호출 하면 server 엔 드 에서 FIN 패 키 지 를 받 고 recv () 가 돌아 오 며 뒤의 코드 는 계속 실 행 됩 니 다.

좋은 웹페이지 즐겨찾기