My UI lags while trying to connect to a socket? - c#

When I try to connect to my server socket, my interface lags, and the catch doesn't run.
Here's my code :
protected void OnButtonClicked(object sender, EventArgs args)
{
if (!clientSocket.Connected)
{
try
{
clientSocket.Connect("172.20.10.4", 100);
}
catch (SocketException)
{
gettext.Text = "Couldn't Connect";
}
}
SendLoop();
}
private void SendLoop()
{
gettext.Text = "get ivi type";
string req = gettext.Text;
byte[] buffer = Encoding.ASCII.GetBytes(req);
clientSocket.Send(buffer);
byte[] BuffRec = new byte[1024];
int rec = clientSocket.Receive(BuffRec);
byte[] data = new byte[rec];
Array.Copy(BuffRec, data, rec);
gettext.Text = Encoding.ASCII.GetString(data);
}
As a result I'd like to display the exception message when I'm not connected to the socket.

Simplistically, you need to do all this asyncronously. Your UI freezes (not lags - lagging implies it's going slowly but it is moving, it's just some time behind) because the thread that would ordinarily be busy drawing the UI and keeping it responding, is waiting on the connection to connect, then it's sending and receiving data
Where you've said Connect, Send and Receive, those need to be ConnectAsync, SendAsync and ReceiveAsync. You'll need to make other code changes to use async methods, such as marking your own methods as async and using the await keyword before method calls that could block.
By switching to using xAsync methods, when your UI is going to get blocked up waiting for a connection to complete, or for data to transfer, the code will pause what it's doing and go back to drawing the UI. When data is available etc, it will be called back to the point where it left off, and carry on processing
I also recommend you don't try to call SendLoop outside of your check whether the socket is connected..

Related

Is this a misuse of asynchronous methods?

I'm facing asynchronous methods for the first time and I cannot understand the advantages of the following code on a synchronous version:
private void SendCallback(IAsyncResult ar)
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
// Signal that all bytes have been sent.
SendCompleted.Set();
}
private AutoResetEvent SendCompleted = new AutoResetEvent(false);
public bool Send(byte[] byteData)
{
try
{
RfTcpClient.Client.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(this.SendCallback), RfTcpClient.Client);
}
catch (Exception)
{
return false;
}
return SendCompleted.WaitOne(1000, true);
}
I simplified it a bit so don't care about trivial error !
The Send method starts sending the message and then waits till the operation is completed without wasting cpu time. A new thread executes SendCallback which writes on the communication channel and it actively wait for the operation to complete, then signal the thread of the Send method.
I cannot see any advantages on synchronous method.
My assumption is that client.EndSend costs cpu time till it is completed, so the synchronous method is only moved to another thread. Am I missing something ?

c# tcp socket receive loop break logic

I'm writng a c# tcp socket server which will receive data from c++ socket application. Now everything works good except the loop break logic inside my c# receiving thread. I'm showing a code snippet below to explain better.
//creating socket object
private Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//accepting connections
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
this.socket = tcpListener.AcceptSocket();
tcpListener.Stop();
//code for
//public byte[] ReceiveMessage(ref int intError)
while (this.socket.Available > 0)
{
try
{
intBytesReceived = this.socket.Receive(byteReceivedBuffer, byteReceivedBuffer.Length, SocketFlags.None);
Thread.Sleep(100);
}
catch (SocketException ex)
{
string str = ex.Message;
intError = -1;
}
}
Below is the thread function to receive data continuously
//Thread to continuous poll data from client
//Now this has been done as I need to receive multiple messages from client after server ack received at client side.
//Thread quit logic based on manual stop button press
//I want to have one more logic by which thread will exit if the connection closed by client socket. i.e. a call of 'CloseSocket()' function from c++ application.
if (TCPServerListener.serverStatus == TCPServerListener.ServerStatus.Stopped)
{
tcpCommunication.Disconnect();
break;
}
while(true)
{
int sockError = 0;
byte[] byteData = tcpCommunication.ReceiveMessage(ref sockError);
if (byteData.Length > 0)
{
ParseBuffer(byteData, ref tcpCommunication);
}
}
For better picture I'm wrting below my communication protocol.
Client initiate a connection. Send a data set
Server receives, process, send ack
Client is in halt mode until it receive the ack from server, but didn't close the socket
This time, server will not receive any message but the receiving thread should active as I'm creating a single thread for each client.
Once the client receives the ack it will continue to send next data
Server receiving thread will get data now and process accordingly
Once client closes down its socket, server receiver thread should close also
I'm able to getting my work done but the server receiver thread is not getting closed. That's my problem. Any suggestions would be a off great help.
It has been my experience that when you use a TCP server/client socket relationship, the TCP server socket side will be in a thread that is controlled by a flag to continue listening until told to stop (Your comments mention a stop button).
The client side runs until all data is done, or the same flag controlling the server side is tripped.
When a client connects, I would store the AcceptSocket into a list. When I did this, I had a custom class that the takes the AcceptSocket and the custom class had counters for like how many messages, or bytes was sent/received to/from this client.
// This should be a threaded method if you're using a button to stop
private void StartTcpListener()
{
List<ClientClass> clientClassList = new List<ClientClass>();
TcpListener tcpListener = new TcpListener(ipAdd, iPort);
tcpListener.Start();
while (keepListening)
{
Socket socket = tcpListener.AcceptSocket();
// Create a client object and store it in a list
ClientClass clientClass = new ClientClass(socket);
clientClassList.Add(clientClass);
// This method would start a thread to read data from the accept socket while it was connected.
clientClass.Start();
}
foreach (ClientClass client in clientClassList)
{
// This method would stop the thread that reads data from the accept socket and close the accept socket
client.Stop();
}
tcpListener.Stop();
}
For the client side, when reading from the client accept socket this would be thread controlled and either the thread is aborted or the client closes its end causing the read to return a -1 for number of bytes read.
// Threaded method
private void Receive()
{
// Don't know how much of a buffer you need
byte[] dataIn = byte[1000];
while (acceptSocket.Connected)
{
// Exception handling so you either end the thread or keep processing data
try
{
int bytesRead = acceptSocket.Read(dataIn);
if (bytesRead != -1)
{
// Process your data
}
else
{
// -1 Bytes read should indicate the client shutdown on their end
break;
}
}
catch(SocketException se)
{
// You could exit this loop depending on the SocketException
}
catch(ThreadAbortException tae)
{
// Exit the loop
}
catch (Exception e)
{
// Handle exception, but keep reading for data
}
}
// You have to check in case the socket was disposed or was never successfully created
if (acceptSocket != null)
{
acceptSocket.Close();
}
}
// This is the stop method if you press your stop button
private void Stop()
{
// Aborts your read thread and the socket should be closed in the read thread. The read thread should have a ThreadState.Stopped if the while loop was gracefully ended and the socket has already been closed
if (readThread != null && readThread.ThreadState != ThreadState.Stopped)
{
readThread.Abort();
}
}
I think this is the basics of what I've done before. I'm sure there are "cleaner" ways of doing this now. This was years ago when I use to implement TCP client/server socket objects.
Hope this helps...

Why does BeginReceive() not return for more than one read?

In the code below, I make a call from Main() to Receive(), which in turn calls the Async BeginReceive(), and completes receiving the data in a background thread.
The Problem: For the first read, BeginReceive is succesful and appends the StringBuilder. However, when called again, the if(bytesread>0) condition is never reached and thus I never act on the data received.
I want BeginReceive to deal with more than one read, and (i think this is related with the threading) I would like for the Main() function to be always listening for new COMMANDS from the client (not new connections, I'd like to keep the same Socket). Is this even possible?
Attempts At Solution: I added the ManualResetEvent in an attempt to stop the Main() function from exiting prior to the Async reading going on in another thread.
Relevant Code in Main():
Receive(server); //await instructions from the client
done.WaitOne(); //This is a ManualResetEvent.
Console.ReadLine();
Method Definitions:
public static void Receive(Socket server)
{
try
{
SocketArgs sockargs = new SocketArgs();
sockargs.handler = server;
server.BeginReceive(sockargs.buffer, 0, sockargs.buffersize, 0, new AsyncCallback(ReceiveCallBack), sockargs);
}
catch
{
}
}
public static void ReceiveCallBack(IAsyncResult ia)
{
try
{
SocketArgs sockargs = (SocketArgs)ia.AsyncState;
Socket server = sockargs.handler;
int BytesRead = server.EndReceive(ia);
if (BytesRead > 0)
{
//Continue reading data.
sockargs.sb.Append(Encoding.ASCII.GetString(sockargs.buffer, 0, BytesRead));
MessageBox.Show(sockargs.sb.ToString());
server.BeginReceive(sockargs.buffer, 0, sockargs.buffersize, 0, new AsyncCallback(ReceiveCallBack), sockargs);
}
else
{ //Do stuff with sb.ToString()
done.Set();
}
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
}
Reset the event so that WaitOne blocks again. As per the comments the event is erroneously left in a set state causing Main to exit.
BytesRead only returns zero when the socket disconnects. Thus, the solution to my issue is to simply handle a disconnect in the else{} section.
More information can be bound in this very helpful article.
Edit: And to clarify, I left the BeginReceive() call there at the end of the if() construction, so there is "always" a BeginReceive() operation occuring.

Windows Service thread is not stopping in timely fashion in c#

I have a windows service which is getting started using Thread.After installation as windows service i am able to start the service properly but as soon as i try to stop the service it is taking too much time and and not getting stopped.I am using ManualResetEvent to stop the windows service Here is my code.
protected override void OnStart(string[] args)
{
_thread = new Thread(DoWork);
_thread.Start();
}
private void DoWork()
{
while (!_shutdownEvent.WaitOne(0))
{
data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
}
sock.Shutdown(SocketShutdown.Both);
sock.Close();
}
catch (Exception DFGFD)
{
}
}
protected override void OnStop()
{
_shutdownEvent.Set();
_thread.Join(); // wait for thread to stop
}
}
}
Please help me to resolve this.
You socket is blocking on the receive code. I would suggest issuing:
sock.Shutdown(SocketShutdown.Both);
sock.Close();
in a method called from the OnStop() handler (so it is called from another thread to the blocking Receive). This will cause the blocking sock.Receive to fail with an exception that you can handle by quitting the loop.
Maybe the code in the while is blocking ( ie waiting data from the conenction synchronously )
Typically you shoul use asynchronous I/O operation with the socket, that generally allow you to avoid starting a new thread.
The problem is in the call to Receive in the loop. From MSDN:
If no data is available for reading, the Receive method will block
until data is available, unless a time-out value was set by using
Socket.ReceiveTimeout. If the time-out value was exceeded, the Receive
call will throw a SocketException. If you are in non-blocking mode,
and there is no data available in the in the protocol stack buffer,
the Receive method will complete immediately and throw a
SocketException. You can use the Available property to determine if
data is available for reading. When Available is non-zero, retry the
receive operation.
Therefore, I'd suggest to change the code in the loop to this:
if (sock.Available > 0)
{
data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
}
Thread.Sleep(200);
This code checks whether data is available for reading and only calls Receive if there is data to read. In order to avoid busy waiting, it issues a call the Thread.Sleep.
If you want to avoid the call to Thread.Sleep, you can specify a ReceiveTimeout on the socket:
sock.ReceiveTimeout = 200;
The code in the while loop would then look like this:
try
{
data = new byte[1024];
int recv = sock.Receive(data);
stringData = Encoding.ASCII.GetString(data, 0, recv);
}
catch(SocketException ex)
{
if (ex.SocketErrorCode != SocketError.TimedOut)
throw;
// In case of Timeout, do nothing, continue loop
}
Problem: Receive() is waiting for additional input.
The Thread.Join() function is waiting for the thread to finish.
Possible Solution:
When I've been in similar situations, I've used a timeout on the Join function thread.Join(3000); This gives the thread an opportunity to do a clean shutdown, then continue.

Lock on dedicated lock-object causes deadlock

Yesterday I came accross a strange problem, which gave me quite some headaches. I have a server application with a Server class, which in turn is derived from a Connection class. The Connection class provides information about the connection state and the possibility to close the connection
public bool Connected
{
get
{
if (connection != null)
{
lock (lockObject)
{
bool blockingState = connection.Blocking;
try
{
connection.Blocking = false;
connection.Send(new byte[1], 1, 0);
}
catch (SocketException e)
{
if (!e.NativeErrorCode.Equals(10035))
{
return false;
}
//is connected, but would block
}
finally
{
connection.Blocking = blockingState;
}
return connection.Connected;
}
}
return false;
}
}
public virtual void CloseConnection()
{
if (Connected)
{
lock (lockObject)
{
connection.Close();
}
}
}
The Server class is resonsible for actually sending data
private void ConnectAndPollForData()
{
try
{
TcpListener listener = new TcpListener(Port);
listener.Start();
while (true)
{
connection = listener.AcceptSocket();
string currentBuffr = string.Empty;
const int READ_BUFFER_SIZE = 1024;
byte[] readBuffr = new byte[READ_BUFFER_SIZE];
while (Connected)
{
int bytesReceived;
lock (lockObject)
{
bytesReceived = connection.Receive(readBuffr, READ_BUFFER_SIZE, SocketFlags.None);
}
currentBuffr += ASCIIEncoding.ASCII.GetString(readBuffr, 0, bytesReceived);
//do stuff
}
}
catch(ThreadAbortException)
{
Thread.ResetAbort();
}
finally
{
}
}
public void SendString(string stringToSend)
{
stringToSend += "\r\n";
if(Connected)
{
lock(lockObject)
{
connection.Send(ASCIIEncoding.UTF7.GetBytes(stringToSend));
}
}
}
There is no other explicit access to the connection object. The ConnectAndPollForData function executes in a seperate thread. Whenever I ran the host in this version (I am currently using a non thread-safe version, which causes other problems) it hang after quite a few lines received via TCP. Pausing the debugger showed me, that one thread tried to execute the code withing the lock of Connected, while the other tried to receive data in the lock of ConnectAndPollForData. This behavior seems strange to me, for I would expect to execute the code within the first lock and then do the second. There do seem to be similar problems when using callbacks like in Deadlocking lock() method or 'Deadlock' with only one locked object? but the situation here is a bit different, for in my situation (I think) the code within the locks should not emit any events that themselves try to obtain a lock on the object.
Let's assume it gets the lock in the second method first. So it is holding the lock, and waiting for data. It is unclear whether this is directly receiving the data sent by the first method, or whether this is looking for a reply from an unrelated server - a reply to the message sent in the first method. But either way, I'm assuming that there won't be data incoming until the outbound message is sent.
Now consider: the outbound message can't be sent, because you are holding an exclusive lock.
So yes, you've deadlocked yourself. Basically, don't do that. There is no need to synchronize between inbound and outbound socket operations, even on the same socket. And since it makes very little sense to have concurrent readers on the same socket, or concurrent writers, I'm guessing you don't actually need those locks at all.

Categories