c# - 使用.net套接字的文件,传输问题

标签 c# .net sockets c++-cli

我有一个客户端和服务器,客户端将文件发送到服务器。当我在本地计算机上传输文件时,一切正常(尝试将文件传输到700mb以上)。

当我尝试在发送结束时使用Internet向我的 friend 发送文件时,在服务器上出现错误“输入字符串格式不正确”。此错误出现在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());
 }
  }

更新:2Ben Voigt-好的,我可以添加检查clientsocket->Receive(size1);是否等于零,但是为什么他在接收结束时再次开始接收数据。

更新:添加此检查后,问题仍然存在。并且WIN RAR表示要打开存档-文件意外结束!

更新:2Kevin-http://img153.imageshack.us/img153/3760/erorr.gif
我认为它继续从客户端接收一些字节(保留在流中),但是为什么呢? -存在周期while (processed < fSize)
更新:2Ben Voigt -i修复了processed += bytes;并成功传输了文件。谢谢!
我的英语水平不是很好,并且当我说“考虑如果您的初始读取阻塞了文件数据的一部分会发生什么情况……”时,您的意思是什么?您指的是什么初始数据?

最佳答案

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

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

编辑:考虑如果您的初始读取阻塞了文件数据的一部分会发生什么。还请考虑一下,如果您的上次读取(由于某种原因仍然是1024个字节而不是剩余的字节数)阻塞了下一个请求的 header 的一部分,将会发生什么情况。

编辑:您还没有对Receive的返回值做任何有用的事情。您的代码行:

processed = processed + 1024;

需要是
processed += bytes;

编辑:“snags”的意思是“捕获”或“抓斗”

你有:
clientsocket->Receive(size1);

再过一会儿:
clientsocket->Receive(buf);

并假设所有 header 数据都在size1中,所有文件数据都在buf中。在流套接字上,这不是一个安全的假设。数据报套接字保留消息边界,而TCP等流套接字则不会。实际上,Nagle的算法甚至可能使文件数据的第一部分与报头放入同一网络数据包中,但是即使不这样做,接收方的TCP堆栈也会丢弃数据包边界,只是将内容放入一个大接收缓冲区。

关于c# - 使用.net套接字的文件,传输问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2669493/

相关文章:

.net - 从 VS 2017 .NET Core 项目中的发布目录中排除文件

c# - 运行时换出编译时静态引用的程序集

sql-server - 试图以访问权限禁止的方式访问套接字

java - 使用套接字(java)从客户端向服务器发送文件成功,但客户端卡住并且不退出循环

c# - 如何使用 C# 以编程方式下载 GitHub 数据

c# - TreeView 上下文菜单在 HierarchicalDataTemplate 中不起作用

c# - 实现此复合 GetHashCode() 的最佳方法是什么

c# - 杀死应用程序实例的最佳方法

c# - 如何根据频率产生声音?

c++ - Libevent套接字客户端示例