2013-03-02 66 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個字節,會發生什麼?您已經實現了一個用於發送文件數據的合理協議,但是您忘記了如何發送文件大小。 – 2013-03-03 06:05:49

回答

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 = while後的數據)但是我得到了下載的隨機文件。其餘的只是空間..我做了,而你給我在接收和發送.. – 2013-03-02 16:49:20

+0

檢查了一會兒,並由於某種原因它去「金額<= 0」不知道爲什麼..在客戶端和服務器。 – 2013-03-02 17:33:51

+0

服務器錯誤:10057,客戶端錯誤:0 – 2013-03-02 18:16:17

0

我自己面臨同樣的問題,使用Google後發現的send()API可以發送基於哪個都與操作系統有關低電平TCP緩衝器的最大數據。所以爲了發送一個巨大的文件,我們需要執行文件分塊,即以塊的形式發送文件。

`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直到讀取整個文件內容。

Credit to:shacktar cplusplus.com