I cannot get this example to run:
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
The only thing Ive changed with their code is to put everything in the main method, and my port name of course. I Can connect to my server, and even send data. But on the line
Int32 bytes = networkStream.Read(data, 0, data.Length);
The program stops running without an exception. How can microsoft own code not work? My server doesnt send anything yet, but I dont think that should matter? (It recieves perfectly though.) Ive Read something that you cannot se exceptions in other threads, but I dont have any.
I also tried this thread:
C# tcp socket (networkstream.read won't work with 8.1)
It doesnt work. I run win 7 thoguh. But I wish this to work an all new windows.
NetworkStream.Read blocks until data is available, the connection is closed (it will return 0 in that case) or an exception occurs. It is designed that way.
If your server would send data, your client program would continue and be able to process the response.
NetworkStream.Read() is a synchronous call, it will wait till a response is received. To read data of different lengths, you can do something like below.
NOTE: I'm assuming server is sending only one response for a request.
private string GetResponse(string command)
{
//Send request
TcpClient client = new TcpClient(HOST, PORT);
Byte[] data = Encoding.ASCII.GetBytes(command);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
//Read response
data = new Byte[BUFFER_SIZE];
String response = String.Empty;
stream.ReadTimeout = READ_TIMEOUT;
while (!response.EndsWith(RESPONSE_END))
{
int bytes = stream.Read(data, 0, data.Length);
response += Encoding.ASCII.GetString(data, 0, bytes);
}
response = response.Remove(response.Length - RESPONSE_END.Length);
stream.Close();
client.Close();
//Return
return response;
}
Related
I'm trying to receive a stream from a server via TCP/IP Socket connection and the length of the response is not always known.
The method in which I'm receiving to end is the following:
string resp = "";
do
{
bytesRec = clientSender.Receive(bytes);
resp += Encoding.UTF8.GetString(bytes, 0, bytesRec);
}
while (bytesRec != 0);
return resp;
But two weird things occur,
when it looks to do a second receive, it takes about 5 seconds for the server to respond. I know this is code related as when I use a 3rd party terminal to communicate, this delay doesn't happen
when I get to the end of the stream (byteRec == 0), something happens to the socket and I can longer send req through. I have to disconnect and reconnect (which wouldn't be an option because it requires a logon packet to be sent prior to sending requests)
Thanks in advance for any insight!
Easer way is use TcpClient.
string resp;
TcpClient tcpClient = new TcpClient();
tcpClient.Connect("hostname", 21);
StreamReader streamReader = new StreamReader(tcpClient.GetStream());
if(tcpClient.Connected)
resp = streamReader.ReadToEnd(); //or streamReader.ReadLine();
I remain frustrated in my attempts to send multiple TCP messages. I do not know what I have to do on the client side. I've tried using a Socket object and a TcpClient object. I can send one message with no problem. But what do I have to do to send a second message? Do I have to just discard the socket or TcpClient and create a new one? I've never yet been able to to get a second message to work.
Here is my latest attempt with TcpClient. It sends one message and displays the response successfully. But when I put a breakpoint on the first statement inside the while loop and look at the client object before sending the second message, I see that the client's Connected property is false. But on the next line, when I try to call Connect(), an exception is thrown claiming that the object is already connected.
Could somebody please explain what's going on, and what I have to do?
TcpClient client = new TcpClient();
while (true)
{
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes("This message came from the client.");
client.Connect("127.0.0.1", 5001);
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
// Receive the TcpServer.response.
// Buffer to store the response bytes.
data = new Byte[1024];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
stream.Close();
if (MessageBox.Show("Reply: " + responseData + " Try again?", "Try again?", MessageBoxButtons.YesNo) == DialogResult.No)
{
break;
}
}
This specifically is a question on what is going on in the background communications of NetworkStream consuming raw data over TCP. The TcpClient connection is communicating directly with a hardware device on the network. Every so often, at random times, the NetworkStream appears to hiccup, and can be best described while observing in debug mode. I have a read timeout set on the stream and when everything is working as expected, when stepping over Stream.Read, it will sit there and wait the length of the timeout period for incoming data. When not, only a small portion of the data comes through, the TcpClient still shows as open and connected, but Stream.Read no longer waits for the timeout period for incoming data. It immediately steps over to the next line, no data is received obviously, and no data will ever come through until everything is disposed of and a new connection is reestablished.
The question is, in this specific scenario, what state is the NetworkStream in at this point, what causes it, and why is the TcpClient connection still in a seemingly open and valid state? What is going on in the background? No errors thrown and captured, is the stream silently failing in the background? What is the difference between states of TcpClient and NetworkStream?
private TcpClient Client;
private NetworkStream Stream;
Client = new TcpClient();
var result = Client.BeginConnect(IPAddress, Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(2));
Client.EndConnect(result);
Stream = Client.GetStream();
try
{
while (Client.Connected)
{
bool flag = true;
StringBuilder sb = new StringBuilder();
while (!IsCompleteRecord(sb.ToString()) && Client.Connected)
{
string response = "";
byte[] data = new byte[512];
Stream.ReadTimeout = 60000;
try
{
int recv = Stream.Read(data, 0, data.Length);
response = Encoding.ASCII.GetString(data, 0, recv);
}
catch (Exception ex)
{
}
sb.Append(response);
}
string rec = sb.ToString();
// send off data
Stream.Flush();
}
}
catch (Exception ex)
{
}
You are not properly testing for the peer closing its end of the connection.
From this link : https://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.read%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396
This method reads data into the buffer parameter and returns the number of bytes successfully read. If no data is available for reading, the Read method returns 0. The Read operation reads as much data as is available, up to the number of bytes specified by the size parameter. If the remote host shuts down the connection, and all available data has been received, the Read method completes immediately and return zero bytes.
You are simply doing a stream.read, and not interpreting the fact that you might have received 0 bytes, which means that the peer closed its end of the connection. This is called a half close. It will not send to you anymore. At that point you should also close your end of the socket.
There is an example available here :
https://msdn.microsoft.com/en-us/library/bew39x2a(v=vs.110).aspx
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0) {
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer,0,StateObject.BufferSize,0,
new AsyncCallback(ReceiveCallback), state);
} else {
// All the data has arrived; put it in response.
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set(); ---> not that this event is set here
}
and in the main code block it is waiting for receiveDone:
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
// Release the socket.
client.Shutdown(SocketShutdown.Both);
client.Close();
Conclusion : check for reception of 0 bytes and close your end of the socket because that is what the other end has done.
A timeout is handled with an exception. You are not really doing anything with a timeout because your catch block is empty. You would just continue trying to receive.
#Philip has already answered ythe question.
I just want to add that I recommend the use of SysInternals TcpView, which is basically a GUI for netstat and lets you easily check the status of all network connections of your computer.
About the detection of the connection state in your program, see here in SO.
I have a method that reads some data through a TcpClient's NetworkStream, and it has been giving me some errors.
During investigation, I discovered that it actually worked fine... but only if I stepped through the code with Visual Studio 2012's debugger, using a breakpoint.
Here's my code:
public static byte[] DownloadStream(string hostname, int port,
byte[] requestBytes, int bufferSize = 4096)
{
byte[] responseBytes = null;
var client = new System.Net.Sockets.TcpClient(hostname, port);
if (client.Connected)
{
using (var stream = client.GetStream())
{
stream.Write(requestBytes, 0, requestBytes.Length);
stream.Flush();
if (stream.CanRead)
{
var responseStream = new System.IO.MemoryStream();
byte[] buffer = new byte[bufferSize];
int bytesRead = 0;
do
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
responseStream.Write(buffer, 0, bytesRead);
}
while (stream.DataAvailable);
responseBytes = responseStream.ToArray();
}
}
}
client.Close();
return responseBytes;
}
This is pretty frustrating, since there's no real error. It apparently just needs the debugger to hold its hand while it reads the NetworkStream.
Does anybody know why this is happening? How can I fix it?
Edit:
For some reason making this change eliminates the problem:
do
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
responseStream.Write(buffer, 0, bytesRead);
System.Threading.Thread.Sleep(1); //added this line
}
while (stream.DataAvailable);
Any insight on this?
The NetworkStream.DataAvailable property is not a reliable way to detect the end of the response; if the response is split into multiple TCP packets and a packet has not yet been delivered at the moment you check DataAvailable, then the property will return false, terminating your loop prematurely.
Apparently, your network connection is fast enough that Thread.Sleep(1) provides sufficient time for each successive packet to arrive. On a slower connection, though, it might not be adequate.
For reliable communication, the client and the server need to agree on a way to signal the end of the response. For example:
The server can send the length of the response as a prefix before the actual response. The client reads the length, and then it reads from the stream until it has received that number of bytes.
The server can send a special terminator as a suffix after the actual response. The client reads from the stream until it encounters the terminator. (Obviously, the terminator cannot appear anywhere in the response itself.)
The server can close the connection after it sends the entire response. The client reads from the stream until the connection is closed.
I have recently started getting into NetworkStreams, and I had a question. I am currently creating a thread, and processing all incoming messages as they come in.
Here is the code to illustrate this:
client.Connect(serverEndPoint);
clientStream = client.GetStream();
client.NoDelay = true;
ctThread = new Thread(getMessage);
ctThread.Start();
private void getMessage()
{
while (true)
{
Byte[] data = new Byte[800];
String responseData = String.Empty;
Int32 bytes = clientStream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
MessageReceived(this, new ClientMessageEventArgs(responseData));
}
}
In the above, I raise an event "MessageReceived" which is handled according the the packet data. This works great, but also have a seperate case where I need to retrieve data immediately after I send my request.
Is it ok to have two streams per client? Is this even possible to do on the same port? How should this be handled? Essentially, I want to be able to Send and then Receive data immediately after (blocking way).
You can read and write from network streams independently and in a thread safe manner. i.e. reading from one thread and writing from another.
If you checkout the open source network communication library networkComms.net you can see how this is achieved independently in the sending method SendPacket() (line 1304) and receiving method IncomingPacketHandler() (line 802).
Mx