2010-04-19 167 views
1

我有一個客戶端和服務器,客戶端發送文件到服務器。當我在我的計算機上傳輸文件(在本地)時,一切正常(嘗試傳輸超過700MB的文件)。文件使用.net套接字,傳輸問題

當我嘗試發送文件使用互聯網給我的朋友在發送結束時出現錯誤在服務器上「輸入字符串格式不正確」。此錯誤出現在此表達式fSize = Convert::ToUInt64(tokenes[0]); - 我不介意它是出現。文件應該被轉移並等待其他傳輸

PS:抱歉太多的代碼,但我想找到解決

private: void CreateServer() 
    { 

    try{ 
    IPAddress ^ipAddres = IPAddress::Parse(ipAdress); 
    listener = gcnew System::Net::Sockets::TcpListener(ipAddres, port); 
    listener->Start(); 
    clientsocket =listener->AcceptSocket(); 
    bool keepalive = true; 
    array<wchar_t,1> ^split = gcnew array<wchar_t>(1){ '\0' }; 
    array<wchar_t,1> ^split2 = gcnew array<wchar_t>(1){ '|' }; 

    statusBar1->Text = "Connected" ; 
    // 
    while (keepalive) 
    { 
     array<Byte>^ size1 = gcnew array<Byte>(1024); 
     clientsocket->Receive(size1); 
     System::String ^notSplited = System::Text::Encoding::GetEncoding(1251)->GetString(size1); 

     array<String^>^tokenes = notSplited->Split(split2); 
     System::String ^fileName = tokenes[1]->ToString(); 
     statusBar1->Text = "Receiving file" ; 
     unsigned long fSize = 0; 


          //IN THIS EXPRESSIN APPEARS ERROR 
     fSize = Convert::ToUInt64(tokenes[0]); 

     if (!Directory::Exists("Received")) 
     Directory::CreateDirectory("Received"); 

     System::String ^path = "Received\\"+ fileName; 
         while (File::Exists(path)) 
     { 
     int dotPos = path->LastIndexOf('.'); 
     if (dotPos == -1) 
     { 
     path += "[1]"; 
     } 
     else 
     { 
     path = path->Insert(dotPos, "[1]"); 
     } 
     } 

     FileStream ^fs = gcnew FileStream(path, FileMode::CreateNew, FileAccess::Write); 
     BinaryWriter ^f = gcnew BinaryWriter(fs); 
     //bytes received 
     unsigned long processed = 0; 

     pBarFilesTr->Visible = true; 
     pBarFilesTr->Minimum = 0; 
     pBarFilesTr->Maximum = (int)fSize; 
     // Set the initial value of the ProgressBar. 
     pBarFilesTr->Value = 0; 
     pBarFilesTr->Step = 1024; 

     //loop for receive file 
     array<Byte>^ buffer = gcnew array<Byte>(1024); 
     while (processed < fSize) 
     { 
     if ((fSize - processed) < 1024) 
     { 
     int bytes ; 
     array<Byte>^ buf = gcnew array<Byte>(1024); 
     bytes = clientsocket->Receive(buf); 
     if (bytes != 0) 
     { 
     f->Write(buf, 0, bytes); 
     processed = processed + (unsigned long)bytes; 
     pBarFilesTr->PerformStep(); 
     } 
     break;        
     } 
     else 
     { 
     int bytes = clientsocket->Receive(buffer); 
     if (bytes != 0) 
     { 
     f->Write(buffer, 0, 1024); 
     processed = processed + 1024; 
     pBarFilesTr->PerformStep(); 
     } 
     else break; 
     }       
     } 

     statusBar1->Text = "File was received" ; 
     array<Byte>^ buf = gcnew array<Byte>(1); 
     clientsocket->Send(buf,buf->Length,SocketFlags::None); 
     f->Close(); 
     fs->Close(); 
     SystemSounds::Beep->Play(); 
    } 
    }catch(System::Net::Sockets::SocketException ^es) 
    { 
    MessageBox::Show(es->ToString()); 
    } 
    catch(System::Exception ^es) 
    { 
    MessageBox::Show(es->ToString()); 
    } 
    } 

private: void CreateClient() 
{ 

         clientsock = gcnew System::Net::Sockets::TcpClient(ipAdress, port); 
         ns = clientsock->GetStream(); 
    sr = gcnew StreamReader(ns); 
    statusBar1->Text = "Connected" ; 

} 

private:void Send() 
    { 
    try{ 
    OpenFileDialog ^openFileDialog1 = gcnew OpenFileDialog(); 
    System::String ^filePath = ""; 
    System::String ^fileName = ""; 

    //file choose dialog 
    if (openFileDialog1->ShowDialog() == System::Windows::Forms::DialogResult::OK) 
    { 
     filePath = openFileDialog1->FileName; 
     fileName = openFileDialog1->SafeFileName; 
    } 
    else 
    { 
     MessageBox::Show("You must select a file", "Error", 
     MessageBoxButtons::OK, MessageBoxIcon::Exclamation); 
     return; 
    } 
    statusBar1->Text = "Sending file" ; 

    NetworkStream ^writerStream = clientsock->GetStream(); 
    System::Runtime::Serialization::Formatters::Binary::BinaryFormatter ^format = 
     gcnew System::Runtime::Serialization::Formatters::Binary::BinaryFormatter(); 

    array<Byte>^ buffer = gcnew array<Byte>(1024); 
    FileStream ^fs = gcnew FileStream(filePath, FileMode::Open); 
    BinaryReader ^br = gcnew BinaryReader(fs); 
       //file size 
    unsigned long fSize = (unsigned long)fs->Length; 
    //transfer file size + name 
    bFSize = Encoding::GetEncoding(1251)->GetBytes(Convert::ToString(fs->Length+"|"+fileName+"|")); 
    writerStream->Write(bFSize, 0, bFSize->Length); 

    //status bar 
    pBarFilesTr->Visible = true; 
    pBarFilesTr->Minimum = 0; 
    pBarFilesTr->Maximum = (int)fSize; 
    pBarFilesTr->Value = 0; // Set the initial value of the ProgressBar. 
    pBarFilesTr->Step = 1024; 

       //bytes transfered 
    unsigned long processed = 0; 
    int bytes = 1024; 
    //loop for transfer 
    while (processed < fSize) 
    { 
     if ((fSize - processed) < 1024) 
     { 
     bytes = (int)(fSize - processed); 
     array<Byte>^ buf = gcnew array<Byte>(bytes); 
     br->Read(buf, 0, bytes); 

     writerStream->Write(buf, 0, buf->Length); 
     pBarFilesTr->PerformStep(); 
     processed = processed + (unsigned long)bytes; 
     break; 
     } 
     else 
     { 
     br->Read(buffer, 0, 1024); 
     writerStream->Write(buffer, 0, buffer->Length); 
     pBarFilesTr->PerformStep(); 
     processed = processed + 1024; 
     }    
    } 
    array<Byte>^ bufsss = gcnew array<Byte>(100); 
    writerStream->Read(bufsss,0,bufsss->Length); 

statusBar1->Text = "File was sent" ; 
btnSend->Enabled = true; 
fs->Close(); 
br->Close(); 
SystemSounds::Beep->Play(); 
newThread->Abort(); 
} 
catch(System::Net::Sockets::SocketException ^es) 
{ 
    MessageBox::Show(es->ToString()); 
} 
    } 

UPDATE:2Ben福格特 - 好吧,我可以添加檢查,如果clientsocket->Receive(size1);等於零,但爲什麼他在接收結束時再次開始接收數據。

更新:添加此檢查問題後仍然存在。贏得拉爾開放檔案 - 文件意外結束!

更新:2Kevin - http://img153.imageshack.us/img153/3760/erorr.gif 我認爲它繼續從客戶端(保留在流中)接收一些字節,但爲什麼? - 存在週期while (processed < fSize)

更新:2en Voigt -i做了這個修復processed += bytes;和文件傳輸成功。謝謝! 我對英語不太好,我不明白你的意思是什麼時候說「考慮一下,如果你最初的閱讀障礙是文件數據的一部分......」什麼意思呢?你的初始數據是什麼意思?

+1

爲我們打印出「notSplited」和tokenes [0]和tokenes [1]的值。這將顯示很多。我認爲你如何做這件事還有其他問題,但這至少會成爲診斷具體問題的開始。 – 2010-04-19 17:57:43

回答

3

不要忽略來自clientsocket->Receive(size1)的返回值。

DOC:「Socket.Receive Method (Byte[])

編輯:考慮一下,如果您最初讀碰壁文件數據的一部分會發生什麼。還要考慮一下如果上次讀取(由於某些原因,仍然是1024字節而不是剩餘字節數)會發生下一次請求的部分頭部。

編輯:你還沒有做過任何有用的從Receive返回值。你的代碼行:

processed = processed + 1024; 

需求是

processed += bytes; 

編輯: 「碰壁」 的意思是 「捕獲」 或 「掠奪」

您有:

clientsocket->Receive(size1); 

和稍後:

clientsocket->Receive(buf); 

並且您認爲所有標題數據都在size1之內,並且所有文件數據都在buf之內。這在流套接字上不是一個安全的假設。數據報套接字保留消息邊界,像TCP這樣的流套接字不。實際上,Nagle的算法甚至可能會導致文件數據的第一部分被放入與頭部相同的網絡數據包中,但即使不這樣做,接收者的TCP堆棧也會丟棄數據包邊界,並將其放入一個大的接收緩衝區。