C# 客户端/服务器发送大文件
我将要编写一个服务器应用程序,它应该能够从多个源接收大文件(与所有其他FTP客户端/服务器应用程序一样安静) 但我不确定什么是最好的方法,需要一些建议 客户端将向服务器发送XML数据,该数据类似于: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
<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;