2013-03-02 3 views
2

파일을 전송해야하는 서버와 클라이언트를 만들었습니다. 전체 파일을 읽고 보내려고했습니다. 하지만 지금 나는 그것을보고, 나는 문제가 있습니다. 클라이언트가 연결되면 서버가 자동으로 파일을 보내야합니다. 그러나 파일이 비어 있으며 문제가있는 곳을 모르겠습니다. .txt 파일을 보내려고합니다. 하지만 크기는 1MB보다 더 큰 파일을 보낼 수 있지만 미래에하고 싶은)전체 파일을 읽고 소켓을 통해 보내십시오.

편집 :. 여기

사진 : http://img819.imageshack.us/img819/8259/aadi.jpg

  • 좌측 : 내가 보내려고 파일.
  • 오른쪽 :이 파일은 내가

enter image description here

문제점받은 : 나는 손상된받은 파일을, 나는 그것을 사용할 수 없습니다.

서버 :

#include <WinSock2.h> 
#include <Windows.h> 
#include <stdio.h> 
#include <iostream> 
using namespace std; 

#pragma comment(lib, "Ws2_32.lib") 
#define Port 6000 

SOCKET Socket, Sub; 
WSADATA Winsock; 
sockaddr_in Addr; 
sockaddr_in IncomingAddress; 
int AddressLen = sizeof(IncomingAddress); 

int main() 
{ 
    WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock 

    if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version 
    { 
     WSACleanup(); 
     return 0; 
    } 

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    ZeroMemory(&Addr, sizeof(Addr)); 
    Addr.sin_family = AF_INET; 
    Addr.sin_port = htons(Port); 
    bind(Socket, (sockaddr*)&Addr, sizeof(Addr)); 

    if(listen(Socket, 1) == SOCKET_ERROR) 
    { 
     printf("listening error\n"); 
    } 
    else 
    { 
     printf("listening ok\n"); 
    } 

    if(Sub = accept(Socket, (sockaddr*)&IncomingAddress, &AddressLen)) 
    { 
     char *ClientIP = inet_ntoa(IncomingAddress.sin_addr); 
     int ClientPort = ntohs(IncomingAddress.sin_port); 
     printf("Client conncted!\n"); 
     printf("IP: %s:%d\n", ClientIP, ClientPort); 

     printf("Sending file .. \n"); 

     FILE *File; 
     char *Buffer; 
     unsigned long Size; 

     File = fopen("C:\\Prog.rar", "rb"); 
     if(!File) 
     { 
      printf("Error while readaing the file\n"); 
      getchar(); 
      return 0; 
     } 

     fseek(File, 0, SEEK_END); 
     Size = ftell(File); 
     fseek(File, 0, SEEK_SET); 

     Buffer = new char[Size]; 

     fread(Buffer, Size, 1, File); 
     char cSize[MAX_PATH]; 
     sprintf(cSize, "%i", Size); 

     fclose(File); 
     send(Sub, cSize, MAX_PATH, 0); // File size 

     //int len = Size; 
     //char *data = Buffer; 

     int Offset = 0; 
     while(Size > Offset) 
     { 
      int Amount = send(Sub, Buffer + Offset, Size - Offset, 0); 

      if(Amount <= 0) 
      { 
       cout << "Error: " << WSAGetLastError() << endl; 
       break; 
      } 
      else 
      { 
       Offset += Amount; 
       printf("2\n"); 
      } 
     } 


     free(Buffer); 
     closesocket(Sub); 
     closesocket(Socket); 
     WSACleanup(); 
    } 

    getchar(); 
    return 0; 
} 

클라이언트 :

#include <WinSock2.h> 
#include <Windows.h> 
#include <stdio.h> 
#include <iostream> 
using namespace std; 

#pragma comment(lib, "Ws2_32.lib") 

SOCKET Socket; 
WSADATA Winsock; 
sockaddr_in Addr; 
int Addrlen = sizeof(Addr); 

int main() 
{ 
    WSAStartup(MAKEWORD(2, 2), &Winsock); // Start Winsock 

    if(LOBYTE(Winsock.wVersion) != 2 || HIBYTE(Winsock.wVersion) != 2) // Check version 
    { 
     WSACleanup(); 
     return 0; 
    } 

    Socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 

    ZeroMemory(&Addr, sizeof(Addr)); // clear the struct 
    Addr.sin_family = AF_INET; // set the address family 
    Addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 
    Addr.sin_port = htons(6000); // set the port 

    if(connect(Socket, (sockaddr*)&Addr, sizeof(Addr)) < 0) 
    { 
     printf("Connection failed !\n"); 
     getchar(); 
     return 0; 
    } 

    printf("Connection successful !\n"); 

    printf("Receiving file .. \n"); 



    int Size; 
    char *Filesize = new char[1024]; 

    if(recv(Socket, Filesize, 1024, 0)) // File size 
    { 
     Size = atoi((const char*)Filesize); 
     printf("File size: %d\n", Size); 
    } 

    char *Buffer = new char[Size]; 

    //int len = Size; 
    //char *data = Buffer; 

    int Offset = 0; 
    while(Size > Offset) 
    { 
     int Amount = recv(Socket, Buffer + Offset, Size - Offset, 0); 

     if(Amount <= 0) 
     { 
      cout << "Error: " << WSAGetLastError() << endl; 
      break; 
     } 
     else 
     { 
      Offset += Amount; 
      printf("2\n"); 
     } 
    } 

    FILE *File; 
    File = fopen("Prog.rar", "wb"); 
    fwrite(Buffer, 1, Size, File); 
    fclose(File); 

    getchar(); 
    closesocket(Socket); 
    WSACleanup(); 
    return 0; 
} 
+0

파일 크기가 1,024 바이트 문자열로 인코딩 되었습니까? 또는'MAX_PATH' 바이트 문자열? 그리고 첫 번째'recv'가 31 바이트가되면 어떻게 될까요? 파일 데이터를 전송하기위한 정상적인 프로토콜을 구현했지만 파일 크기를 전송하는 방법에 대해 신중하게 생각하지 않았습니다. –

답변

4

send API는 보낼 요청 모든 데이터를 보낼 수 없습니다. 따라서 반환 값에주의를 기울여야하며 마지막으로 보낸 사람이 보낸 곳에서 보낸 사람에게 다시 시도해야합니다. 예를 들면 다음과 같습니다.

offset = 0; 
while (offset < bufsize) { 
    r = send(socket, buf+offset, bufsize-offset); 
    if (r <= 0) break; 
    offset += r; 
} 

파일 전송에 대해 비슷한 작업을 수행하는 동안 파일 크기에 해당하지 않는지 확인하십시오.

파일 크기를 보낼 때 MAX_PATH 전체가 아닌 크기를 나타내는 문자열 만 보내면됩니다. 그런 다음 수신기는 크기를 결정하기 위해 첫 번째 문자열을 구문 분석해야하지만 첫 번째 문자열의 끝에서 읽은 데이터는 파일의 일부로 간주되어야합니다. 그러나 송신자는 MAX_PATH이므로 수신자는 동일한 금액을 받아야합니다. 귀하의 클라이언트 코드는 1024 바이트를 받지만, 이것은 MAX_PATH과 같은 크기라는 표시가 없습니다.

recv API는 요청한 것보다 적은 바이트 수도 반환 할 수 있습니다. 루프를 사용하여 파일 읽기를 처리하지만 파일 크기가 포함 된 전체 메시지를 읽으려면 루프가 필요할 수 있습니다.

클라이언트 수신 루프에서 data 포인터를 증가시킵니다. 이로 인해 나중에 파일을 쓸 수 없게됩니다. 이미 Buffer이 있으니 파일을 작성하는 데 사용하십시오. 당신은 소켓을하고 오류가 발생하면

fwrite(Buffer, 1, len, File); 

는 I/O를, 당신은 WSAGetLastError()와 오류를 검색 할 수 있습니다, 또는 당신은 SO_ERROR 옵션을 소켓에 getsockopt()을 발행 할 수 있습니다. 이들은 다른 값을 반환 할 수 있지만 오류 이유는 상관되어야합니다.

+0

그런 뜻인가요? fwrite ((const char *) ReceivedFile, 1, len, File); ? (ReceviedFile = 잠시 후 데이터) 그러나 다운로드 한 파일에 임의의 문자가 표시됩니다. 그리고 나머지는 그냥 공백입니다 .. 당신이 recv와 send에서 저를 줬던 동안 나는 했어요. –

+0

잠시 동안 점검했는데, 어떤 이유로 "Amount <= 0"이 왜 .. .. 클라이언트 및 서버 .. –

+0

서버 오류 : 10057, 클라이언트 오류 : 0 –

0

나 자신도 같은 문제에 직면하고 검색 후 send() API는 os 의존적 인 저수준 TCP 버퍼를 기반으로 최대 데이터를 보낼 수 있음을 알게되었습니다.그래서 inorder는 거대한 파일을 보내고, 우리는 파일 청킹을 수행 할 필요가있다. 즉, 파일을 청크 형태로 보낸다.

`const int FILE_CHUNK_SIZE = 2000; 

//get file size 
ifstream file("myFile.file", ios::binary); 
file.seekg(0, ios::end); 
unsigned int fileSize = file.tellg(); 
file.close(); 

//get the file 
char* fileBuffer = new char[fileSize]; 
file.open("myFile.file", ios::binary); 
file.seekg (0, ios::beg); 
file.read (fileBuffer, fileSize); 
file.close(); 

//send file in chunks 
unsigned int bytesSent = 0; 
int bytesToSend = 0; 

while(bytesSent < fileSize) 
{ 
    if(fileSize - bytesSent >= FILE_CHUNK_SIZE) 
     bytesToSend = FILE_CHUNK_SIZE; 
    else 
     bytesToSend = fileSize - bytesSent; 
    send(ConnectSocket, fileBuffer + bytesSent, bytesToSend, 0); 
    bytesSent += bytesToSend; 
} 
delete [] fileBuffer;` 

수신 측에서는 전체 파일 내용이 읽힐 때까지 호출되는 recv() API가 있어야합니다.

크레딧 : shacktar cplusplus.com

관련 문제