1

我对为什么我的Socket.BeginSendFile 一次只异步发送两个文件感到困惑。我已经在不同的计算机上进行了测试,结果相同。

Socket.BeginSend似乎按预期一次发送所有三个。

我测试了将三个客户端连接到服务器。效果很好,所有三个都按预期异步连接。每个客户端(图片中的 Test100.exe、Test200.exe、Test300.exe)将根据连接的客户端从服务器请求名为 100、200 或 300 的文件夹中的文件。

问题是Socket.BeginSendFile一次最多只能将两个文件发送到流中。一旦之前调用的 2 个Socket.BeginSendFile 之一完成。见下文; 在此处输入图像描述

前两个发送的客户端之一完成发送后,第三个开始接收。

在此处输入图像描述

在代码中放置一些断点,我可以看出所有三个 Socket.BeginSendFile(...) 都被称为异步。

    private static void Send(Socket handler, String data)
    {
        string dateFolder =  data.Replace("<EOF>", "");

        string longFileName = "C:\\"+dateFolder+"\\poopoo.txt";
        string shortFileName = "poopoo.txt";

        // ==== for beginSend
        //byte[] fileData = File.ReadAllBytes(longFileName);
        // ==== for beginSend


        byte[] fileNameByte = Encoding.ASCII.GetBytes(shortFileName);
        byte[] fileInfo = Encoding.ASCII.GetBytes("C:\\Users\\Trim\\Desktop");
        byte[] fileInfoLen = BitConverter.GetBytes(fileInfo.Length); // we know these are ints (4bytes)

        byte[] clientData = new byte[4 + fileNameByte.Length + fileInfoLen.Length + fileInfo.Length];// + fileData.Length + eofByte.Length
        // ==== for beginSend
        //byte[] clientData = new byte[4 + fileNameByte.Length + fileInfoLen.Length + fileInfo.Length + fileData.Length];
        // ==== for beginSend

        byte[] fileNameLen = BitConverter.GetBytes(fileNameByte.Length); // we know these are int (4bytes);

        fileNameLen.CopyTo(clientData, 0);
        fileNameByte.CopyTo(clientData, 4); // room for error file name 4bytes?
        fileInfoLen.CopyTo(clientData, 4 + fileNameByte.Length);
        fileInfo.CopyTo(clientData, 4 + fileNameByte.Length + fileInfoLen.Length);

        // ==== for beginSend
        //fileData.CopyTo(clientData, 4 + fileNameByte.Length + fileInfoLen.Length + fileInfo.Length);
        // ==== for beginSend
        // *** Break point shows all three being called async
        handler.BeginSendFile(longFileName, clientData, null, 0, new AsyncCallback(AsynchronousFileSendCallback), handler);



       // handler.BeginSend(clientData, 0, clientData.Length, 0, new AsyncCallback(SendCallback), handler);


    }

第三个 Socket.BeginSendFile(...) 实际上直到前两个 AsynchronousFileSendCallback 方法之一才开始发送文件

    private static void AsynchronousFileSendCallback(IAsyncResult ar)
    {
        // Retrieve the socket from the state object.
        Socket client = (Socket)ar.AsyncState;

        // Complete sending the data to the remote device.
        client.EndSendFile(ar); // **Third** client doesn't actually start receiving his data until EndSendFile is called atleast once.

        Console.WriteLine("Send file to client.");
       // sendDone.Set();
        client.Shutdown(SocketShutdown.Both);
        client.Close();
    }

正如我之前所说,如果我使用Socket.BeginSend,问题就会消失。虽然我需要能够使用Socket.BeginSendFile因为它将文件分块在一个单独的线程上,特别是byte[] fileData = File.ReadAllBytes(longFileName);与我的Socket.BeginSend结构一起使用的这行代码对于大文件来说是不可接受的:(

非常感谢大家的时间!

4

1 回答 1

2

BeginSendFile 很可能使用 Windows API 函数 TransmitFile 来完成其工作。此 API 在客户端版本的 Windows上仅限于 2 个并发传输。

Windows 的工作站和客户端版本通过将系统上允许的并发 TransmitFile 操作数限制为最多两个来优化 TransmitFile 功能,以实现最小的内存和资源利用率。在 Windows Vista、Windows XP、Windows 2000 Professional 和 Windows NT Workstation 3.51 及更高版本上,只能同时处理两个未完成的 TransmitFile 请求;第三个请求将等到前面的请求之一完成。

于 2013-01-30T21:01:09.367 回答