大家好,我是一名大四的学生。最近在做毕设,遇到了在c#中socket传输大文件的问题。
我的大体思路有两个(参考网上的资料)
----------------------
(1) 个人认为效率比较低  
  连接..   
  发送第一个字节块...   
  等待确认...(接收确认信息)   
  确认   
  发送第二个字节块...   
  等待确认...   
  确认   
  发送第三个.....   
  .... 
(2)个人认为效率比较高
 
发送端一直写入网络流
接收端一直读取网络流
----------------------
我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
我根据思路(2)写了代码
如下
----------------------
接收端
[code]
private void Listener()  //开始监听传输请求
{
        IPHostEntry ipHostInfo =Dns.Resolve(System.Net.Dns.GetHostName());
        IPAddress ipAddress = ipHostInfo.AddressList[0];
this._ls =new TcpListener (ipAddress,6688);
this._ls .Start ();
while(true)
{  
Socket socket=this._ls .AcceptSocket ();
this.txtConnect .Text =socket.RemoteEndPoint .ToString ();
Receive(socket);   //调用接受文件函数
}
}
//我在每个字节块的前面加入了一个int型的变量,它表示每次发送文件数据的长度
private void Receive(Socket socket)  //接受文件函数
{
    NetworkStream ns = new NetworkStream(socket);
    FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate); 
    bool isRead = true;
    while (isRead)
    {
        int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);
        int datanum = 0;
        datanum = BitConverter.ToInt32(this._receiveBuf, 0);
        if (datanum > 0)                //如果传输的文件字节数>0 证明还有数据没有传输完
        {
            fs.Write(this._receiveBuf, 4, datanum);
            fs.Flush();
        }
        else                            //datanum = 0 ,文件发送完毕
        {
            isRead = false;
        }
    }
    this.txtFile.Text = "文件传输成功";
    fs.Close();
}[/code]
----------------------
发送端
[code]
private void btSend_Click(object sender, System.EventArgs e)  //点击按钮后开始传输
{
    if (this._isConnect)
    {
        _ns = _tc.GetStream();
        string path = this.txtPath.Text.Trim();
        FileStream fs = new FileStream(path, FileMode.Open);
        int sendCount = 0;
        byte[] countbuffer = null;
        byte[] clientbuffer = new byte[1004];
        while (sendCount < fs.Length && _ns.CanWrite)
        {
            int count = fs.Read(_sendBuf, 0, _sendBuf.Length);    //从文件中读出数据
            countbuffer = BitConverter.GetBytes(count);      //表示每次读出了多少字节数
            countbuffer.CopyTo(clientbuffer,0);              //将count加入数组首部
            _sendBuf.CopyTo(clientbuffer, 4);
            this._ns.Write(clientbuffer, 0, 4 + count);         //写入网络流
            sendCount += count;
        }
        countbuffer = BitConverter.GetBytes(0);                  //发送文件完后,读出字节数为0
        this._ns.Write(countbuffer, 0, countbuffer.Length);
        _ns.Close();
        fs.Close();
    }
}
[/code]
----------------------
我发现有时能够成功,有时却陷入死循环,比如我传输2k的txt,结果很长时间都没有停止,我中断后发现生成了200M的txt
实在搞不懂是为什么,请大家帮我分析分析.
-------------------------------
关于思路(1)我不会控制socket和相对应的networkstream
比如说发送端发送数据后,要等待接收端的确认信息
怎样让发送端停止发送数据来等待确认信息
接收到后又怎样重新发送数据
说简单一点就是发送端和接收端有序的操作网络流的问题
请大家多多指点
-----------------------------------
最后的问题:您觉得在socket上传输大文件时,如何能提高传输的效率?
networkstream的同步异步操作是怎么回事?能不能跟我说说他们的区别,最好来一个实例(beginread中的AsyncCallback asyncCallback到底是什么东西)问了好多问题,可是我没有多少分给大家觉得很惭愧(等我有份了一定补给大家),但是我会衷心的谢谢大家
我的mail:[email protected] 如果有code的话您可以mail我
再一次谢谢大家

解决方案 »

  1.   

    上面贴code的时候有问题
    补充:
    ---------------------
    接收端
    private void Receive(Socket socket)
    {
        NetworkStream ns = new NetworkStream(socket);
        FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
        bool isRead = true;
        while (isRead)
        {
            int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);
            int datanum = 0;
            datanum = BitConverter.ToInt32(this._receiveBuf, 0);   //从buffer中的前4个字节读出count 
            if (datanum > 0)                                       //确定每次要接受多少字节数
            {
                fs.Write(this._receiveBuf, 4, datanum);
            }
            else                              //如果接受字节数为0 就推出
            {
                isRead = false;
            }
        }
        this.txtFile.Text = "文件传输成功";
        fs.Close();
    }
    ---------------------
    发送端
    private void btSend_Click(object sender, System.EventArgs e)
    {
        if (this._isConnect)
        {
            _ns = _tc.GetStream();
            string path = this.txtPath.Text.Trim();
            FileStream fs = new FileStream(path, FileMode.Open);
            int sendCount = 0;
            byte[] countbuffer = null;
            byte[] clientbuffer = new byte[1004];
            while (sendCount < fs.Length && _ns.CanWrite)
            {
                int count = fs.Read(_sendBuf, 0, _sendBuf.Length);   //读出要发送的数据
                countbuffer = BitConverter.GetBytes(count);
                countbuffer.CopyTo(clientbuffer,0);
                _sendBuf.CopyTo(clientbuffer, 4);              
                this._ns.Write(clientbuffer, 0, 4 + count);          //写入网络流
                sendCount += count;
            }
            countbuffer = BitConverter.GetBytes(0);                 //发送完文件后 发送count = 0
            this._ns.Write(countbuffer, 0, countbuffer.Length);     //使接收端停止
            _ns.Close();
            fs.Close();
        }
    }
      

  2.   

    你为什么不把这两种方案结合在一起呢?
    首先把文件的总长度和每次发送的大小先发送出去,等接收端接受并分析,然后开始。
    比如每次发送4K(这是操作系统文件管理中使用到的最小文件大小,你可以看看你系统中的任何一个文件,占用空间都是4K的整数倍),
    最后一次可能会少与4K,但是接受方是可以计算出来的。
    必要时,你可以使用多线程,分段发送,接收端收集后分段组合,这还要多使用一个段号码。
    socket是最底层的类,传输效率最高!
    对于你说的异步操作,一句话说不清楚,基本上可以用“非阻塞模型”来概括,就是调用后立马返回,不是等到操作完成后才返回!
    打个比方:阻塞模型
    while(isok)
    {
    readdata(data);//从文件读数据
    send(data); //一直等到data发送完毕后才返回,其实这期间本来可以进行下一次读操作
                  //影响了效率。
    if(读完)
    isok=false;
    else
    isok=true;
    }
    非阻塞模型,可以在发送过程中进行读取操作,提高了效率。
    当然,在第二次发送前,必须等待第一次发送操作完成才行,需要检测和控制!
      

  3.   

    while (sendCount  < fs.Length && _ns.CanWrite) 
            { 
                int count = fs.Read(_sendBuf, 0, _sendBuf.Length);   //读出要发送的数据 
                countbuffer = BitConverter.GetBytes(count); 
                countbuffer.CopyTo(clientbuffer,0); 
                _sendBuf.CopyTo(clientbuffer, 4);               
                this._ns.Write(clientbuffer, 0, 4 + count);          //写入网络流 
                sendCount += count; 
            } 有点乱:你每次读取1000还是1004??不是前四个字节是长度吗?为什么从文件里读取1004个字节啊?
      

  4.   

    BeginReceiveFrom 方法启动从远程主机异步读取无连接数据报的操作。调用 BeginReceiveFrom 方法将使您能够在单独的执行线程中接收数据。您可以创建一个实现 AsyncCallback 委托的回调方法并将它的名称传递给 BeginReceiveFrom 方法。为此,您的 state 参数至少必须包含用于通信的已连接或默认 Socket。如果您的回调需要更多信息,则可以创建一个小型类来保存 Socket 和其他必需的信息。通过 state 参数将此类的一个实例传递给 BeginReceiveFrom 方法。回调方法应调用 EndReceiveFrom 方法。当应用程序调用 BeginReceiveFrom 时,系统将会使用单独的线程来执行指定的回调方法,并将在 EndReceiveFrom 上一直阻止到 Socket 读取数据或引发异常为止。如果想要在调用 BeginReceiveFrom 方法后使原始线程阻止,请使用 WaitHandle.WaitOne。当需要原始线程继续执行时,请在回调方法中调用 T:System.Threading.ManualResetEvent 的 Set 方法。有关如何编写 callback 方法的其他信息,请参见 Callback 示例。注意 
    在调用 BeginReceiveFrom 之前,必须使用 Bind 方法显式地将 Socket 绑定到本地终结点,否则 BeginReceiveFrom 将会引发 SocketException。
     该方法将数据读入 buffer 参数中,并捕获从其发送数据的远程主机终结点。有关如何检索此终结点的信息,请参考 EndReceiveFrom。如果打算从未知主机或多个主机异步接收无连接的数据报,则最适合使用此方法。在这些情况下,BeginReceiveFrom 将会读取本地网络缓冲区接收到的第一个排队数据报。如果您接收到的数据报大于 buffer 的大小,则 BeginReceiveFrom 方法将在 buffer 中尽可能多地填充消息内容,并引发 SocketException。如果您使用的是不可靠协议,多余的数据将会丢失。而如果当前使用的是可靠协议,则服务提供程序将保留多余的数据,而且通过使用一个足够大的缓冲区调用 BeginReceiveFrom 方法来检索这些数据。虽然 BeginReceiveFrom 是用于无连接协议的,但您同样可以使用面向连接的协议。如果选择这样做,则必须通过调用 Connect / BeginConnect 方法来建立远程主机连接,或者调用 Accept 或 BeginAccept 方法来接受传入的连接请求。如果在建立连接或接受连接之前就调用了 BeginReceiveFrom 方法,则您将得到 SocketException。您也可以在调用 BeginReceiveFrom 方法之前,为无连接协议建立默认远程主机。在上述任何一种情况下,BeginReceiveFrom 方法都会忽略 remoteEP 参数,并且只从已连接的或默认的远程主机接收数据。对于面向连接的套接字,BeginReceiveFrom 将读取所有可用的数据,直到达到 size 参数所指定的字节数。若要取消挂起的 BeginReceiveFrom,请调用 Close 方法。下面的代码示例异步接收来自远程主机的无连接数据报。IPHostEntry lipa = Dns.Resolve("host.contoso.com");
    IPEndPoint lep = new IPEndPoint(lipa.AddressList[0], 11000);   Socket s = new Socket(lep.Address.AddressFamily,
                                      SocketType.Dgram,
                                         ProtocolType.Udp);
       
       IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
       EndPoint tempRemoteEP = (EndPoint)sender;
       s.Connect(sender);
       
       try{
            while(true){
                 allDone.Reset();
                 StateObject so2 = new StateObject();
                 so2.workSocket = s;
                 Console.WriteLine("Attempting to Receive data from host.contoso.com");
             
                 s.BeginReceiveFrom(so2.buffer, 0, StateObject.BUFFER_SIZE,0, ref tempRemoteEP,
                                       new AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback), so2);    
                 allDone.WaitOne();
            }
       }
       catch (Exception e){
            Console.WriteLine(e.ToString());
       }
      

  5.   

    传输文件还可以利用UDP来。
    下面的示例使用主机名 www.contoso.com 在端口 11000 上建立 UdpClient 连接。将很短的字符串消息发送到两个单独的远程主机。Receive 方法在接收消息前阻止执行。使用传递给 Receive 的 IPEndPoint 可以显示响应主机的标识。// This constructor arbitrarily assigns the local port number.
    UdpClient udpClient = new UdpClient(11000);
        try{
             udpClient.Connect("www.contoso.com", 11000);         // Sends a message to the host to which you have connected.
             Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
          
             udpClient.Send(sendBytes, sendBytes.Length);         // Sends a message to a different host using optional hostname and port parameters.
             UdpClient udpClientB = new UdpClient();
             udpClientB.Send(sendBytes, sendBytes.Length, "AlternateHostMachineName", 11000);         //IPEndPoint object will allow us to read datagrams sent from any source.
             IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);         // Blocks until a message returns on this socket from a remote host.
             Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint); 
             string returnData = Encoding.ASCII.GetString(receiveBytes);
       
             // Uses the IPEndPoint object to determine which of these two hosts responded.
             Console.WriteLine("This is the message you received " +
                                       returnData.ToString());
             Console.WriteLine("This message was sent from " +
                                         RemoteIpEndPoint.Address.ToString() +
                                         " on their port number " +
                                         RemoteIpEndPoint.Port.ToString());          udpClient.Close();
              udpClientB.Close();
              
              }  
           catch (Exception e ) {
                      Console.WriteLine(e.ToString());
            }
      

  6.   

    另外如果你想保证传输的质量的话,用TCP/IP协议吧,它的优点是可以控制传输中的质量(降低出错率),缺点是效率稍微低点。
    TcpClient 类提供了一些简单的方法,用于在同步阻止模式下通过网络来连接、发送和接收流数据。为使 TcpClient 连接并交换数据,使用 TCP ProtocolType 创建的 TcpListener 或 Socket 必须侦听是否有传入的连接请求。可以使用下面两种方法之一连接到该侦听器: 创建一个 TcpClient,并调用三个可用的 Connect 方法之一。使用远程主机的主机名和端口号创建 TcpClient。此构造函数将自动尝试一个连接。注意 
    如果要在同步阻止模式下发送无连接数据报,请使用 UdpClient 类。
     给继承者的说明 要发送和接收数据,请使用 GetStream 方法来获取一个 NetworkStream。调用 NetworkStream 的 Write 和 Read 方法与远程主机之间发送和接收数据。使用 Close 方法释放与 TcpClient 关联的所有资源。下面的代码示例建立 TcpClient 连接。static void Connect(String server, String message) 
    {
      try 
      {
        // Create a TcpClient.
        // Note, for this client to work you need to have a TcpServer 
        // connected to the same address as specified by the server, port
        // combination.
        Int32 port = 13000;
        TcpClient client = new TcpClient(server, port);
        
        // Translate the passed message into ASCII and store it as a Byte array.
        Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);             // Get a client stream for reading and writing.
       //  Stream stream = client.GetStream();
        
        NetworkStream stream = client.GetStream();    // Send the message to the connected TcpServer. 
        stream.Write(data, 0, data.Length);    Console.WriteLine("Sent: {0}", message);             // Receive the TcpServer.response.
        
        // Buffer to store the response bytes.
        data = new Byte[256];    // String to store the response ASCII representation.
        String responseData = String.Empty;    // Read the first batch of the TcpServer response bytes.
        Int32 bytes = stream.Read(data, 0, data.Length);
        responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
        Console.WriteLine("Received: {0}", responseData);             // Close everything.
        stream.Close();         
        client.Close();         
      } 
      catch (ArgumentNullException e) 
      {
        Console.WriteLine("ArgumentNullException: {0}", e);
      } 
      catch (SocketException e) 
      {
        Console.WriteLine("SocketException: {0}", e);
      }
        
      Console.WriteLine("\n Press Enter to continue...");
      Console.Read();
    }
      

  7.   

    谢谢您的关注
    关于您说的“首先把文件的总长度和每次发送的大小先发送出去,等接收端接受并分析,然后开始。 ”
    client发送文件总长度和每次发送大小,这我会。
    可是每次client在发送完一次的数据后,如何设置client等待server的回传信息,client接收到回传信息后,还能继续发送数据呢??
    比如
    ----------------------------------
    发送端
    while (sendCount   < fs.Length && _ns.CanWrite)  
            {  
                int count = fs.Read(_sendBuf, 0, _sendBuf.Length);   //读出要发送的数据  _sendBuf长度1000
                countbuffer = BitConverter.GetBytes(count);  
                countbuffer.CopyTo(clientbuffer,0);  
                _sendBuf.CopyTo(clientbuffer, 4);                
                this._ns.Write(clientbuffer, 0, 4 + count);          //写入网络流  
                sendCount += count;  
                等待回复信息
                  接受到回复信息后判断服务器端是否接受成功
                  如果成功继续循环 (请大家帮我实现)       
    }  
    -------------------------------------------
    接收端
    private void Receive(Socket socket) 

        NetworkStream ns = new NetworkStream(socket); 
        FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate); 
        bool isRead = true; 
        while (isRead) 
        { 
            int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length); 
            int datanum = 0; 
            datanum = BitConverter.ToInt32(this._receiveBuf, 0);   //从buffer中的前4个字节读出count  
            if (datanum > 0)                                       //确定每次要接受多少字节数 
             { 
                fs.Write(this._receiveBuf, 4, datanum); 
                接受datanum字节数
                  发送至发送端
                  等待第2次接受           (请大家帮我实现)
            } 
            else                              //如果接受字节数为0 就退出
            { 
                isRead = false; 
            } 
        } 
        this.txtFile.Text = "文件传输成功"; 
        fs.Close(); 

      

  8.   

    谢谢大家的关注 我自己在写入网络流后,加上了读取网络流的代码 实现了发送端和接收端的轮流操作网络流
    可是又碰见一个问题
    我的接收端最终要将文件写入数据库的 现在有两个写入方案
    --------------------
    (1)发送端以单独socket发送数据,接收端单独线程接受数据,
      连接..    
      发送第一个字节块...    
      等待确认...(接收确认信息)    
      确认    
      发送第二个字节块...    
      等待确认...    
      确认    
      发送第三个.....    
    总体来说是:接受一块数据写入一块数据(已实现分块写入数据库)
    但这样我觉得效率不够高
    --------------------
    (2)发送端多个线程发送数据,接收端多个socket同时接受数据,但这样在写入数据库的时候就出现了数据块顺序问题(不能保证接受数据块顺序的正确性,因为多个socket同时接受)
    就算解决了数据块顺序问题,但是有没有可能在(2)的机制下实现多个发送端同时向接收端发送文件
    请大家多多指教
    --------------------
    下面是我自己写的接受端的code,在写入网络流后直接读取在接收端发送的返回信息,什么都不用设置,实现了接收端和发送端轮流操作网络流.接下来我要处理的就是效率问题(多线程发送)
    C# code
    while (sendCount < fs.Length && _ns.CanWrite)
    {
        int count = fs.Read(_sendBuf, 0, _sendBuf.Length);
        countbuffer = BitConverter.GetBytes(count);
        countbuffer.CopyTo(clientbuffer,0);
        _sendBuf.CopyTo(clientbuffer, 4);
        this._ns.Write(clientbuffer, 0, 4 + count);
        sendCount += count;
        int servernum = this._ns.Read(_sendBuf,0,4);         //在写入网络流后直接读取在接收端发送的返回信息 原
        int servercount = BitConverter.ToInt32(_sendBuf, 0); //来它本来就在阻塞,等待着接收端发来的信息,我以为
        if (count != servercount)                            //要人为的阻塞
        {
            MessageBox.Show("Error");
            break;
        }
    }
    countbuffer = BitConverter.GetBytes(0);
    this._ns.Write(countbuffer, 0, countbuffer.Length);
    _ns.Close();
    fs.Close();
    }
      

  9.   


    您能不能给我找个例子,或是写一些关于这个的code
      

  10.   

    感谢大家的关注对于 zzultc
    我对socket的异步传输一窍不通,能不能麻烦您找一找这方面的资料
    我自己也会去找找,找到了会发到帖子上的对于 zhoufoxcn
    msdn上的资料我也看了,对于一点不是很懂s.BeginReceiveFrom(so2.buffer, 0, StateObject.BUFFER_SIZE,0, ref tempRemoteEP,
    new AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback), so2);    
    allDone.WaitOne();为什么要new一个AsyncCallback(Async_Send_Receive.ReceiveFrom_Callback)?AsyncCallback是什么?
    Async_Send_Receive.ReceiveFrom_Callback 这个是方法么?
    谁能给我讲一讲s.BeginReceiveFrom 执行的步骤和执行顺序对于 jiangsheng
    一开始就用socket了,没有找ftp的相关资料
    您能不能说说使用ftp的优势?对于 yagebu1983
    您说的定义协议
    发送文件的时候封装协议!! 
    接受文件的时候解释协议!!
    我没有听说过
    您能不能找到这方面的资料给我对于 virusplayer
    您说的一直打开是什么意思?
    “要有一个通信协议,比如说传输大小,开始,结束,都要定义的”
    我不是很懂 能不能详细说说
      

  11.   

    请大家帮我看看
    我写的接收端和发送端 有时候运行正确 有时接受端的文件会少很多数据(甚至发送两次就停止了)接收端        /// <summary>
            /// 将每次要发送文件的字节数放置在数据的首部
            /// 服务器接收后将接收到的字节数发回
            /// 发送端发送完成后接受服务器的发来的字节数
            /// 然后与自己发送的字节数比较,进行检验
            /// 发送文件完成后发送count=0的消息到服务器
            /// 通知服务器停止接受
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void btSend_Click(object sender, System.EventArgs e)
            {
                if (this._isConnect)
                {
                    _ns = _tc.GetStream();
                    string path = this.txtPath.Text.Trim();
                    FileStream fs = new FileStream(path, FileMode.Open);
                    int sendCount = 0;
                    byte[] countbuffer = null;
                    byte[] clientbuffer = new byte[_sendBuf.Length + 4];  //生成每次发送的buf 首部4个字节表示发送字节数
                    while (sendCount < fs.Length && _ns.CanWrite)
                    {
                        int count = fs.Read(_sendBuf, 0, _sendBuf.Length);  //从文件中读出数据
                        countbuffer = BitConverter.GetBytes(count);         //得到字节数的buf
                        countbuffer.CopyTo(clientbuffer,0);                 //将count放入最终buf
                        _sendBuf.CopyTo(clientbuffer, 4);                   //将数据放入最终buf
                        this._ns.Write(clientbuffer, 0, 4 + count);         //发送最终buf
                        sendCount += count;                                 //更新发送总字节数
                        int servernum = this._ns.Read(countbuffer,0,4);     //等待接收端发来信息
                        int servercount = BitConverter.ToInt32(countbuffer, 0);//将发送信息转换成count
                        if (count != servercount)
                        {
                            MessageBox.Show("Error in transmit");
                            break;
                        }
                    }
                    countbuffer = BitConverter.GetBytes(0);
                    this._ns.Write(countbuffer, 0, countbuffer.Length);
                    _ns.Close();
                    fs.Close();
                    }
      

  12.   

    上面是发送端 搞错了这是接收端/// <summary>
    /// 从网络流读出数据,读出发送端发送的字节数
    /// 根据字节数写入文件并判断是否发送完成
    /// 并将字节数写入网络流,让发送端判断是否发送成功
    /// 最后停止循环
    /// </summary>
    /// <param name="socket">c与s之间的socket</param>
    private void Receive(Socket socket)
    {
        NetworkStream ns = new NetworkStream(socket);
        FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
        bool isRead = true;
        byte[] countbuf = new byte[4];
        while (isRead)
        {
            int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);  //从网络流读取数据
            int datanum = 0;
            datanum = BitConverter.ToInt32(this._receiveBuf, 0);    //将字节数转换成int
            if (datanum > 0)
            {
                countbuf = BitConverter.GetBytes(datanum);
                ns.Write(countbuf, 0, 4);                           //将字节数写入网络流
                fs.Write(this._receiveBuf, 4, datanum);             //写入文件
            }
            else
            {
                isRead = false;
            }
        }
        this.txtFile.Text = "文件传输成功";
        fs.Close();
    }
      

  13.   

    我看看看你的接受端代码,好像只把isread的状态改变了但是没有传到上面去啊 ,每次发送过来的数据你的 isread都是true,你要吧isread首先设为false然后在 文件流不>0的情况下才是 true。
      

  14.   

    我没有明白您的意思,你能不能说的再详细一点
    我的想法是isread为true,直到接受到的数据字节数为0(datanum=0)时,isread才为false(停止循环)
      

  15.   

    再怎么实验都不对
    估计问题出在下面
    (1)发送端发送完成后就直接read网络流this._ns.Write(clientbuffer, 0, 4 + count);         //发送最终buf
    sendCount += count;                                 //更新发送总字节数
    servernum = this._ns.Read(countbuffer,0,4);     //等待接收端发来信息(2)接收端接受到数据后将字节数发回客户端        int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);  //从网络流读取数据
            int datanum = 0;
            datanum = BitConverter.ToInt32(this._receiveBuf, 0);    //将字节数转换成int
            if (datanum > 0)
            {
                countbuf = BitConverter.GetBytes(datanum);
                ns.Write(countbuf, 0, 4);                           //将字节数写入网络流
                fs.Write(this._receiveBuf, 4, datanum);             //写入文件
    请各位大大帮我看看呀
      

  16.   

    调试成功原因是在接受端应该先将接收到的字节数写入文件,然后再将count写入网络流以便使发送端检查
    可能是数据传得太快,还没有写到文件中下次数据又来了,导致数据丢失
    感谢大家的帮助
    剩下就是多线程和socket的异步处理了
    谁能帮我找找这方面的资料修改接收端代码/// <summary>
    /// 从网络流读出数据,读出发送端发送的字节数
    /// 根据字节数写入文件并判断是否发送完成
    /// 并将字节数写入网络流,让发送端判断是否发送成功
    /// 最后停止循环
    /// </summary>
    /// <param name="socket">c与s之间的socket</param>
    private void Receive(Socket socket)
    {
        NetworkStream ns = new NetworkStream(socket);
        FileStream fs = new FileStream("c:\\file.txt", FileMode.OpenOrCreate);
        bool isRead = true;
        byte[] countbuf = new byte[4];
        while (isRead)
        {
            int count = ns.Read(this._receiveBuf, 0, this._receiveBuf.Length);  //从网络流读取数据
            int datanum = 0;
            datanum = BitConverter.ToInt32(this._receiveBuf, 0);    //将字节数转换成int
            if (datanum > 0)
            {
                fs.Write(this._receiveBuf, 4, datanum);             //写入文件
                countbuf = BitConverter.GetBytes(datanum);
               ns.Write(countbuf, 0, 4);                           //将字节数写入网络流
            }
            else
            {
                isRead = false;
            }
        }
        this.txtFile.Text = "文件传输成功";
        fs.Close();
    }
      

  17.   

    http://topic.csdn.net/u/20080202/09/2a639488-5c1e-42d2-9d11-3f6e2ceebc26.html楼主可以参考我的回帖。另外,楼主如果不是必须自己写所有代码,我可以给你我的一个类库。封好了传输功能。对算法嘛。楼主的想法几本是对的。但是没自己看你的代码质量。C/S都开两个线,一读一写。每个包头上加序号, 3579/100/1  3579/100/2  3579/100/3以此类推
    3579表示该数据块的编号。 100表示一共分了100个包,后便的数字表示当前是第几个包。
    接受方把接到的数据包都保存下来,一旦发现数据不连续,就请求一下。比如3579/100/23 之后得到 3579/100/25
    那么就再请求一下  3579/100/24,  发送方得到这个后,再把24包补发一次(包里要注明补发,以免接收方吧计数器弄错),
    数据传输完成。接收方返回一个确认指令。传输完成。
      

  18.   

    以上的算法可以根据需要变换。  比如你要传输的东西太大,接收和发送方都吧所有数据放内存里等待校验和重发是很浪费的。
    那么你在发送前就该先吧数据分段。比如不分段需要1000个包,那么你可以线分成20段,每段50个包。每完成一段,就确认一下,吧数据写入磁盘,继续处理下一段。
    不过如果要求传输的是命令队列(一般这东西要求及时处理,不能耽搁)那么你最好采用类似ATM的传输方式。接受一个,处理一个。
      

  19.   

    今天仔细看了楼主的code,对这一句:
                        int count = fs.Read(_sendBuf, 0, _sendBuf.Length);  //从文件中读出数据
    很疑惑啊,楼主每次都是从文件流的开始位置读起数据,这样测试结果也对??似乎要用sendCount加以控制吧,请指教!