C# 客户端/服务器发送大文件

C# 客户端/服务器发送大文件,c#,.net,tcp,tcplistener,httplistener,C#,.net,Tcp,Tcplistener,Httplistener,我将要编写一个服务器应用程序,它应该能够从多个源接收大文件(与所有其他FTP客户端/服务器应用程序一样安静) 但我不确定什么是最好的方法,需要一些建议 客户端将向服务器发送XML数据,该数据类似于: <Data xmlns="http://schemas.datacontract.org/2004/07/DataFiles" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <Category>General

我将要编写一个服务器应用程序,它应该能够从多个源接收大文件(与所有其他FTP客户端/服务器应用程序一样安静)

但我不确定什么是最好的方法,需要一些建议

客户端将向服务器发送XML数据,该数据类似于:

<Data xmlns="http://schemas.datacontract.org/2004/07/DataFiles" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <Category>General</Category>
    <Files>
        <DataFile>
            <Extension>.txt</Extension>
            <Filename>test4</Filename>
            <Bytes>"Some binary data"</Bytes>
        </DataFile>
    </Files>
</Data>
请注意,客户机应该将数据(作为XML)发送到服务器,服务器将反序列化接收到的数据(使用filestream服务器端),如前所述

以下是我的TcpServer示例:

public class TcpServer
{
    protected TcpListener Listener;
    private bool _running;

    public TcpServer(int port)
    {
        Listener = new TcpListener(IPAddress.Any, port);
        Console.WriteLine("Listener started @ {0}:{1}", ((IPEndPoint)Listener.LocalEndpoint).Address, ((IPEndPoint)Listener.LocalEndpoint).Port);
        _running = true;
    }

    protected readonly ManualResetEvent TcpClientConnected = new ManualResetEvent(false);
    public void Start()
    {
        while (_running)
        {
            TcpClientConnected.Reset();
            Listener.BeginAcceptTcpClient(AcceptTcpClientCallback, Listener);
            TcpClientConnected.WaitOne(TimeSpan.FromSeconds(5));
        }
    }

    protected void AcceptTcpClientCallback(IAsyncResult ar)
    {
        try
        {
            var listener = ar.AsyncState as TcpListener;
            if (listener == null) return;

            using (var client = listener.EndAcceptTcpClient(ar))
            {
                using (var stream = client.GetStream())
                {
                    //Append or create to file stream
                }
            }

            //Parse XML data received?
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
        finally
        {
            TcpClientConnected.Set();
        }
    }
}   

创建一个新的空MVC应用程序

接下来将新控制器添加到
Controllers
文件夹

using System.Web;
using System.Web.Mvc;

namespace UploadExample.Controllers
{
    public class UploadController : Controller
    {
        public ActionResult File(HttpPostedFileBase file)
        {
            file.SaveAs(@"c:\FilePath\" + file.FileName);
        }

    }
}
现在,您所要做的就是上传一个文档,并将其作为多部分表单数据发布到您的站点

void Main()
{   
    string fileName = @"C:\Test\image.jpg";
    string uri = @"http://localhost/Upload/File";
    string contentType = "image/jpeg";

    Http.Upload(uri, fileName, contentType);
}

public static class Http
{
    public static void Upload(string uri, string filePath, string contentType)
    {
        string boundary         = "---------------------------" + DateTime.Now.Ticks.ToString("x");
        byte[] boundaryBytes    = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

        string formdataTemplate = "Content-Disposition: form-data; name=file; filename=\"{0}\";\r\nContent-Type: {1}\r\n\r\n";
        string formitem         = string.Format(formdataTemplate, Path.GetFileName(filePath), contentType);
        byte[] formBytes        = Encoding.UTF8.GetBytes(formitem);

        HttpWebRequest request  = (HttpWebRequest) WebRequest.Create(uri);
        request.KeepAlive       = true;
        request.Method          = "POST";
        request.ContentType     = "multipart/form-data; boundary=" + boundary;
        request.SendChunked     = true;

        using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            requestStream.Write(formBytes, 0, formBytes.Length);

            byte[] buffer = new byte[1024*4];
            int bytesLeft;

            while ((bytesLeft = fileStream.Read(buffer, 0, buffer.Length)) > 0) requestStream.Write(buffer, 0, bytesLeft);

            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
        }

        using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
        {
        }

        Console.WriteLine ("Success");    
    }
}
编辑 如果您遇到问题,请编辑您的Web.Config文件,很可能您达到了请求长度限制

<system.web>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"  maxRequestLength="1048576"/>
</system.web>

我在下面给您打电话“因为上下文是作为一个数据包而不是碎片接收的”。你能确切地解释一下这意味着什么吗?我注意到,当客户端向服务器发送文件时(使用TcpClient作为客户端),根据wireshark跟踪,许多tcp包被发送到主机/服务器。但是在发送完整的HTTP/XML包之前,上下文不存在于waithandle中。你确定吗?我使用HttpListener从客户端读取了非常大的HTTP流,而不必等待整个负载到达服务器。让我们看一些代码。我认为你做错了。很可能我做错了什么。今天下午,当我再次使用有线连接时,我将发布一些代码。Http使用TCP作为传输层。因此,在tcp完全传输之前,您不会在wireshark上看到http。实际上没有发送任何http,而是tcp。Wiresharp在获得所有tcp之前不会解码http。FTP也使用TCP作为传输层。FTP只是一个在tcp上运行的应用程序。tcp数据包的最大长度约为1500字节,使用多个tcp发送大型消息。我可能会将TCP用于使用最少开销的大型文件。感谢您提供的详细示例。我可能错过了,但服务器端应该作为自托管windows服务运行,而不是依赖IIS服务运行。您的示例是否能够在没有IIS服务的情况下运行(很抱歉,我缺乏asp.net经验)
void Main()
{   
    string fileName = @"C:\Test\image.jpg";
    string uri = @"http://localhost/Upload/File";
    string contentType = "image/jpeg";

    Http.Upload(uri, fileName, contentType);
}

public static class Http
{
    public static void Upload(string uri, string filePath, string contentType)
    {
        string boundary         = "---------------------------" + DateTime.Now.Ticks.ToString("x");
        byte[] boundaryBytes    = Encoding.ASCII.GetBytes("\r\n--" + boundary + "\r\n");

        string formdataTemplate = "Content-Disposition: form-data; name=file; filename=\"{0}\";\r\nContent-Type: {1}\r\n\r\n";
        string formitem         = string.Format(formdataTemplate, Path.GetFileName(filePath), contentType);
        byte[] formBytes        = Encoding.UTF8.GetBytes(formitem);

        HttpWebRequest request  = (HttpWebRequest) WebRequest.Create(uri);
        request.KeepAlive       = true;
        request.Method          = "POST";
        request.ContentType     = "multipart/form-data; boundary=" + boundary;
        request.SendChunked     = true;

        using (FileStream fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
        using (Stream requestStream = request.GetRequestStream())
        {
            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
            requestStream.Write(formBytes, 0, formBytes.Length);

            byte[] buffer = new byte[1024*4];
            int bytesLeft;

            while ((bytesLeft = fileStream.Read(buffer, 0, buffer.Length)) > 0) requestStream.Write(buffer, 0, bytesLeft);

            requestStream.Write(boundaryBytes, 0, boundaryBytes.Length);
        }

        using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
        {
        }

        Console.WriteLine ("Success");    
    }
}
<system.web>
    <compilation debug="true" targetFramework="4.5"/>
    <httpRuntime targetFramework="4.5"  maxRequestLength="1048576"/>
</system.web>
request.SendChunked = true;