예전 TCP 를 이용한 Echo 채팅 프로그램을 응용한 파일 전송 프로그램입니다.
서버에 접속하면 Read.jpg 을 클라이언트 쪽으로 송신하여 클라이언트는 이걸 받아 Write.jpg 로 저장하는 내용입니다.
간단하지만, 약간의 파일 처리 기교가 필요한 부분이 있습니다.
fseek, fwrite, fread 함수를 사용했으며, TCP 통신 부분은 Blocking 방식으로 간단하게 구현 했습니다. 코드가 복잡하거나 이해하기 어렵다면 TCP 소켓 프로그래밍을 공부하시면 좋습니다.
이 프로그램은 FTP 는 쓰지 않습니다.
Windows XP SP2 / Visual C++ 6.0 에서 제작 했습니다.
recv 함수에 문제가 있습니다. 뒤늦게 확인된봐 recv 함수는 한번에 다 받지 못하며 받은 용량을 return 합니다. 힌트가 되셨는지요... 몰라서, 한참 헤맷습니다. 모르시면 메일 주시면 가르쳐 드리겠습니다.
저작권 표기 하에 교육을 목적으로 자유롭게 배포가 가능합니다.
접습니다(Fold)..
/* Winsock 을 이용한 간단한 파일 전송 write.jpg 파일을 받는 내용입니다. 저작권 : http://cakel.tistory.com */ #include <stdio.h> #include <winsock.h> #include <string.h> #pragma comment (lib, "ws2_32.lib") // Linker 를 위한 컴파일러 옵션 #define PORT 5000 // 기본은 로컬 IP 의 포트 번호 5000 번 #define IP "127.0.0.1" // 로컬 = 127.0.0.1 int main(void) { // 윈속 초기화 WSADATA wsd; if(WSAStartup(MAKEWORD(2,2), &wsd) != 0) { fprintf(stderr, "WSAStartup 오류\n"); return 1; } // 소켓 구조체 완성 // TCP int s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (s == SOCKET_ERROR) { fprintf(stderr,"socket() 함수 오류\n"); WSACleanup(); return 1; } // TCP 연결에 필요한 주소 구조체 완성 sockaddr_in server; server.sin_addr.s_addr = inet_addr(IP); server.sin_port = htons(PORT); server.sin_family = AF_INET; // 서버에 접속 if(connect(s, (sockaddr*) &server, sizeof(server) ) == SOCKET_ERROR) { printf("connect() 오류\n"); closesocket(s); WSACleanup(); return 1; } // 파일 크기를 받음 int ret; char buff[1024]; if( (ret = recv(s, buff, 1024, 0)) == SOCKET_ERROR) { printf("Socket Error : 파일을 받지 못했습니다.\n"); closesocket(s); WSACleanup(); return 1; } else { // 파일을 받음 FILE *fp; if( (fp = fopen("write.jpg", "wb")) == NULL) // write.jpg 파일을 2진 쓰기 용으로 열기 { printf("write.jpg 파일 생성을 할수 없습니다.\n"); fclose(fp); closesocket(s); WSACleanup(); return 1; } long fsize = atol(buff); char* recvbuff; recvbuff = new char[fsize]; // 동적 할당으로 메모리 낭비 줄임 if( (ret = recv(s, recvbuff, fsize, 0) ) == SOCKET_ERROR) { printf("recv : 전송중 문제가 발생했습니다.\n"); fclose(fp); closesocket(s); WSACleanup(); return 1; } else { // 다 받았을때 파일 크기 만큼 다시 전송 fwrite(recvbuff, sizeof(char), fsize, fp); ltoa(fsize, buff, 10); ret = send(s, buff, sizeof(buff), 0); printf("%ld 바이트를 받았습니다.\n",fsize); fflush(fp); fclose(fp); delete recvbuff; } } // 파일, 소켓을 닫습니다. closesocket(s); WSACleanup(); return 0; }
접습니다(Fold)..
접습니다(Fold)..
/* Winsock 을 이용한 간단한 파일 전송 read.jpg 파일을 보내는 내용입니다. 저작권 : http://cakel.tistory.com */ #include <stdio.h> #include <winsock.h> #pragma comment (lib, "ws2_32.lib") // Linker 를 위한 컴파일러 옵션 #define PORT 5000 // 서버 포트 번호 5000 번 int main() { // 보낼 파일 읽어서 구조체로 저장 FILE *fp; long fsize; if( (fp = fopen("read.jpg", "rb")) == NULL ) { printf("read.jpg 이 없습니다.\n"); return 1; } // 파일의 길이 계산 fseek(fp, 0, SEEK_END); // 끝 fsize = ftell(fp); // 현재 포인터의 위치 = EOF fseek(fp, 0, SEEK_SET); // 다시 처음으로 돌리기 printf("보낼 파일 크기 : %ld 바이트\n", fsize); // 윈속 초기화 WSADATA wsd; if(WSAStartup(MAKEWORD(2,2), &wsd) != 0) { printf("Winsock 생성 오류\n"); fclose(fp); return 1; } // 서버 생성을 위한 주소 구조체 및 소켓 생성 int s, ns, addrsize; sockaddr_in client, server; server.sin_family = AF_INET; server.sin_addr.s_addr = INADDR_ANY; server.sin_port = htons(PORT); s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Welcome 소켓을 만들어 들어오는 클라이언트와 Bind 시킴 if (bind (s, (sockaddr*) &server, sizeof(server)) == SOCKET_ERROR) { printf("bind() 오류\n"); WSACleanup(); return 1; } // 대기 ... 최대 인원수 2명 // Blocking 방식으로 받음 listen(s,2); printf("클라이언트를 기다립니다.\n"); // 클라이언트가 왔을때 이 부분이 시작 // Bind 된 Welcome 소켓을 새로운 소켓에 승낙시켜 클라이언트와 통신 시도 addrsize = sizeof(client); ns = accept(s, (sockaddr*) &client, &addrsize); if (ns == INVALID_SOCKET) { printf("accept() 오류\n"); WSACleanup(); return 1; } // 연결이 완료 printf("%s:%d에서 접속\n", inet_ntoa(client.sin_addr), ntohs(client.sin_port)); // 파일 크기 전송 int ret; char buff[1024] = {0}; ltoa(fsize, buff, 10); ret = send(ns, buff, sizeof(char)*1024, 0); if(ret == SOCKET_ERROR) { printf("Socket_Error : 전송이 되지 않았습니다.\n"); fclose(fp); closesocket(s); closesocket(ns); return 1; } else { // 파일 전송 char* sendbuff; sendbuff = new char[fsize]; fread(sendbuff, sizeof(char), fsize, fp); ret = send(ns, sendbuff, fsize, 0); // 파일 전송이 끝났으면 클라이언트에서 파일 크기를 보냄 // 확인용 // 주의 : 이 부분이 없다면 클라이언트로 파일을 다 주기 전에 프로세스가 끝이 나므로 // 정상적인 전송이 불가능, 반복을 시켜서 대기를 하던지 추가적인 전송을 통해 중요 파일은 // 다 보내야 함. ret = recv(ns, buff, sizeof(buff), 0); if(fsize == atol(buff)) { printf("전송이 완료 되었습니다.\n"); } else { printf("Socket_Error : 전송이 되지 않았습니다.\n"); } // 마무리 fclose(fp); closesocket(s); closesocket(ns); WSACleanup(); delete sendbuff; } return 0; }
접습니다(Fold)..