ConnectAsync blocking UI Thread - sockets

I have simple WinRT application, that will be communicating with remote server via TCP.
In order to do that I'm creating new StreamSocket object, and connecting to remote server after clicking a proper button, like this:
private async void ConnectButtonClick(object sender, RoutedEventArgs e)
{
StreamSocket socket = new StreamSocket();
HostName host = new HostName("192.168.1.15");
await socket.ConnectAsync(host, "12121");
}
The problem is that this code is blocking the UI thread. I've created simple animation, using MonoGame (couple of moving sprites) that is running on the screen continously, in order to check if UI is blocked.
The problem is, that after clicking Connect button, animation is freezing for a second, so I assume that, connecting to the server is made in the UI thread.
Should I put my whole network code into a separate thread, or is this async/await enough?
I'd like to implement a loop, that will handle incoming data (with help od DataReader), like this:
private async void ReceiveLoop()
{
bool running = true;
while (running)
{
try
{
uint numStrBytes = await _reader.LoadAsync(BufferSize);
if (numStrBytes == 0)
{
Disconnect();
return;
}
string msg = _reader.ReadString(numStrBytes);
OnLog(string.Format("Received: {0}", msg));
OnDataReceived(msg);
}
catch (Exception exception)
{
OnLog("Receive failed with error: " + exception.Message);
Disconnect();
running = false;
}
}
}
Sending data will be done using StoreAsync from DataWriter.
So should I put these functions into separate threads?

Can't you just try doing that on a background thread to see if that helps? Something like this:
Task.Run(
async () =>
{
StreamSocket socket = new StreamSocket();
HostName host = new HostName("192.168.1.15");
await socket.ConnectAsync(host, "12121");
});

For any async calls in a normal .net library, the general rule is to use ConfigureAwait(false) which helps prevent issues like you are seeing. So for instance in WinRT stuff it would be:
await socket.ConnectAsync(host, "12121").AsTask().ConfigureAwait(false);
This has some great information:
http://blogs.msdn.com/b/windowsappdev/archive/2012/04/24/diving-deep-with-winrt-and-await.aspx

Related

UWP - StreamSocket connection error for some connections

We have 2 UWP apps. One app shares data to the other app through StreamSocket. The server app will send data to client app. There will be 30-40 or more devices running the client app and connecting to the server's socket to receive data.
When we test with one client app, all the data sharing happens without any issue. But when we started testing with about 10 devices using the client app, sometimes some apps don't receive data. And there seems to be an error saying 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
In general it get shared to most of the devices, but few fails sometimes randomly. What could be the reason for this? Is there a connection limit to connect to a socket with given IP and port using Stream Socket?
Here is some parts of our code. Please let me know what we have to correct here to avoid getting that error.
Server side
public async Task StartServer(string serverIp, string serverPort)
{
try
{
HostName serverAddress = new HostName(serverIp);
//Create a StreamSocketListener to start listening for TCP connections.
StreamSocketListener socketListener = new StreamSocketListener();
//Hook up an event handler to call when connections are received.
socketListener.ConnectionReceived += SocketListener_ConnectionReceived;
//Start listening for incoming TCP connections on the specified port.
await socketListener.BindEndpointAsync(serverAddress, serverPort);
}
catch (Exception e)
{
}
}
private async void SocketListener_ConnectionReceived(StreamSocketListener sender, StreamSocketListenerConnectionReceivedEventArgs args)
{
try
{
await Task.Run(() => ShareFile(args.Socket));
}
catch (Exception e)
{
}
}
Client side
public async Task ServerConnect(string serverIP, string serverPort)
{
try
{
HostName serverAddress = new HostName(serverIP);
StreamSocket socket = new StreamSocket();
socket.Control.KeepAlive = false;
// Connect to the server.
await socket.ConnectAsync(serverAddress, serverPort, SocketProtectionLevel.PlainSocket);
}
catch (Exception e)
{
}
}
Also would like to get these clarified
-What is the difference between BindServiceNameAsync and BindEndpointAsync? Most examples seems to use the first one. When should we use the second one?
-If we call sender.Dispose(); in SocketListener_ConnectionReceived, will that affect the other clients trying to join the same socket?
-In the ShareFile() function, if we close args.Socket() after sending data, can it close the socket before the client actually read the data from that side?

Connection not working from Android to UWP on desktop - ZeroMq (NetMq)

I tried some examples of ZMQ on C++,C# and Python. I am trying to have Request-Reply pattern to connect Android device to PC running UWP with Xamarin forms.
Below is the Requestor code:
public void HelloWorld()
{
var timer = new Timer(60000);
timer.Start();
timer.Elapsed += (sender, args) =>
{
this.Cancel = true;
timer.Stop();
};
// Create
const string endpoint = "tcp://PC_ip:3245";
using (var request = new RequestSocket())
{
request.Bind(endpoint);
Thread.Sleep(2000);
while (!Cancel)
{
request.SendFrame("Requester says hello");
var reply = request.ReceiveFrameString();
Debug.WriteLine("Gets reply {0}",reply);
}
}
}
Reply socket code:
public void HelloWorld()
{
var timer = new Timer(60000);
const string endpoint = "tcp://PC_ip:3245";
timer.Start();
timer.Elapsed += (sender, args) =>
{
timer.Stop();
Cancel = true;
};
using (var replierSocket = new ResponseSocket())
{
replierSocket.Connect(endpoint);
Thread.Sleep(2000);
while (!Cancel)
{
var replyFromRequester = replierSocket.ReceiveFrameString();
Debug.WriteLine("Got reply {0}", replyFromRequester);
replierSocket.SendFrame("Response socket say hello");
}
}
}
Cancel is boolean
I went through some questions posted on this and added delay and these connection code blocks only trigger after button clicks on app.
While debugging , request.ReceiveFrameString() replierSocket.ReceiveFrameString(); are not even hit.
I am new to network programming , I understand that for REQ/REP pattern the code has to be in particular order which I traced and fixed I believe and turned off firewall on my PC so that firewall wont block my incoming connections from Android device.
PC_ip stands for IPv4 address I got from ipconfig /all for my wifi. I also tried external ip of my machine from sites like whatsmyip.org at ResponseSocket but I still dont get response between devices.
Please let me know what am I doing wrong.
Issue replication repository : GitHub/me/XamZeroMq

UWP streamsocket ping networktimer issues

I have a StreamSocket in UWP and I send my messages like this using a DataWriter object using the StoreAsync() method:
public static async Task<bool> SendNetworkMessage(NetworkMember member, NetworkMessage message)
{
DataWriter writer = member.DataWriter;
//Check that writer is not null
if (writer != null)
{
try
{
//Serialize Message
string stringToSend = SerializeObject<NetworkMessage>(message);
//Send Message Length
writer.WriteUInt32(writer.MeasureString(stringToSend));
//Send Message
writer.WriteString(stringToSend);
await writer.StoreAsync();
return true;
}
catch (Exception e)
{
Debug.WriteLine("DataWriter failed because of " + e.Message);
Debug.WriteLine("");
Disconnect(member);
OnMemberDisconnectedEvent(member);
return false;
}
}
else { return false; }
}
All is well, the only problem is that I don't know if a connection went down.
Now I want to check my connection using a DispatcherTimer like this:
private static async void NetworkTimer_Tick(object sender, object e)
{
foreach (NetworkMember member in networkMemberCollection)
{
if (member.Connected == true && member.Disconnecting == false)
{
await SendNetworkMessage(member, new PingMessage());
}
}}
However, this is causing timing issues which is causing ObjectDisposedExceptions on the DataWriter. It seems that the DispatcherTimer thread cannot use the StreamSocket when I send a message from a different thread. My question is: How can I make sure the Ping is sent each time but that SendNetworkMessage operations are done in order instead of overlapping?
Thanks
It seems that the DispatcherTimer thread cannot use the StreamSocket when I send a message from a different thread.
How can I make sure the Ping is sent each time but that SendNetworkMessage operations are done in order instead of overlapping?
It's possible, and I think your code using foreach and await operation can ensure the work of sending message in order.
the only problem is that I don't know if a connection went down.
If you want to know if the connection went down, you can refer to Handling WinRT StreamSocket disconnects (both server and client side).

Cloud Service for incoming TCP connections hangs

I'm developing a cloud service (worker role) for collecting data from a number of instruments. These instruments reports data randomly every minute or so. The service itself is not performance critical and doesn't need to be asynchronous. The instruments are able to resend their data up to an hour on failed connection attempt.
I have tried several implementations for my cloud service including this one:
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.stop(v=vs.110).aspx
But all of them hang my cloud server sooner or later (sometimes within an hour).
I suspect something is wrong with my code. I have a lot of logging in my code but I get no errors. The service just stops to receive incoming connections.
In Azure portal it seems like the service is running fine. No error logs and no suspicious cpu usage etc.
If I restart the service it will run fine again until it hangs next time.
Would be most grateful if someone could help me with this.
public class WorkerRole : RoleEntryPoint
{
private LoggingService _loggingService;
public override void Run()
{
_loggingService = new LoggingService();
StartListeningForIncommingTCPConnections();
}
private void StartListeningForIncommingTCPConnections()
{
TcpListener listener = null;
try
{
listener = new TcpListener(RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["WatchMeEndpoint"].IPEndpoint);
listener.Start();
while (true)
{
_loggingService.Log(SeverityLevel.Info, "Waiting for connection...");
var client = listener.AcceptTcpClient();
var remoteEndPoint = client.Client != null ? client.Client.RemoteEndPoint.ToString() : "Unknown";
_loggingService.Log(SeverityLevel.Info, String.Format("Connected to {0}", remoteEndPoint));
var netStream = client.GetStream();
var data = String.Empty;
using (var reader = new StreamReader(netStream, Encoding.ASCII))
{
data = reader.ReadToEnd();
}
_loggingService.Log(SeverityLevel.Info, "Received data: " + data);
ProcessData(data); //data is processed and stored in database (all resources are released when done)
client.Close();
_loggingService.Log(SeverityLevel.Info, String.Format("Connection closed for {0}", remoteEndPoint));
}
}
catch (Exception exception)
{
_loggingService.Log(SeverityLevel.Error, exception.Message);
}
finally
{
if (listener != null)
listener.Stop();
}
}
private void ProcessData(String data)
{
try
{
var processor = new Processor();
var lines = data.Split('\n');
foreach (var line in lines)
processor.ProcessLine(line);
processor.ProcessMessage();
}
catch (Exception ex)
{
_loggingService.Log(SeverityLevel.Error, ex.Message);
throw new Exception(ex.InnerException.Message);
}
}
}
One strange observation i just did:
I checked the log recently and no instrument has connected for the last 30 minutes (which indicates that the service is down).
I connected to the service myself via a TCP client i've written myself and uploaded some test data.
This worked fine.
When I checked the log again my test data had been stored.
The strange thing is, that 4 other instruments had connected about the same time and send their data successfully.
Why couldn't they connect by themself before I connected with my test client?
Also, what does this setting in .csdef do for an InputEndpoint, idleTimeoutInMinutes?
===============================================
Edit:
Since a cuple of days back my cloud service has been running successfully.
Unfortunately this morning last log entry was from this line:
_loggingService.Log(SeverityLevel.Info, String.Format("Connected to {0}", remoteEndPoint));
No other connections could be made after this. Not even from my own test TCP client (didn't get any error though, but no data was stored and no new logs).
This makes me think that following code causes the service to hang:
var netStream = client.GetStream();
var data = String.Empty;
using (var reader = new StreamReader(netStream, Encoding.ASCII))
{
data = reader.ReadToEnd();
}
I've read somewhere that StremReader's ReadToEnd() could hang. Is this possible?
I have now changed this piece of code to this:
int i;
var bytes = new Byte[256];
var data = new StringBuilder();
const int dataLimit = 10;
var dataCount = 0;
while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
{
data.Append(Encoding.ASCII.GetString(bytes, 0, i));
if (dataCount >= dataLimit)
{
_loggingService.Log(SeverityLevel.Error, "Reached data limit");
break;
}
dataCount++;
}
Another explanation could be something hanging in the database. I use the SqlConnection and SqlCommand classes to read and write to my database. I always close my connection afterwards (finally block).
SqlConnection and SqlCommand should have default timeouts, right?
===============================================
Edit:
After some more debugging I found out that when the service wasn't responding it "hanged" on this line of code:
while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
After some digging I found out that the NetStream class and its read methods could actually hang. Even though MS declares otherwise.
NetworkStream read hangs
I've now changed my code into this:
Thread thread = null;
var task = Task.Factory.StartNew(() =>
{
thread = Thread.CurrentThread;
while ((i = netStream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data.Append(Encoding.ASCII.GetString(bytes, 0, i));
}
streamReadSucceeded = true;
});
task.Wait(5000);
if (streamReadSucceeded)
{
//Process data
}
else
{
thread.Abort();
}
Hopefully this will stop the hanging.
I'd say that part of your problem is you are processing your data on the thread that listens for connections from clients. This would prevent new clients from connecting if another client has started a long running operation of some type. I'd suggest you defer your processing to worker threads thus freeing the "listener" thread to accept new connections.
Another problem you could be experiencing, if your service throws an error, then the service will stop accepting connections as well.
private static void ListenForClients()
{
tcpListener.Start();
while (true)
{
TcpClient client = tcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private static void HandleClientComm(object obj)
{
try
{
using(TcpClient tcpClient = (TcpClient)obj)
{
Console.WriteLine("Got Client...");
using (NetworkStream clientStream = tcpClient.GetStream())
using (StreamWriter writer = new StreamWriter(clientStream))
using(StreamReader reader = new StreamReader(clientStream))
{
//do stuff
}
}
}
catch(Exception ex)
{
}
}

When is a started service not a started service? (SQL Express)

We require programmatic access to a SQL Server Express service as part of our application. Depending on what the user is trying to do, we may have to attach a database, detach a database, back one up, etc. Sometimes the service might not be started before we attempt these operations. So we need to ensure the service is started. Here is where we are running into problems. Apparently the ServiceController.WaitForStatus(ServiceControllerStatus.Running) returns prematurely for SQL Server Express. What is really puzzling is that the master database seems to be immediately available, but not other databases. Here is a console application to demonstrate what I am talking about:
namespace ServiceTest
{
using System;
using System.Data.SqlClient;
using System.Diagnostics;
using System.ServiceProcess;
using System.Threading;
class Program
{
private static readonly ServiceController controller = new ServiceController("MSSQL$SQLEXPRESS");
private static readonly Stopwatch stopWatch = new Stopwatch();
static void Main(string[] args)
{
stopWatch.Start();
EnsureStop();
Start();
OpenAndClose("master");
EnsureStop();
Start();
OpenAndClose("AdventureWorksLT");
Console.ReadLine();
}
private static void EnsureStop()
{
Console.WriteLine("EnsureStop enter, {0:N0}", stopWatch.ElapsedMilliseconds);
if (controller.Status != ServiceControllerStatus.Stopped)
{
controller.Stop();
controller.WaitForStatus(ServiceControllerStatus.Stopped);
Thread.Sleep(5000); // really, really make sure it stopped ... this has a problem too.
}
Console.WriteLine("EnsureStop exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
private static void Start()
{
Console.WriteLine("Start enter, {0:N0}", stopWatch.ElapsedMilliseconds);
controller.Start();
controller.WaitForStatus(ServiceControllerStatus.Running);
// Thread.Sleep(5000);
Console.WriteLine("Start exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
private static void OpenAndClose(string database)
{
Console.WriteLine("OpenAndClose enter, {0:N0}", stopWatch.ElapsedMilliseconds);
var connection = new SqlConnection(string.Format(#"Data Source=.\SQLEXPRESS;initial catalog={0};integrated security=SSPI", database));
connection.Open();
connection.Close();
Console.WriteLine("OpenAndClose exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
}
}
On my machine, this will consistently fail as written. Notice that the connection to "master" has no problems; only the connection to the other database. (You can reverse the order of the connections to verify this.) If you uncomment the Thread.Sleep in the Start() method, it will work fine.
Obviously I want to avoid an arbitrary Thread.Sleep(). Besides the rank code smell, what arbitary value would I put there? The only thing we can think of is to put some dummy connections to our target database in a while loop, catching the SqlException thrown and trying again until it works. But I'm thinking there must be a more elegant solution out there to know when the service is really ready to be used. Any ideas?
EDIT: Based on feedback provided below, I added a check on the status of the database. However, it is still failing. It looks like even the state is not reliable. Here is the function I am calling before OpenAndClose(string):
private static void WaitForOnline(string database)
{
Console.WriteLine("WaitForOnline start, {0:N0}", stopWatch.ElapsedMilliseconds);
using (var connection = new SqlConnection(string.Format(#"Data Source=.\SQLEXPRESS;initial catal
using (var command = connection.CreateCommand())
{
connection.Open();
try
{
command.CommandText = "SELECT [state] FROM sys.databases WHERE [name] = #DatabaseName";
command.Parameters.AddWithValue("#DatabaseName", database);
byte databaseState = (byte)command.ExecuteScalar();
Console.WriteLine("databaseState = {0}", databaseState);
while (databaseState != OnlineState)
{
Thread.Sleep(500);
databaseState = (byte)command.ExecuteScalar();
Console.WriteLine("databaseState = {0}", databaseState);
}
}
finally
{
connection.Close();
}
}
Console.WriteLine("WaitForOnline exit, {0:N0}", stopWatch.ElapsedMilliseconds);
}
I found another discussion dealing with a similar problem. Apparently the solution is to check the sys.database_files of the database in question. But that, of course, is a chicken-and-egg problem. Any other ideas?
Service start != database start.
Service is started when the SQL Server process is running and responded to the SCM that is 'alive'. After that the server will start putting user databases online. As part of this process, it runs the recovery process on each database, to ensure transactional consistency. Recovery of a database can last anywhere from microseconds to whole days, it depends on the ammount of log to be redone and the speed of the disk(s).
After the SCM returns that the service is running, you should connect to 'master' and check your database status in sys.databases. Only when the status is ONLINE can you proceed to open it.