public void doprocess(TcpClient client)
{
MemoryStream ms = new MemoryStream();
Stream clStream = client.GetStream();
byte[] buffer_1 = new byte[8192];
int count = clStream.Read(buffer_1, 0, buffer_1.Length);
while (count > 0)
{
ms.Write(buffer_1, 0, count);
//the below line doesn't gives response and code hangs here
count = clStream.Read(buffer_1, 0, buffer_1.Length);
}
}
Is there any other way to write one stream to another? I want to use this Stream twice, which is why I need to write it to the MemoryStream.
In .NET 4 the copying part is really easy:
MemoryStream ms = new MemoryStream();
client.GetStream().CopyTo(ms);
If you're not using .NET 4, then code similar to what you've already got is basically the same thing.
However, note that this (and any other attempt) will only work if the network stream has been closed - otherwise the Read call will block waiting for more data. I suspect that's what's going wrong for you - and it's a fundamental problem.
If your network stream isn't closed, then it's unclear how you'd really want it to behave - should the two readers of the "split" stream basically read any buffered data, but then block until there's new data otherwise? The buffered data could be removed when it's been read from both streams, of course. If that is what you're after, I don't think there's anything in .NET to help you particularly - and it's probably pretty tricky.
If you could give us more context of what you're trying to do (and what the TcpClient is connecting to) that would really help.
The reason why your code hangs on clStream.Read is because you are tying to read 8192 bytes from the socket but on the other side no-one is writing that many bytes. So the client just sits there and waits for the other side to send the required number of bytes. Depending on the protocol you are trying to implement over TCP there must be some indincation from the server how much data it intends to send so that the client knows in advance and only tries to read that many bytes.
For example in the HTTP protocol the server sends in the headers the Content-Length header to indicate to the clients how much data is going to be sent in the body.
Related
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();
}
The main issue in your code is that your server (the file host) neglected to read from the socket it's writing the file to, and so has no way to detect, never mind wait for, the client shutting down the connection.
The code could be way better, but at a minimum you could probably get it to work by adding something like this just before your client.Close(); statement:
// Indicate the end of the bytes being sent
ns.Socket.Shutdown(SocketShutdown.Send);
// arbitrarily-sized buffer...most likely nothing will ever be written to it
byte[] buffer = new byte[4096];
int byteCount;
while ((byteCount = ns.Read(buffer, 0, buffer.Length)) > 0)
{
// ignore any data read here
}
When an endpoint initiates a graceful closure (e.g. by calling Socket.Shutdown(SocketShutdown.Send);), that will allow the network layer to identify the end of the stream of data. Once the other endpoint has read all of the remaining bytes that the remote endpoint has sent, the next read operation will complete with a byte length of zero. That's that other endpoint's signal that the end-of-stream has been reached, and that it's time to close the connection.
Either endpoint can initiate the graceful closure with the "send" shutdown reason. The other endpoint can acknowledge it once it's finished sending whatever it wants to send by using the "both" shutdown reason, at which point both endpoints can close their sockets (or streams or listeners or whatever other higher-level abstraction they might be using the wrap the socket).
Of course, in a properly-implemented protocol, you'd know in advance whether any data would ever actually be sent by the remote endpoint. If you know none ever will be, you could get away with a zero-length buffer, and if you know some data might be sent back from the client, then you'd actually do something with that data (as opposed to the empty loop body above).
In any case, the above is strictly a kludge, to get the already-kludged code you posted to work. Please don't mistake it for something intended to be seen in production-quality code.
All that said, the code you posted is a long way from being all that good. You aren't just implementing a basic TCP connection, but apparently are trying to reimplement the HTTP protocol. There's no point in doing that, as .NET already has HTTP server functionality built in (see e.g. System.Net.HttpListener). If you do intend to reinvent the HTTP server, you need a lot more code than the code you posted. The lack of error-handling alone is a major flaw, and will cause all kinds of headaches.
If you intend to write low-level network code, you should do a lot more research and experimentation. One very good resource is the Winsock Programmer’s FAQ. It's primary focus is, of course, programmers targeting the Winsock API. But there is a wealth of general-purpose information there as well, and in any case all of the various socket APIs are very similar, as they are all based on the same low-level concepts.
You may also want to review various existing Stack Overflow Q&A. Here are a couple of ones closely related to your specific problem:
How to correctly use TPL with TcpClient?
Send a large file over tcp connection
Do be careful though. There's almost as much bad advice out there as good. There's no shortage of people going around acting like they are experts in network programming when they aren't, so take everything you read with a grain of salt (including my advice above!).
I was trying to recieve xml file with simple tcp server. But all my efforts ends with crushing application on reading bytes from NetworkStream. I have no idea, what is wrong.
I have already tried to copy source code from the answer to a very similar question. It looks like it should work, but it doesn't
Code sample of my client sending xml:
private void SendFile()
{
// stm is a class attribue NetworkStream defined in another method
byte[] dataToSend = File.ReadAllBytes(string_path_to_file);
stm.Write(dataToSend, 0, dataToSend.Length);
sstm.Flush();
}
Code sample of my server recieving xml:
public void RecieveFile()
{
Stream fs = new FileStream(path_to_recieved_file, FileMode.Create, FileAccess.ReadWrite);
Byte[] bytes = new Byte[1024];
int length;
//client was defined earlier, on establishing connection
NetworkStream networkStream = client.GetStream();
length = networkStream.Read(bytes, 0, bytes.Length);
while ((length = networkStream.Read(bytes, 0, bytes.Length)) != 0)
{
fs.Write(bytes, 0, length);
}
}
Client works fine. I am sending test xml file (~533b) and server can read these data. When I debugging my app, I can see that first time server will read 533b (obviously, the whole file). Then writes it and stops responding after trying to read second time. I expected that after second reading, when there is nothing in networkStream, I'll get length=0 and loop will stop. What am I doing wrong?
I would really appreciate any help. Thanks in advance.
You are reading to the end of the stream - however, this will not happen until you close the sending socket. Until the socket is closed, it is in a limbo pending state, and it is correct and expected that Read will block indefinitely, until one of:
the stream becomes closed (or faulted)
at least one byte is available
read timeout, if enabled
Incidentally, you are discarding the first chunk of data you read. If you are in a position to close the sending stream, you should just replace all of that code with:
using(var fs = File.Create(path_to_recieved_file)) {
client.GetStream().CopyTo(fs);
}
However, if you cannot close the sending stream (because you want to send multiple messages, for example), you will need to implement some kind of framing protocol - for example, prefixing the data with the payload length.
This question already has answers here:
Get Length of Data Available in NetworkStream
(4 answers)
Closed 8 years ago.
I'm trying to get my client application to read a response from the server, and I'm really having trouble grasping a certain concept here.
According to the research I've done, you must have the length of the bytes to read from a NetworkStream before you can actually read the data. This makes very little sense to me. How are you supposed to know how much data is coming in before it even gets there?
This code:
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Data sent.\n");
Console.WriteLine("Reading response...\n");
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
}
reads 1024 bytes into a buffer with a set size. So what if the response from the server has more than 1024 bytes? Then what?
If somebody could help me grasp this concept, I'd be extremely grateful.
You need to loop whilst the NetworkStream.DataAvailable is true; see here:
http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read.aspx
You need to have some sort of pre-agreed scheme (a protocol) between the sender and the receiver for determining the "end of message".
Usually this is done by starting the message with a header that includes the length of message. For example, both parties can agree that the first 4 bytes determine the length of the incoming message, so the receiver reads that many bytes.
Another way would be having a specific sequence of bytes that signifies the end of message. For instance, the receiver keeps reading in until it sees the ascii bytes of <EOF>.
Do not use DataAvailable because it is quite possible that you receive the message in chunks, so DataAvailable can turn false before you have received the full message.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
TcpClient send data and receive data over network
Loop until TcpClient response fully read
I am trying to send a file from a server to a client over TCP.
Server-side code, sending file:
NetworkStream netStream = client.GetStream();
FileStream fs = new FileStream("usb.exe",FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data,0, data.Length);
fs.Flush();
fs.Close();
netStream.Write(data, 0, data.Length);
netStream.Flush();
Client-side code, receive file:
FileStream str = new FileStream("usb.exe", FileMode.Create, FileAccess.Write);
byte[] data = new byte[1024];
while ((dataCitit = netStream.Read(data,0, data.Length)) > 0)
{
Thread.Sleep(25);
Application.DoEvents();
str.Write(data, 0, dataCitit);
totalbytes += dataCitit;
}
str.Close();
Can someone point where I am getting it wrong ?
The file has 1036 kb, and it sends only 1032 kb and then gets stuck it won't get out the while loop on the client-side.
Also if I close the server and open it really quick it sends the last bytes and the files sends completely. (this file opens perfectly)
I think it`s a problem on the server side not sending all the bytes but why and where...
Well this is a problem in your server-side code to start with:
fs.Read(data,0, data.Length);
You're ignoring the value returned by Read. Never do that. With FileStream you're possibly okay, but I personally wouldn't trust it anyway. If you're using .NET 4, you don't need to do this anyway - just use Stream.CopyTo.
On the client-side code, your biggest initial problem is that you're doing all of this on the UI thread. That's a terrible idea - the UI will freeze if there's a network glitch, as the Read call is blocking.
Again, just use Stream.CopyTo, but do it in a background thread.
Additionally, in all of these cases, use a using statement for the streams, so that you close them cleanly whatever happens.
That's all just general hygiene. Now, as for why you're hanging...
... you're not closing the network stream on the server side. Therefore you never reach the end of the stream on the client side. If you only need to use the connection for a single file, then the answer is simple: just close the connection on the server side.
If, however, you need to use the same connection for multiple files, then you need more protocol - you need to some way of indicating the end of the data. There are three common ways of doing that:
Write the length of the data before the data itself, then on the reading side, first read the length, then read that many bytes, failing if the stream finishes before you've done so. This requires that you know how much data you're going to write before you start writing.
Use an "end of data" marker which you can detect on the reading side; this is a pain in general, as it requires escaping the marker if it appears in the text itself.
A variation on the first approach, where you write a length-prefixed chunk at a time, then a zero-length chunk to indicate "end of data". This is pretty flexible, but obviously a bit more work than the first approach if the first approach actually works for you.
I was wondering to myself whether or not writing a full message to a NetworkStream would be better than writing each section of a message in multiple Write calls. For example, would writing the message in full like such...
NetworkStream ns = tcpClient.GetStream();
byte[] message = Encoding.ASCII.GetBytes("This is a message.");
ns.Write(message, 0, message.Length);
... be a better idea than writing like this...
NetworkStream ns = tcpClient.GetStream();
byte[] message1 = Encoding.ASCII.GetBytes("This ");
byte[] message2 = Encoding.ASCII.GetBytes("is ");
byte[] message3 = Encoding.ASCII.GetBytes("a ");
byte[] message4 = Encoding.ASCII.GetBytes("message.");
ns.Write(message1, 0, message1.Length);
ns.Write(message2, 0, message2.Length);
ns.Write(message3, 0, message3.Length);
ns.Write(message4, 0, message4.Length);
Is there also much difference in program performance or networking performance for each method?
This gets tricky, and depends on how the socket is configured. What you Write does not not map directly to what is received:
the NIC may have to split it into packets at transmission
the socket/NIC may be configured to combine packets for tramsmission (reducing the actual network packets, but making it hard to be sure that you've sent what you think you have - it may be buffered locally)
Note in particular that NetworkStream.Flush() doesn't do anything, so you can't use that to push any last few bytes
A good compromise is to wrap the NetworkStream in a BufferedStream, and configure the Socket with NoDelay = true (disables local output buffering). The BufferedStream allows you to keep writing in any-size chunks (including individual bytes), without causing huge packet fragmentation; the BufferedStream will flush itself when it approaches a set size. However, and importantly, you now have access to the BufferedStream's Flush() method which will empty the buffered data to the network; useful if having a complex back-fore conversation and need to know you've sent the end of your message.
The risk otherwise is that the client waits forever for a response (without realising it still has 3 bytes buffered locally, so hasn't sent a full request), and the server doesn't respond because it is still waiting for the last 3 bytes of a request. Deadlock.
In terms of networking it will be the same. But on the client you don't need to have the entire message loaded in memory if you use the second approach. This could be useful when dealing with really big volumes of data. For example let's suppose that you want to send huge files. You could read those files in chunks so that you never need to load the entire file contents in memory and send it in chunks to the network. Only one chunk will ever be loaded at a time in-memory on the client.
But obviously if you already have the entire message in memory don't bother and write it in one shot to the network socket.