【发布时间】:2020-03-18 16:36:29
【问题描述】:
我正在使用 TcpClient 为 PDF 文件构建一个简单的 HTTP 服务器。它运行良好,但是 TcpClient 在浏览器下载 PDF 完成之前关闭。如何强制 TcpClient 等到远程客户端在关闭之前获得所有写入的内容?
//pdf is byte[]
TcpListener server = new TcpListener(address, port);
server.Start();
TcpClient client = server.AcceptTcpClient(); //Wait for connection
var ns = client.GetStream();
string headers;
using (var writer = new StringWriter())
{
writer.WriteLine("HTTP/1.1 200 OK");
//writer.WriteLine("Accept: text/html");
writer.WriteLine("Content-type: application/pdf");
writer.WriteLine("Content-length: " + pdf.Length);
writer.WriteLine();
headers = writer.ToString();
}
var bytes = Encoding.UTF8.GetBytes(headers);
ns.Write(bytes, 0, bytes.Length);
ns.Write(pdf, 0, pdf.Length);
Thread.Sleep(TimeSpan.FromSeconds(10)); //Adding this line fixes the problem....
client.Close();
server.Stop();
我可以替换那个丑陋的“Thread.Sleep”黑客吗?
编辑:根据答案,下面的代码有效:
TcpListener Server = null;
public void StartServer()
{
Server = new TcpListener(IPAddress.Any, Port);
Server.Start();
Server.BeginAcceptTcpClient(AcceptClientCallback, null);
}
void AcceptClientCallback(IAsyncResult result)
{
var client = Server.EndAcceptTcpClient(result);
var ns = client.GetStream();
string headers;
byte[] pdf = //get pdf
using (var writer = new StringWriter())
{
writer.WriteLine("HTTP/1.1 200 OK");
//writer.WriteLine("Accept: text/html");
writer.WriteLine("Content-type: application/pdf");
writer.WriteLine("Content-length: " + pdf.Length);
writer.WriteLine();
headers = writer.ToString();
}
var bytes = Encoding.UTF8.GetBytes(headers);
ns.Write(bytes, 0, bytes.Length);
ns.Write(pdf, 0, pdf.Length);
client.Client.Shutdown(SocketShutdown.Send);
byte[] buffer = new byte[1024];
int byteCount;
while ((byteCount = ns.Read(buffer, 0, buffer.Length)) > 0)
{
}
client.Close();
Server.Stop();
}
【问题讨论】:
-
监听器应该向客户端发送一条消息,表明它已获取所有数据。然后客户端在收到消息后应该关闭。当客户端关闭连接时,服务器将自动关闭,因此您无需在服务器端执行任何操作。
-
@jdweng:在上面的代码中,监听器是发送数据,而不是接收它。在任何情况下,都没有必要确认数据。接收端点只需要关闭连接(例如调用
Socket.Shutdown(SocketShutdown.Send))来表明它已完成连接。本地端点也应该如此,以便远程端点知道数据流何时完成。 -
您绝对需要确认该消息。如果您不同意,那么我建议您阅读一本好的沟通理论书。服务器永远不应该关闭连接。它是奴隶。客户端是主服务器,服务器应该做的就是接受命令、处理数据并返回响应。
-
@jdweng:恕我直言,你不知道你在说什么。一旦建立了 TCP 连接,唯一的硬性规则是两个端点需要就它们使用的协议达成一致。如果这意味着服务器(监听端)只是发送一个数据流,然后以“发送”的原因关闭套接字,那么这就是所有需要发生的事情。不需要明确确认收到数据;客户端在获取所有数据后以“both”原因关闭就足够了,然后两个端点都可以关闭套接字。
-
@jdweng:是的,关于什么是实现服务器/客户端架构的“最佳”方式有各种“理论”。但这里唯一重要的是什么会起作用,以及 TCP/IP 协议支持什么。您的说法与这些事实不符。