I have mobile RF terminal with Windows CE 6.0 CF 3.5 and I need send data as quickly as possible to my server.
Problem is that wifi connection is not stable enough in place of use.
I reduced the loss of data with repeated sending when connection is aborted by exception. But time for exception is ~21sec and it's too long for me. Repeated connections are successful (mostly), but I need shorten time for exception, or find different method for connection.
For data receive I have TCP server in terminal. And here I have one thread with timer and after my timeout I close client (TcpClient) and catch exception from this :-). But I mean that this method is not ideal.
Any ideas??
Thanks!
Below is my code for TCP client connection
internal string TCPsend(string strMessage)
{
string exception = string.Empty;
TcpClient client = null;
try
{
client = new TcpClient(IPServer, PortServer);
client.SendTimeout = 500; //no effect
Stream stream = client.GetStream();
StreamWriter strWriter = new StreamWriter(stream);
strWriter.Write(strMessage);
strWriter.Close();
}
catch (Exception ex)
{
exception = ex.ToString();
utility.SaveExceptionLog("SendTCP A: " + ex.ToString());
}
finally
{
if (client != null)
{
client.Close();
}
}
return exception;
}
If you want to take connectivity check into your hands, probably you should open new thread, where you will check in a loop for an established connection.
Here is the answer where the trivial check disscussed: What is the best way to check for Internet connectivity using .NET?
This will impact on overall sending performance, but should reduce the waiting time.
Related
I am using TCP as a mechanism for keep alive here is my code:
Client
TcpClient keepAliveTcpClient = new TcpClient();
keepAliveTcpClient.Connect(HostId, tcpPort);
//this 'read' is supposed to blocked till a legal disconnect is requested
//or till the server unexpectedly dissapears
int numberOfByptes = keepAliveTcpClient.GetStream().Read(new byte[10], 0, 10);
//more client code...
Server
TcpListener _tcpListener = new TcpListener(IPAddress.Any, 1000);
_tcpListener.Start();
_tcpClient = _tcpListener.AcceptTcpClient();
Tracer.Write(Tracer.TraceLevel.INFO, "get a client");
buffer = new byte[10];
numOfBytes = _tcpClient.GetStream().Read(buffer, 0, buffer.Length);
if(numOfBytes==0)
{
//shouldn't reach here unless the connection is close...
}
I put only the relevant code... Now what that happens is that the client code is block on read as expected, but the server read return immediately with numOfBytes equals to 0, even if I retry to do read on the server it return immediately... but the client read is still block! so in the server side I think mistakenly that the client is disconnected from the server but the client thinks it connected to the server... someone can tell how it is possible? or what is wrong with my mechanism?
Edit: After a failure I wrote to the log these properties:
_tcpClient: _tcpClient.Connected=true
Socket: (_tcpClient.Client properties)
_tcpClient.Client.Available=0
_tcpClient.Client.Blocking=true
_tcpClient.Client.Connected=true
_tcpClient.Client.IsBound=true
Stream details
_tcpClient.GetStream().DataAvailable=false;
Even when correctly implemented, this approach will only detect some remote server failures. Consider the case where the intervening network partitions the two machines. Then, only when the underlying TCP stack sends a transport level keep-alive will the system detect the failure. Keepalive is a good description of the problem. [Does a TCP socket connection have a “keep alive”?] 2 is a companion question. The RFC indicates the functionality is optional.
The only certain way to reliably confirm that the other party is still alive is to occasionally send actual data between the two endpoints. This will result in TCP promptly detecting the failure and reporting it back to the application.
Maybe something that will give clue: it happens only when 10 or more clients
connect the server the same time(the server listen to 10 or more ports).
If you're writing this code on Windows 7/8, you may be running into a connection limit issue. Microsoft's license allows 20 concurrent connections, but the wording is very specific:
[Start->Run->winver, click "Microsoft Software License Terms"]
3e. Device Connections. You may allow up to 20 other devices to access software installed on the licensed computer to use only File Services, Print Services, Internet Information Services and Internet Connection Sharing and Telephony Services.
Since what you're doing isn't file, print, IIS, ICS, or telephony, it's possible that the previous connection limit of 10 from XP/Vista is still enforced in these circumstances. Set a limit of concurrent connections to 9 in your code temporarily, and see if it keeps happening.
The way I am interpretting the MSDN remarks it seems that behavior is expected. If you have no data the Read the method returns.
With that in mind I think what I would try is to send data at a specified interval like some of the previous suggestions along with a "timeout" of some sort. If you don't see the "ping" within your designated interval you could fail the keepalive. With TCP you have to keep in mind that there is no requirement to deem a connection "broken" just because you aren't seeing data. You could completely unplug the network cables and the connection will still be considered good up until the point that you send some data. Once you send data you'll see one of 2 behaviors. Either you'll never see a response (listening machine was shutdown?) or you'll get an "ack-reset" (listening machine is no longer listening on that particular socket)
https://msdn.microsoft.com/en-us/library/vstudio/system.net.sockets.networkstream.read(v=vs.100).aspx
Remarks:
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.
As I can see you are reading data on both sides, server and client. You need to write some data from the server to the client, to ensure that your client will have something to read. You can find a small test program below (The Task stuff is just to run the Server and Client in the same program).
class Program
{
private static Task _tcpServerTask;
private const int ServerPort = 1000;
static void Main(string[] args)
{
StartTcpServer();
KeepAlive();
Console.ReadKey();
}
private static void StartTcpServer()
{
_tcpServerTask = new Task(() =>
{
var tcpListener = new TcpListener(IPAddress.Any, ServerPort);
tcpListener.Start();
var tcpClient = tcpListener.AcceptTcpClient();
Console.WriteLine("Server got client ...");
using (var stream = tcpClient.GetStream())
{
const string message = "Stay alive!!!";
var arrayMessage = Encoding.UTF8.GetBytes(message);
stream.Write(arrayMessage, 0, arrayMessage.Length);
}
tcpListener.Stop();
});
_tcpServerTask.Start();
}
private static void KeepAlive()
{
var tcpClient = new TcpClient();
tcpClient.Connect("127.0.0.1", ServerPort);
using (var stream = tcpClient.GetStream())
{
var buffer = new byte[16];
while (stream.Read(buffer, 0, buffer.Length) != 0)
Console.WriteLine("Client received: {0} ", Encoding.UTF8.GetString(buffer));
}
}
}
I'm new to c# and trying to set up a server client connection for some test purpose.
Currently I have this snippet letting my client app crashing when it trys to connect while the server isn't running. It seems to me the crash is happening in the client.Connect line, letting me no chance to prevent this, as it didn't return form the method when the crash happens.
Also looking on MSDN didn't give me some usefull info.
so would I have to make some preperation?
because just checking a return value isn't possible as the crash happens inside the method.
Or is there a way I had to check before for I run the connect mehtod for connectability?
Int32 port = 4999;
Byte[] teststring;
GameConfiguration objGameConfClient = new GameConfiguration();
TcpClient client = new TcpClient();
client.Connect("XXX.XXX.XXX.XXX", port);
if (client == null)
{
return;
}
http://msdn.microsoft.com/de-de/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
The MSDN example apears to me also not handling this crash, is it?
try
{
client.Connect("XXX.XXX.XXX.XXX", port);
}
catch(Exception e)
{
//XXX
}
I am using Asynchronous TCP server/client communication. I have noticed in my log that the same client reconnects several times. However, it never shows that it was disconnected. My code has logging for both connection and disconnection. So why does readAsync stay in loop while the client has disconnected? Here is the code for your reference:
private async Task Accept(TcpClient client)
{
//get client information
string clientEndPoint = GetClientIPAddress(client);
log.Info("Client connected at " + clientEndPoint); //same client is connected several times in log
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream ())
{
byte[] dataReceived = new byte [100];
while (await stream.ReadAsync(dataReceived, 0, dataReceived.Length) != 0) //read input stream - 0=>end of stream is reached
{
//pass on data for processing
var task = ProcessData(dataReceived);
}
}
log.Info("Closing client connection " + clientEndPoint);//this line is never reached in log
if (client.Connected)
client.Close();
} //end try
catch (Exception ex)
{
log.Error(ex.Message);
log.Info("Closing client connection " + clientEndPoint);
if (client.Connected)
client.Close();
}
It looks like you may have a half-open problem. You should periodically write data to determine whether the socket is still connected; reads can detect graceful shutdowns but not half-open scenarios.
I describe the half-open problem more on my blog.
Did you check if TCP keep alive is set? That should detect if connection is broken.
Also, check if you got zero length bytes on receive, this means that connection is closed.
Edit: Keep Alive is standard method to check if connection is active, this means that one side sends small chunks of data to the other side periodically: http://en.wikipedia.org/wiki/Keepalive.
Many components have this feature already implemented. I've never used TcpClient class, but it must be some wrapper class for Socket over TCP and, as doc states, this class have exposed underlaying Socket (you can use Socket class for TCP also, but never mind). And this Socket have method SetSocketOption. So try:
client.Socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.KeepAlive, true);
Is there a reason why a Socket should close by itself, after 2h? I am receiving data every second from this socket, and writing back some tiny "keep-alive" data every 30s.
Before sending, I check if socket is still connected using the following method:
public bool IsSocketReadyForWriting(Socket s)
{
try
{
if (!s.Connected)
{
Log.Info("Socket.Connected was false");
return false;
}
// following line will throw if socket disconnected
bool poll = s.Poll(2000, SelectMode.SelectWrite);
if (!poll)
{
try
{
// if poll is false, socket is closed
Log.Info("poll is false");
this.Close();
}
catch { }
return false;
}
Log.Debug("still connected");
return true;
}
catch (Exception ex)
{
Log.Error("Error while checking if socket connected", ex);
return false;
}
}
Everything works fine for about 2h, then suddenly Socket.Poll returns false, and the Socket gets closed.
Is there a setting which controls this, or am I doing something really wrong?
[Edit]
Forgot to mention: I control both server and client side of the link. These are both C# apps, one of them creates a listening socket, the other one opens a connection and sends data. They communicate without problems for 2h (no memory leaks and stuff), then the socket closes.
When this happens, I can reconnect the socket again easily, but I am just wandering if anyone knows why could be the reason for this.
By default a TCP socket is writable when there's at least one byte of space available in the socket send buffer. To reverse that - the socket is not writable when there's enough unacknowledged data sitting in the "output queue".
That said, pull out wireshark or whatever Microsoft provides for packet sniffing and see what's going on on the wire. Are your heartbeat chunks getting ACK-ed? Does the receiver window stay open or does it go to zero? Or are you just getting explicit RST or a FIN from some intermediate switch?
One way to mitigate temporary clogged pipe is to increase the send buffer size, which is kind of tiny by default on Windows - 8192 iirc. See the setsockopt (.NET probably has a version of that) and the SO_SNDBUF option.
Could be the server that is closing the connection? Do you have control over it?
I'm trying to find out whether a Socket is currently connected - according to the MSDN docs for Socket.Connected - I should do the following:
// This is how you can determine whether a socket is still connected.
bool blockingState = client.Blocking;
try
{
byte [] tmp = new byte[1];
client.Blocking = false;
client.Send(tmp, 0, 0);
Console.WriteLine("Connected!");
}
catch (SocketException e)
{
// 10035 == WSAEWOULDBLOCK
if (e.NativeErrorCode.Equals(10035))
Console.WriteLine("Still Connected, but the Send would block");
else
{
Console.WriteLine("Disconnected: error code {0}!", e.NativeErrorCode);
}
}
finally
{
client.Blocking = blockingState;
}
Console.WriteLine("Connected: {0}", client.Connected);
I've tested this works by connecting the socket to a remote server running on Windows and killing the remote server and it works fine.
However, if I do the same with a remote Server running on Unix (in this case MAC OS X) then the code does not work - the client.Send(tmp, 0, 0) call completes without throwing an exception and prints "Connected: true".
I'm guessing this has something to do with the fact that the other side of the connection has closed so the send may still work but a receive would fail - can I do a zero-byte Receive or something to see if the socket is closed?
Yes, you can.
Calling Send only really checks if the local socket is open. Calling Receive will check the other end too.
Maybe you can sniff with Wireshark the traffic and see if there are any difference if the dying server side is a windows or unix system.
Maybe the dying windows system is able to send a tcp close while the unix system can't. That would explain the difference (but maybe not help your actual problem).
btw, if you would use a udp connection you could never determine if the other site is living, due to the fact this would be a send & forget communication.