socket 프로 그래 밍 22: socket 프로 그래 밍 파일 전송 기능 구현
4651 단어 사물 인터넷
//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 () 가 돌아 오 며 뒤의 코드 는 계속 실 행 됩 니 다.