I have a long running TCP connection. A machine (IoT device) establishes a connection with the server, connection is setup (encryption and stuff) and data stored, connection is kept open a while.
Everything kind of works but sometimes the server 'drops' the connection with an error:
An established connection was aborted by the software in your host machine (code: 10053 - ConnectionAborted). But the connection isn't dropped, cause server can read data from the device after the error and could start sending again. If the connection drops in real, both the server and client need to reinitialize connection (security and stuff).
There is nothing really that indicates why network stream cannot be written to.
And polling the socket says, that it's writetable, and in next point it throws an exception. Seems to happen randomly.
public class ClientIdentifier
{
...
public TcpClient Connection { get; set; }
public BlockDecoder ConnectionDecoder { get; set; }
}
private void ReplyToClient(ClientIdentifier client, byte[] data)
{
byte[] encrypted = client.ConnectionDecoder.Encrypt(data);
var stream = client.Connection.GetStream();
int dataIndex = 0;
while (dataIndex != encrypted.Length)
{
if (CanWriteClient(client))
{
byte[] block = encrypted.GetChunk(dataIndex, Frame.BLOCK_LENGTH);
stream.Write(block, 0, Frame.BLOCK_LENGTH);
dataIndex += Frame.BLOCK_LENGTH;
}
}
}
private bool CanWriteClient(ClientIdentifier client)
{
try
{
return client.Connection.Client.Poll(1000, SelectMode.SelectWrite);
}
catch (Exception ex)
{
Logger.Warn(ex, $"[{client.HexIdentifier}]: Polling client write failed");
return false;
}
}
EDIT (12.11.2017)
Server: 192.168.1.150
Device: 192.168.1.201
I can see that the device sends RST when the server resets Seq and Ack in some weird way.
Managed to find the mistake. Timeout was set to way too low.
...
TcpClient client = server.EndAcceptTcpClient(ar);
int timeout = (int)TimeSpan.FromSeconds(3).TotalMilliseconds;
client.ReceiveTimeout = timeout;
client.SendTimeout = timeout;
...
Related
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
I am trying to create an asynchronous methode to verify if i can connect with an host Through TCP. It seem like i am not releasing correctly all the memory i use.
I'm i forgetting something ?
My Connection Indicator is :
Bool CanConnectToHost = false;
My Function is :
private async void TryToConnectToHost()
{
// host IP Address and communication port
string ipAddress = Properties.Settings.Default.HostIPaddr;
int port = 9100;
//Try to Connect with the host
try
{
TcpClient client = new TcpClient();
await client.ConnectAsync(ipAddress, port);
//Verify if connected succesfully
if (client.Connected)
{
//Connection with host
CanConnectToHost = true;
}
else
{
// No connection with host
CanConnectToHost = false;
}
//Close Connection
client.Close();
}
catch (Exception exception)
{
//Do Something
}
}
Thx a lot
I don't think you need to care about memory here. What you probably observe is that the Garbage Collection doesn't bother to clean up all memory immediatly after your method is finished. It will do so eventually when it has time or your process starts to run out of free memory.
TcpClient.ConnectAsync() throws a SocketException if the connection cannot be established. So your code has the flaw that in case of that exception, you don't set your CanConnectToHost correctly (though it is false by initialization).
I recommend to use using here. That also has the advantage that Close() will also be called in case of the exception. And Close() will also free any resources used by the TcpClient immediatly and not only if GC starts to work.
Your code with using:
private async void TryToConnectToHost()
{
// host IP Address and communication port
string ipAddress = Properties.Settings.Default.HostIPaddr;
int port = 9100;
//Try to Connect with the host
try
{
using (TcpClient client = new TcpClient())
{
await client.ConnectAsync(ipAddress, port);
CanConnectToHost = client.Connected; // no need for if
}
}
catch (Exception exception)
{
CanConnectToHost = false;
}
}
Below is my code for the TCP server side. The problem is when the app on client machine closes, the server can't automically try to reconnect every 2 seconds until connected. How can I achieve that?
My idea is after connected to the client, server creates a status thread to send a byte to that client every 30s, if fail ---> terminate connection and retry to connect again. I'm not sure if its gonna work.
public static TcpClient client = new TcpClient();
public static int port = 6446;
public static string connectTo = "192.168.0.11";
public static NetworkStream dataStream;
static void Main(string[] args)
{
int retry = 0;
TryingConnect:
try
{
do
{
if (retry == 10)
{
retry = 0;
Console.Clear();
}
cout("Connecting...");
IPAddress ipAddress = IPAddress.Parse(connectTo);
client.Connect(ipAddress, port);
} while (client.Connected != true);
cout("Connected!");
dataStream = client.GetStream();
}
catch (Exception ex)
{
// Debug: MessageBox.Show(ex.ToString());
retry++;
Thread.Sleep(2000);
goto TryingConnect;
}
}
A server is the communication party which listen for connections from clients. A client is the one which initiates the connection. If you would like to server to recreate a lost connection to the client the server would actually be the client in this case because it initiates a new connection.
Apart from the meaning of the words client and server: if peer C likes S to connect to it C must be first listen and accept incoming connections, which is not the case for the common client. Even if C would do this the network of C must actually be reachable by S to create a new connection. This is often not the case, i.e if C is located in some local network (typical setup at home, work and often on mobile phone) then C is not reachable by S while C itself could reach S. Therefore S could not make a connection back to C.
I have a Visual Studio 2008 C# .NET 3.5 application running on Windows XP SP3 x86. In my application, I have an event handler OnSendTask that can be called by multiple threads simultaneously. It opens a TCP connection to a remote host and sends/receives data.
For example:
/// <summary>
/// prevent us from exceeding the maximum number of half-open TCP
/// connections in Windows XP.
/// </summary>
private System.Threading.Semaphore tcp_connection_lock_ =
new System.Threading.Semaphore(10, 10);
public event EventHandler<SendTaskEventArgs> SendTask;
private void OnSendTask(object sender, SendTaskEventArgs args)
{
try
{
tcp_connection_lock_.WaitOne();
using (TcpClient recipient = new TcpClient())
{
// error here!
recipient.Connect(args.IPAddress, args.Port);
using (NetworkStream stream = recipient.GetStream())
{
// read/write data
}
}
catch
{
// write exceptions to the logfile
}
finally
{
tcp_connection_lock_.Release();
}
}
void SendTasks(int tasks_to_send)
{
using (ManualResetEvent done_event = new ManualResetEvent(false))
{
int countdown = tasks_to_send;
for (int i = 0; i < tasks_to_send; ++i)
{
ThreadPool.QueueUserWorkItem((o) =>
{
SendTaskEventArgs args = new SendTaskEventArgs(/*...*/);
EventHandler<SendTaskEventArgs> evt = SendTask;
if (evt != null)
evt(this, e);
if (Interlocked.Decrement(ref countdown) == 0)
done_event.Set();
}, i);
}
done_event.WaitOne();
}
}
Unfortunately, I occasionally see this error:
System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 192.168.0.16:59596
at System.Net.Sockets.TcpClient.Connect(String hostname, Int32 port)
Some points of information:
If I send a task to 40 remotes, I will see this response from around 6.
A Wireshark trace shows no attempt to even initiate a TCP connection from the PC to the remote.
I can ping the remote from the PC and get consistent good responses.
The remotes are all on the same switch and subnet as the PC running this application. There is no fancy networking in the way.
Can anybody suggest what may be causing this error or how I can fix it?
Thanks
I am not sure of all of the details behind the max half-open TCP connections but, I believe it is NOT specific to application connections, but rather system wide. Are you sure that when this error occurs there are no other applications on the system that are creating TCP connections?
I'd setup a retry whenever an error occurs. Something like:
private const int MaxRetries = 10;
private void OnSendTask(object sender, SendTaskEventArgs args)
{
bool retry = false;
try
{
tcp_connection_lock_.WaitOne();
using (TcpClient recipient = new TcpClient())
{
// error here!
recipient.Connect(args.IPAddress, args.Port);
using (NetworkStream stream = recipient.GetStream())
{
// read/write data
}
}
}
catch (SocketException ex)
{
if(args.RetryCount < MaxRetries)
{
retry = true;
args.RetryCount++;
}
else
{
// write exceptions to the logfile
}
}
finally
{
tcp_connection_lock_.Release();
}
if(retry)
{
Thread.Sleep(1);
OnSendTask(sender, args);
}
}
I need to poll a server, which is running some propriatary software, to determine if this service is running. Using wireshark, I've been able to narrow down the TCP port its using, but it appears that the traffic is encrypted.
In my case, its a safe bet that if the server is accepting connections (i.e. telnet serverName 1234) the service is up and all is OK. In other words, I don't need do any actual data exchange, just open a connection and then safely close it.
I'm wondering how I can emulate this with C# and Sockets. My network programming basically ends with WebClient, so any help here is really appreciated.
The process is actually very simple.
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
try
{
socket.Connect(host, port);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.ConnectionRefused)
{
// ...
}
}
}
Just use TcpClient try to connect to the server, TcpClient.Connect will throw an exception if the connection fails.
bool IsListening(string server, int port)
{
using(TcpClient client = new TcpClient())
{
try
{
client.Connect(server, port);
}
catch(SocketException)
{
return false;
}
client.Close();
return true;
}
}
I've used the following code. There is one caveat ... in a high transaction environment, the client's available ports may run out as the sockets are not released by the OS at the same rate they are released by the .NET code.
If anyone's got a better idea, please post. I've seen snowball issues arise where the server can no longer make outgoing connections. I'm working on a better solution ...
public static bool IsServerUp(string server, int port, int timeout)
{
bool isUp;
try
{
using (TcpClient tcp = new TcpClient())
{
IAsyncResult ar = tcp.BeginConnect(server, port, null, null);
WaitHandle wh = ar.AsyncWaitHandle;
try
{
if (!wh.WaitOne(TimeSpan.FromMilliseconds(timeout), false))
{
tcp.EndConnect(ar);
tcp.Close();
throw new SocketException();
}
isUp = true;
tcp.EndConnect(ar);
}
finally
{
wh.Close();
}
}
}
catch (SocketException e)
{
LOGGER.Warn(string.Format("TCP connection to server {0} failed.", server), e);
isUp = false;
}
return isUp;
Use the TcpClient class to connect the server.