1

我有一个客户端/服务器应用程序。它们在接收数据时都使用异步调用。它使用 TCP 构建,主要用于发送文件。

一个命令沿着一个套接字发送,然后将其“转换”为一个简单的开关盒并进行操作。如果客户端发送命令“SENDFILE”,我希望服务器能够输入一个调用一个函数的案例,该函数然后处理该套接字上的任何进一步数据并将其组合到一个文件中。

这是服务器端的 OnDataReceive 回调函数和 switch case:

public void OnDataReceived(IAsyncResult asyn)
        {
            SocketData socketData = (SocketData)asyn.AsyncState;
            try
            {

                // Complete the BeginReceive() asynchronous call by EndReceive() method
                // which will return the number of characters written to the stream 
                // by the client
                socketData.m_currentSocket.EndReceive(asyn);

                //Get packet dtata
                Packet returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer);

                switch (returnPacket.command)
                {
                    case Command.SENDREQUEST: //Get ready for an incoming file      

这里异步读取网络流并同步写入文件流的类:对吗?

    public static void NetToFile(NetworkStream net, FileStream file)
        {
            var copier = new AsyncStreamCopier(net, file);
            copier.Start();
        }

public class AsyncStreamCopier
    {
        public event EventHandler Completed;

        private readonly Stream input;
        private readonly Stream output;

        private byte[] buffer = new byte[Settings.BufferSize];

        public AsyncStreamCopier(Stream input, Stream output)
        {
            this.input = input;
            this.output = output;
        }

        public void Start()
        {
            GetNextChunk();
        }

        private void GetNextChunk()
        {
            input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null);
        }

        private void InputReadComplete(IAsyncResult ar)
        {
            // input read asynchronously completed
            int bytesRead = input.EndRead(ar);

            if (bytesRead == 0)
            {
                RaiseCompleted();
                return;
            }

            // write synchronously
            output.Write(buffer, 0, bytesRead);

            // get next
            GetNextChunk();
        }

        private void RaiseCompleted()
        {
            if (Completed != null)
            {
                Completed(this, EventArgs.Empty);
            }
        }
    }

我遇到的问题是相反,从文件流读取到网络流,我应该从文件流异步读取并同步写入网络流吗?

还因为在上面的示例中,第一次调用 Start() 并且函数结束时它会返回到服务器开关盒,然后任何进一步的(文件)数据都会命中Packet returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer);

和错误:(

*编辑 1 *

  • 我不能使用任何外部库或大量代码,这必须从头开始构建。

  • 这不是典型的客户端-服务器应用程序,它更多的是 p2p,但不完全是,每个应用程序都有自己的服务器和客户端在不同的线程中运行,这允许多个应用程序相互连接,从而创建一个......网络。

  • 客户端告诉服务器它正在向它发送文件,它不会从服务器请求文件

4

3 回答 3

0

查看这篇关于异步流操作的文章http://msdn.microsoft.com/en-us/magazine/cc337900.aspx(具有异步复制流的紧凑代码)。

您的示例代码不使用您拥有的已完成通知...确保您的外部代码等待流复制完成。

于 2011-01-11T23:08:06.457 回答
0

好吧,我认为您的问题没有任何直接的答案;但是,这里有一些观察:

如果客户端发送命令“SENDFILE”,我希望服务器能够...

这是一种方法;但是,您可能会考虑更多地反转控件。有一个返回大小/版本信息的获取文件信息。然后有一个带有偏移量和长度的读取文件。现在客户端可以“轮询”它通过文件的方式,而不是试图以服务器发送数据的速度吸收数据。

这里异步读取网络流并同步写入文件流的类:对吗?

是的,乍一看似乎是对的。

我遇到的问题是相反,从文件流读取到网络流,我应该从文件流异步读取并同步写入网络流吗?

同样,我将使用客户端轮询循环一次提取文件的各个部分。如果套接字断开连接,这也可以重新启动。

也因为在上面的例子中,第一次调用 Start() 并且函数结束......

是的,这通常会导致套接字出现问题。您将不得不跟踪每个套接字的一些状态信息,以便您知道如何处理收到的字节。我是在写文件吗,我是在等待命令吗?坦率地说,如果我正在写这个(无论如何我不会使用套接字),我会将所有内容打包到带有长度前缀的google protobuffer中,其中包含有关每个请求的详细信息。这允许您将状态管理卸载到客户端,而不是在服务器上跟踪它。

有人能指出我正确的方向吗?据我所见,网上没有太多内容。

我认为你在网上搜索不到太多的一般原因是因为大多数人(90% 左右)甚至没有尝试过这个。使用套接字执行此操作是困难、乏味且极易出错的。我什至不会开始使用原始套接字进行通信。选择任何现有的客户端/服务器传输并使用它。如果您需要示例,我的建议可能会倾向于 WCF。

干杯,祝你好运!

于 2011-01-11T22:34:18.927 回答
0

我想我已经通过使用等待事件解决了其中的一部分问题,因此该功能不会结束,它允许网络流-> 文件流完成。

我现在遇到的问题是文件流-> 网络流。“我应该异步读取文件流并同步写入网络流吗?”

于 2011-01-12T19:18:01.180 回答