views:

174

answers:

2

I have a client and server, client sending file to server. When i transfer files on my computer(in local) everything is ok(try to sen file over 700mb).

When i try to sent file use Internet to my friend in the end of sending appears error on server "Input string is not in correct format".This error appears in this expression fSize = Convert::ToUInt64(tokenes[0]); - and i don't mind wht it's appear. File should be transfered and wait other transferring

ps: sorry for too much code, but i want to find solution

   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 Voigt - ok, i can add checking if clientsocket->Receive(size1); equal zero, but why he begin receiving data again , in the ending of receiving.

UPDATE:After adding this checking problem remains. AND WIN RAR SAY TO OPENING ARCHIVE - unexpected end of file!

UPDATE:2Kevin - http://img153.imageshack.us/img153/3760/erorr.gif I think it continue receiving some bytes from client(that remains in the stream), but why? - exists cycle while (processed < fSize)

UPDATE: 2Ben Voigt -i did this fix processed += bytes; and file transfered successfully.Thanks! I am not very good with english and I don't understand what you mean when said "Consider what happens if your initial read snags part of the file data..." What means snags? And what initial data do you mean?

+3  A: 

Don't ignore the return value from clientsocket->Receive(size1).

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

EDIT: Consider what happens if your initial read snags part of the file data. Also consider what happens if your last read (which for some reason is still 1024 bytes instead of the remaining byte count) snags part of the header for the next request.

EDIT: You also haven't yet done anything useful with the return value from Receive. Your line of code:

processed = processed + 1024;

needs to be

processed += bytes;

EDIT: "snags" means "captures" or "grabs"

You have:

clientsocket->Receive(size1);

and a little later:

clientsocket->Receive(buf);

and you assume that all the header data is in size1 and all the file data is in buf. That's not a safe assumption on a stream socket. Datagram sockets preserve message boundaries, stream sockets like TCP do not. In fact, Nagle's algorithm might even cause the first part of the file data to be put into the same network packet as the header, but even if it doesn't, the receiver's TCP stack throws away the packet boundaries and just puts things into one big receive buffer.

Ben Voigt
+1  A: 

As Ben mentioned above, you need to use Message Framing to enable the client to know how much data to expect as part of each TCP packet.

Also, if all you are doing is a file transfer, you might want to look into Implementing fast file transfer using Socket.SendFile API. This provides a faster way of transferring files between machines.

feroze