I am building a simple HTTP server for PDF files with TcpClient. It works well, however the TcpClient closes before the browser is downloading of the PDF is being finished. How can I force TcpClient to wait until the remote client get everything that is written before closing?
//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(); Can I replace that ugly 'Thread.Sleep' hack?
EDIT: The code below works, based on the answers:
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(); }
Socket.Shutdown(SocketShutdown.Send)) to indicate that it's done with the connection. The local endpoint should as well, so that the remote endpoint knows when the data stream is complete.