TcpClient established, but TcpClient.getStream() fails - c#

My Client class for synchronous message exchange:
public class AsClient
{
private TcpClient connection;
public AsClient(int serverPort, String ip)
{
connection = new TcpClient(ip, port);
}
public AsMessage sendMessage(AsMessage message)
{
System.Diagnostics.Debug.WriteLine("Connected: " + connection.Connected);
NetworkStream ns = connection.GetStream();
StreamReader reader = new StreamReader(ns);
StreamWriter writer = new StreamWriter(ns);
// Send Message:
String msgToSendEncoded = message.encode();
writer.WriteLine(msgToSendEncoded);
writer.WriteLine("\n"); // each message is terminated by a paragraph
writer.Flush();
// Receive Message:
String msgReceivedRaw = reader.ReadLine();
AsMessage response = AsMessage.decode(msgReceivedRaw);
reader.Dispose();
writer.Dispose();
ns.Close();
return response;
}
}
If I debug this application, the first message sent and response received works perfectly well, but as soon as I want to send the second message, TcpClient.getStream() fails with the InvalidOperationException, which states that the connection is not established anymore.
The problem is that I am not actively closing the connection anywhere. If I put connection.Connect(host,port) before calling getStream(), it fails with the exception that the socket is still connected, even though connection.Connected is false.
Any ideas to solve this issue?

As I have experience Dispose close the underlying stream.
So you close the connection on the Dispose.

I'm running into the same problem with this piece of code that replicates follows the steps in the MS documentation for GetStream(): https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.getstream?view=netframework-4.8
public void Send(String message)
{
try
{
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = Encoding.ASCII.GetBytes(message);
// Get a client stream for reading and writing.
NetworkStream stream = Client.GetStream();
stream.Write(data, 0, data.Length);
stream.Close(); // this also closses the connection the server!
}
catch (Exception e)
{
LogException(e);
}
}
What we see on the server side is that:
1) The connection is established.
2) The message never arrives.
3) when the stream.Close() statement executes, the server reports that the client closed the connection.
Inspecting the properties of stream I can see that streams OWNS the socket. So, wen it closes it must also close its socket. How come???

Related

Server Timeout C#

So, I'm developing a client-side application in C# that connects to a server side application (also written in C#). To begin with, I am just trying to get the applications to successfully communicate with one another. Currently, I have both the client and server running on the same device.
Server Side
On the server side, I'm using a TcpListener to accept a socket, printing out that it has connected for debugging purposes, receiving a request, and sending a response. The code can be found below:
Server Side Code:
while (true)
{
// Accept a new connection
Socket socket = socketListener.AcceptSocket();
if (socket.Connected)
{
Console.WriteLine("\nClient Connected!!\n==================\nClient IP {0}\n", socket.RemoteEndPoint);
// Make a byte array and receive data from the client
byte[] receive = new byte[1024];
_ = socket.Receive(receive, receive.Length, 0);
// Convert byte to string
string buffer = Encoding.ASCII.GetString(receive);
string response = "Test response";
int numBytes = 0;
try
{
if (socket.Connected)
{
if ((numBytes = socket.Send(data, data.Length, 0)) == -1)
Console.WriteLine("Socket Error: cannot send packet");
else
Console.WriteLine("No. of bytes sent {0}", numBytes);
}
else
{
Console.WriteLine("Connection Dropped...");
}
}
catch (Exception e)
{
Console.WriteLine("An exception has occurred: " + e.ToString());
}
}
}
Client Side
On the client side, I'm using a TcpClient to connect to the server using an IP address (In this case it's 127.0.0.1), establishing a NetworkStream object, sending a request, and reading a response.
Client-Side Code:
private static readonly TcpClient socket = new TcpClient();
private const string IP = "127.0.0.1";
private const int PORT = 46495;
static void Main(string[] args)
{
try
{
socket.Connect(IP, PORT);
}
catch (Exception)
{
Console.WriteLine("Error connecting to the server.");
return;
}
NetworkStream stream = socket.GetStream();
stream.ReadTimeout = 2000;
string request = "Test Request";
byte[] bytes = Encoding.UTF8.GetBytes(request);
stream.Write(bytes, 0, bytes.Length);
StreamReader reader = new StreamReader(stream, Encoding.UTF8);
try
{
string response = reader.ReadToEnd();
Console.WriteLine(response);
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
The Output
On the server side, everything appears to be fine. The client connects successfully with the expected IP address, I get the expected request, and the correct response appears to have been sent successfully.
The client-side is where it gets more complicated. Where I would expect the "Test Response" response, instead I get a SocketException that from what I understand indicates a timeout??? The full output can be found below:
System.IO.IOException: Unable to read data from the transport connection: A connection attempt failed because the connected party did not properly respond after a period of time, or an established connection failed because the connected host has failed to respond...
---> System.Net.Sockets.SocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or an established connection failed because the connected host has failed to respond.
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.IO.StreamReader.ReadBuffer()
at System.IO.StreamReader.ReadToEnd()
at Client.Client.Main(String[] args) in C:\Dev\Project Orange Sunshine\Project Orange Sunshine\Client\Client.cs:line 38
What I have tried
To begin I wanted to ensure that my server was in fact sending a response in the first place. To test this, I tried accessing the server application through a web browser. Sure enough, I got a blank page with the expected "Test Response" text in the top left corner. This, to me, indicates my server application is working as expected.
Through some googling, I have found a variety of answers to similar questions stating that it is likely that the Windows Defender Firewall is blocking the port that is being used. For testing purposes, I tried disabling the firewall entirely for private networks such as the one that I am on. This didn't change anything, unfortunately.
I feel like I am missing something obvious and any input would be greatly appreciated.
Cheers!
StreamReader.ReadToEnd() on a NetworkStream will only return once the "end" of the stream is reached, which doesn't happen in your example; thus, the StreamReader times out.
You should fix this by using the lower-level NetworkStream.Read method to read from the stream:
var buffer = new byte[4096];
var bytesRead = stream.Read(buffer, 0, buffer.Length);
Console.WriteLine("Read {0} bytes", bytesRead);
string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine(response);
To make this test program more robust, you will also need to introduce "framing", i.e., some way for the server to indicate to the client that it can stop reading. This can be a terminator suffix, such as \r\n used by HTTP, or a length prefix that is sent upfront to tell the client how many more bytes to read.

TCP Client Not Reconnecting After Disconnect

I've made a server and a client. The client should re-attempt to connect to the server if I close the server. I've made it so when the try/catch during waitForCommands fails, it restarts the attemptConnection method in a new thread. The problem I have here is that it simply won't reconnect. As a test, I open my TCP server and the TCP client. The client connects to the server as usual. Then, I close the TCP Server, and the clients spits out this error: 'System.Net.Sockets.SocketException' rapidly, and never connects.
class Program
{
public static TcpClient client = new TcpClient();
public static NetworkStream stream;
public static byte[] readBuffer;
static void Main(string[] args)
{
new Thread(attemptConnection).Start();
}
public static void waitForCommands()
{
while (client.Connected)
{
try
{
readBuffer = new byte[client.ReceiveBufferSize];
int data = stream.Read(readBuffer, 0, readBuffer.Length);
string plainText = Encoding.ASCII.GetString(readBuffer, 0, data);
if (plainText.Contains("mbox"))
{
MessageBox.Show("");
}
}
catch
{
new Thread(attemptConnection).Start();
}
}
}
public static void attemptConnection()
{
while(!client.Connected)
{
try
{
client.Connect("127.0.0.1", 23154);
stream = client.GetStream();
new Thread(waitForCommands).Start();
}
catch(Exception ex)
{
Console.WriteLine(ex.Data);
}
}
}
}
An interesting thing I noticed, is that if I write 'client.Close();' on the server exit event, I get no error messages when the client tries to reconnect. It just shows a blank screen and does nothing
If you'd like to see the code that waits for connections on my server, it's really simple so I'm not sure why this problem is occuring.
public static void waitForConnection()
{
server.Start();
client = server.AcceptTcpClient();
stream = client.GetStream();
f.labelControl1.Text = "Connected";
}
To expand on my comment, I think it's due to the underlying TCP connection (the network stream) not closing automatically.
Try closing the stream manually and see what it does:
client.GetStream().Close();
You could also just close the client which closes the stream for you (see https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close.aspx):
client.Close();
And another way to resolve your issue (see https://stackoverflow.com/a/38006848/4408417):
client.Client.Disconnect(true);
I changed client.Connect() to
client = new TcpClient();
client.Connect("127.0.0.1", 23154);
As Jasper recommended in the comments

Do I have to create a new TcpClient for each message I send?

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;
}
}

TCP Socket/NetworkStream Unexpectedly Failing

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.

C# TCP Server Reply Packet Issue

I have been banging my head against my code for the better part of the day, and I am completely stumped. Basically, the source game engine has a documented protocol for its RCON (Remote Console Over Network?) which I am trying to reproduce. There are hundreds of examples, but all of them are from the client side (establishing a connection to the game server's RCON) where as I am trying to actually re-create the server portion to reply to clients.
Here is the information on the RCON Protocol. The problem I am having with the code is, when I receive the Authentication request everything is fine. When I attempt to reply to it and okay the connection, the connection fails. So I am doing something wrong when replying but not sure what.
http://developer.valvesoftware.com/wiki/Source_RCON_Protocol
private void ReadClientPacket(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
while (true)
{
try
{
int packetsize;
// Create a new Packet Object and fill out the data from the incoming TCP Packets
RCONPacket packet = new RCONPacket();
using (BinaryReader reader = new BinaryReader(clientStream))
{
// First Int32 is Packet Size
packetsize = reader.ReadInt32();
packet.RequestId = reader.ReadInt32();
packet.RconDataReceived = (RCONPacket.RCONDATA_rec)reader.ReadInt32();
Console.WriteLine("Packet Size: {0} RequestID: {1} ServerData: {2}", packetsize, packet.RequestId, packet.RconDataReceived);
// Read first and second String in the Packet (UTF8 Null Terminated)
packet.String1 = ReadBytesString(reader);
packet.String2 = ReadBytesString(reader);
Console.WriteLine("String1: {0} String2: {1}", packet.String1, packet.String2);
switch (packet.RconDataReceived)
{
case RCONPacket.RCONDATA_rec.SERVERDATA_AUTH:
{
ReplyAuthRequest(packet.RequestId, tcpClient);
break;
}
case RCONPacket.RCONDATA_rec.SERVERDATA_EXECCOMMAND:
{
//ReplyExecCommand(packet.RequestId, tcpClient);
break;
}
default:
{
break;
}
}
}
break;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
break;
}
}
tcpClient.Close();
}
private void ReplyAuthRequest(int RequestID, TcpClient client)
{
Console.WriteLine("Replying to Auth Request");
// Authentication Reply
using (NetworkStream clientStream = client.GetStream())
using (MemoryStream stream = new MemoryStream())
using (BinaryWriter writer = new BinaryWriter(stream))
{
writer.Write((int)10); // Packet Size
writer.Write(RequestID); // Mirror RequestID if Authenticated, -1 if Failed
writer.Write((int)RCONPacket.RCONDATA_sent.SERVERDATA_AUTH_RESPONSE);
writer.Write(ConvertStringToByteArray("" + char.MinValue));
writer.Write(ConvertStringToByteArray("" + char.MinValue));
byte[] buffer = stream.ToArray();
Console.WriteLine("size of full auth response packet is {0}", buffer.Length);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
Have you been using Wireshark?
This tool is essential when you try to copy/reverse-engineer existing protocols. Just do a normal authentication with a known-working client and save the log. Then use your own code and try to see where the bits sent on the wire are different from those in the log.
Sometimes its pretty difficult things to see just by looking at the code, like a '\n' getting inserted at the wrong point, or an extra line after the whole message
I've had a similar problem a while ago
In your Reply function :
using (NetworkStream clientStream = client.GetStream())
(...)
The disposal of the clientStream could be the culprit. In my case the disposal of the stream caused the connection termination, GetStream() doesn't return a new instance of a stream, it returns the Stream that is owned by the TCPClient. See if that helps.

Categories

Resources