Socket on a Thread stops processing and locks the UI - c#

I have a standalone test application developed in c# (4.5).
The application is primarily meant for sending some data to COM ports. The application accepts the data through the UI and the corresponding data is sent to respective COM ports.
For eg: Data from text box 1 goes to COM 1 on pressing a button, Data from Textbox 2 goes to COM 2 on pressing a different button etc.
Later I had to add a functionailty where a different set of data has to be accepted via Windows sockets and has to be sent to a different COM port other than above. This listening socket could receive data from multiple sources. If the listening socket receives back to back socket data, the application is expected to queue the data and process the data on a First come first serve bases.
Hence I created a synchronous socket to receive data. If the server receives data from 2 sources, it processes the data from source 1 and sends the completion status to source 1 and then takes the data from source 2,processes it and informs the status and this goes on. The socket is created on a thread so that it could receive and process data independently from the UI.
The application was meeting its objective as most of the communication was through sockets and people were not really using the UI for entering data.
Recently, as people started UI, i noticed a completely new issue. When someone tries to enters a data on to UI while the socket data is in process, it stops the socket data processing. When I press ctrl+Alt+Del on the host, it resumes the processing of the socket data.
I could not identify my mistake here. Also, I looked over to the Backgroundworkder class but I am not sure if that would allow the sockets commands to be processed in a synchronous way.
Please treat me as a newbie as I am still learning and complex suggestions might be hard to digest.
public partial class frm_bot : Form
{
public frm_bot()
{
StartServer();
}
private void frm_bot_Load(object sender, EventArgs e)
{
try
{
myThread = new System.Threading.Thread(new System.Threading.ThreadStart(OnClientConnect));
myThread.IsBackground = true;
myThread.Start();
}
catch (Exception ex)
{
showErrorMsg(ex.Message);
}//catch
}
public void StartServer()
{
InitializeComponent();
System.Net.IPAddress localIPAddress = System.Net.IPAddress.Parse(GetlocalIp());
IPEndPoint ipLocal = new IPEndPoint(localIPAddress, 8089);
_listener = new TcpListener(ipLocal);
}
private void OnClientConnect()
{
try
{
_listener.Start();
TcpClient clientSocket = default(TcpClient);
clientSocket = _listener.AcceptTcpClient();
_clientSocket = clientSocket;
ReadCallback();
}
catch (Exception se)
{
MessageBox.Show("Could not bind to Port 8089! Please close all Applications that uses Port 8089");
}
}
public void ReadCallback()
{
try
{
using (StreamReader sr = new StreamReader(_clientSocket.GetStream()))
using (StreamWriter sw = new StreamWriter(_clientSocket.GetStream()))
{
sw.AutoFlush = true;
char[] c = null;
while (sr.Peek() >= 0)
{
c = new char[25];
sr.Read(c, 0, c.Length);
Console.WriteLine(c);
}
string d = new string(c);
string[] cmddata = d.Split('\0');
string dataFromClient = cmddata[0];
if (dataFromClient.Length == 0)
{
Console.WriteLine("Client sent empty string!");
}
else
{
ProcessSocketData(dataFromClient);
sw.Write("Done");
}
sw.Close();
}
OnClientConnect();
}
catch (Exception ex)
{
OnClientConnect();
return;
}
}
public void ProcessSocketData(string sockdata)
{
try
{
// Socket data is processed here.
}
catch (Exception ex)
{
MessageBox.Show("Exception on ProcessSocketData: " + ex.Message);
return;
}
}
}

Related

Lost frames on synchrous/asynchrous data receiveing

I have some problem with receiving frames in C#. After few hours from application start, some frames are lost.
Well, at start I'm running two threads which are receiving data. Code:
public void ATSListenerThreadA(MainWindow mainWindow)
{
UdpClient listenerA = new UdpClient(19001);
listenerA.Client.ReceiveBufferSize = 1000;
IPEndPoint remoteIPEndPointA = new IPEndPoint(IPAddress.Any, 1);
Byte[] receivedBytes;
try
{
while (mainWindow.ATSThreadActive)
{
receivedBytes = listenerA.Receive(ref remoteIPEndPointA);
if (receivedBytes.Length > 170)
{
Log.Write(MessageType.Info, "BUG KANAL A: " + BitConverter.ToString(receivedBytes));
}
mainWindow.ATSTimeoutTimer.Start();
ATSDataReceived(Channel.A, mainWindow, receivedBytes);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
public void ATSListenerThreadB(MainWindow mainWindow)
{
UdpClient listenerB = new UdpClient(19002);
listenerB.Client.ReceiveBufferSize = 1000;
IPEndPoint remoteIPEndPointB = new IPEndPoint(IPAddress.Any, 1);
Byte[] receivedBytes;
try
{
while (mainWindow.ATSThreadActive)
{
receivedBytes = listenerB.Receive(ref remoteIPEndPointB);
if (receivedBytes.Length > 170)
{
Log.Write(MessageType.Info, "BUG KANAL B: " + BitConverter.ToString(receivedBytes));
}
mainWindow.ATSTimeoutTimer.Start();
ATSDataReceived(Channel.B, mainWindow, receivedBytes);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ATSDataReceived(Channel channel, MainWindow mainWindow, Byte[] received)
{
try
{
mainWindow.Dispatcher.Invoke(() =>
{
mainWindow.ATSStatusLabel.Foreground = System.Windows.Media.Brushes.Green;
mainWindow.ATSStatusLabel.Content = "OK";
});
ATSInterface.UpdateObjects(channel, received);
}
catch (Exception ex)
{
mainWindow.Dispatcher.Invoke(() =>
{
mainWindow.ATSStatusLabel.Foreground = System.Windows.Media.Brushes.Red;
mainWindow.ATSStatusLabel.Content = "ERR";
});
Log.Write(MessageType.Warning, ex.Message);
}
lock (this)
{
if (mainWindow.ATSTimeoutTimer != null)
{
mainWindow.ATSTimeoutTimer.Stop();
mainWindow.ATSTimeoutTimer.Start();
}
}
}
Then, in ATSDataReceived method, received data are processed with calling method ATSInterface.UpdateObjects(). Of course inside ATSInterface.UpdateObjects() method is lock. I was trying to receiving data synchronously and asynchronously, but it doesn't change anything. Also I was checking if two frames are not sticking together, but it's not this too. As I said, problem araises after few hours from program start, in both threads simultaneously.
I might add that frames are coming very often, once at ~150 ms.
What can be a reason?
some frames are lost.
That's perfectly normal for UDP. By design, you may or may not ever receive a datagram that was sent to you.
Other unreliable behaviors of UDP include the possibility that a given datagram may be received more than once, and that one datagram may be received after a different datagram that was sent later than it (i.e. the datagrams are not guaranteed to be received in the same order in which they were sent).
If you want reliable communications, you will need to use TCP, or add reliability features on top of your UDP protocol.
udp is unreliable protocol to use.
if you want to make sure that everything arrives you need to use TcpClient instead.

Bind multiple listener to the same port

I am using UdpClient class in .net 3.5
I need to bind multiple applications to the same port .
So, if UDP servers broadcast any request - all the applications thats listen on the port can receive the message but the problem is, when I try bind to an application to the same port, only one application receive the message and the other does not.
Below is some sample code for the two application:
UdpClient udpClient = new UdpClient();
Thread thread;
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 11000);
public Form1()
{
//CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
udpClient.ExclusiveAddressUse = false;
udpClient.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(endPoint);
}
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
thread.Abort();
udpClient.Close();
Close();
}
}
private void ReceiveMessage()
{
//while (true)
//{
// IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 11000);
// byte[] content = udpClient.Receive(ref endPoint);
udpClient.BeginReceive(new AsyncCallback(Read_Callback), null);
//if (content.Length > 0)
//{
// string message = Encoding.ASCII.GetString(content);
// this.Invoke(myDelegate, new object[] { message });
//}
// }
}
public void Read_Callback(IAsyncResult ar)
{
try
{
byte[] buffer = udpClient.EndReceive(ar, ref endPoint);
// Process buffer
string s = Encoding.ASCII.GetString(buffer);
// richTextBox1.Text = s;
udpClient.BeginReceive(new AsyncCallback(Read_Callback), null);
}
catch (Exception ex)
{ }
}
PS : I am unable to figure out the reason or am I missing something. ?
That's the nature of sockets. Even in cases (such as UDP) where multiple applications can access the same port, the data is handed out first-come, first-serve. UDP is also designed with minimum overhead, so there isn't even an opportunity to "check the queue," like you (hypothetically) could with TCP.
It's designed around having multiple processes share a server load, alternating who receives the request based on who's idle.
You'd need to build something external to get around this, like a retransmission protocol or a database to make sure every inbound message is shared.
If you can deal with the changes, a smarter way to handle this would be UDP Multicast, where multiple programs essentially enroll to receive group messages. In that case, the single-port restriction can (and should) be abandoned.

Can you read and write with a single Named Pipe client?

I've written a little apllication that creates a named pipe server and a client that connects to it. You can send data to the server, and the server reads it successfully.
The next thing I need to do is receive messages from the server, so I've got another thread that spawns and sits and waits for incoming data.
The problem is that whilst the thread is sat waiting for incoming data, you can no longer send messages to the server as it hangs on the WriteLine call as I assume the pipe is now tied up checking for data.
So is it just that I'm not approaching this properly? Or are named pipes not meant to be used like this? The examples I've seen on named pipes seem to only go one way, a client sends and a server receives, although you can specify the direction of a pipe as In, Out or both.
Any help, pointers or suggestions would be appreciated!
Heres' the code so far:
// Variable declarations
NamedPipeClientStream pipeClient;
StreamWriter swClient;
Thread messageReadThread;
bool listeningStopRequested = false;
// Client connect
public void Connect(string pipeName, string serverName = ".")
{
if (pipeClient == null)
{
pipeClient = new NamedPipeClientStream(serverName, pipeName, PipeDirection.InOut);
pipeClient.Connect();
swClient = new StreamWriter(pipeClient);
swClient.AutoFlush = true;
}
StartServerThread();
}
// Client send message
public void SendMessage(string msg)
{
if (swClient != null && pipeClient != null && pipeClient.IsConnected)
{
swClient.WriteLine(msg);
BeginListening();
}
}
// Client wait for incoming data
public void StartServerThread()
{
listeningStopRequested = false;
messageReadThread = new Thread(new ThreadStart(BeginListening));
messageReadThread.IsBackground = true;
messageReadThread.Start();
}
public void BeginListening()
{
string currentAction = "waiting for incoming messages";
try
{
using (StreamReader sr = new StreamReader(pipeClient))
{
while (!listeningStopRequested && pipeClient.IsConnected)
{
string line;
while ((line = sr.ReadLine()) != null)
{
RaiseNewMessageEvent(line);
LogInfo("Message received: {0}", line);
}
}
}
LogInfo("Client disconnected");
RaiseDisconnectedEvent("Manual disconnection");
}
// Catch the IOException that is raised if the pipe is
// broken or disconnected.
catch (IOException e)
{
string error = "Connection terminated unexpectedly: " + e.Message;
LogError(currentAction, error);
RaiseDisconnectedEvent(error);
}
}
You cannot read from one thread and write on another thread to the same pipe object. So while you could create a protocol where the listening position changes depending on the data you're sending, you cannot do both at the same time. You will need a client and server pipe on both sides to do this.

Delay when send string via socket

I make an application in android can send character code to server C# when user input on android keyboard.
This is send method in android side:
public Boolean writeMessage(String message) {
try {
printWriter = new PrintWriter(socket.getOutputStream(), true);
printWriter.println(message);
return true;
} catch (Exception ex) {
Log.e(TAG,"write error: " +ex.getMessage());
return false;
}
}
And server listen the messages (C#):
Thread myThread = new Thread(new ThreadStart(ServeClient));
myThread.Start();
void ServeClient(){
StreamReader reader = new StreamReader(tcpClient.GetStream());
while (true)
{
try
{
String message = reader.ReadLine();
if (message != null)
{
Console.WriteLine(message);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
My code works, but when user input faster, the server delay read message in 1,2 or 3 seconds (I have test the method get character when user input, it works fine, not delay). Where is my problem? Thanks in advance!
Your problem may be caused by Nagle's algorithm reducing TCP traffic. Consider setting TCP_NODELAY on your client (and server - TcpClient.Client.NoDelay - if communication is two-way).
Edit: For java it is Socket.setTcpNoDelay method.

How to connect to modems with tcp clients, in multiple port or other way?

I have around 5000 modem (thin clients), and I want to communicate with them, one of a my method is like this : string GetModemData(modemID), now I have an open port in server that listens to modem and I'm using socket programming to send data to modems (calling related function), but when i want send data to multiple modem in a same time and get response from them, I don't know what should i do? I can send data to one modem and waiting for its response and then send another data to other modems (sequential), but the problem is client should be wait long time to get answer(may be some different client want to get some information from modems so they all will be wait into the Q or something like this), I think one way to solving this problem is to use multiple port and listen for each modem to related port, but it takes too many ports and also may be memory usage going up and exceed my available memory space, so some lost may be occurred (is this true?). what should to do ? I'd thinking about Parallelism, but i think its not related i should to wait for one port, because i don't know should to pass current received data to which client. I'm using asp.net.
currently I'm doing like this:
private void StartListener()
{
ModemTcpListener = new TcpListener(ModemPort);
//ClientTcpListener = new TcpListener(ClientPort);
ModemTcpListener.Start();
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
}
and in return
private void DoReadModemCallback(IAsyncResult ar)
{
try
{
bool bRet = ar.AsyncWaitHandle.WaitOne(420000);
Modem modem = ar.AsyncState as Modem;
if (!bRet || modem == null)
{
return;
}
}
catch{}
// now send data to which client?????? if i'm going to use async????
}
and :
private void DoAcceptModemCallback(IAsyncResult ar)
{
try
{
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
TcpClient tcpClient = ModemTcpListener.EndAcceptTcpClient(ar);
Modem modem= new Modem(tcpClient, "");
tcpClient.GetStream().BeginRead(modem.Buffer, 0, tcpClient.ReceiveBufferSize, new AsyncCallback(DoReadModemCallback), modem);
ModemTcpListener.BeginAcceptTcpClient(new AsyncCallback(DoAcceptModemCallback), ModemTcpListener);
Log.Write("a Modem connect ...");
}
catch (Exception ex)
{
}
}
Heres an example keeping track of all your clients. I've compacted it for readability. You should really split it up into multiple classes.
I'm using Pool (which I just created and commited) and SimpleServer. Both classes are part of a library that I'm currently building (but far from done).
Don't be afraid of having 5000 sockets open, they do not consume much resources when you are using asynchronous operations.
public class SuperServer
{
private List<ClientContext> _clients = new List<ClientContext>();
private SimpleServer _server;
private Pool<byte[]> _bufferPool;
public SuperServer()
{
// Create a buffer pool to be able to reuse buffers
// since your clients will most likely connect and disconnect
// often.
//
// The pool takes a anonymous function which should return a new buffer.
_bufferPool = new Pool<byte[]>(() => new byte[65535]);
}
public void Start(IPEndPoint listenAddress)
{
_server = new SimpleServer(listenAddress, OnAcceptedSocket);
// Allow five connections to be queued (to be accepted)
_server.Start(5);
}
// you should handle exceptions for the BeginSend
// and remove the client accordingly.
public void SendToAll(byte[] info)
{
lock (_clients)
{
foreach (var client in _clients)
client.Socket.BeginSend(info, 0, info.Length, SocketFlags.None, null, null);
}
}
// Server have accepted a new client.
private void OnAcceptedSocket(Socket socket)
{
var context = new ClientContext();
context.Inbuffer = _bufferPool.Dequeue();
context.Socket = socket;
lock (_clients)
_clients.Add(context);
// this method will eat very few resources and
// there should be no problem having 5000 waiting sockets.
context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
context);
}
//Woho! You have received data from one of the clients.
private void OnRead(IAsyncResult ar)
{
var context = (ClientContext) ar.AsyncState;
try
{
var bytesRead = context.Socket.EndReceive(ar);
if (bytesRead == 0)
{
HandleClientDisconnection(context);
return;
}
// process context.Inbuffer here.
}
catch (Exception err)
{
//log exception here.
HandleClientDisconnection(context);
return;
}
// use a new try/catch to make sure that we start
// read again event if processing of last bytes failed.
try
{
context.Socket.BeginReceive(context.Inbuffer, 0, context.Inbuffer.Length, SocketFlags.None, OnRead,
context);
}
catch (Exception err)
{
//log exception here.
HandleClientDisconnection(context);
}
}
// A client have disconnected.
private void HandleClientDisconnection(ClientContext context)
{
_bufferPool.Enqueue(context.Inbuffer);
try
{
context.Socket.Close();
lock (_clients)
_clients.Remove(context);
}
catch(Exception err)
{
//log exception
}
}
// One of your modems
// add your own state info.
private class ClientContext
{
public byte[] Inbuffer;
public Socket Socket;
}
}
Used classes:
Pool: http://fadd.codeplex.com/SourceControl/changeset/view/58858#1054902
SimpleServer: http://fadd.codeplex.com/SourceControl/changeset/view/58859#1054893
You need to use the asynchronous tcp/ip methods. This article shows how:
http://www.codeproject.com/KB/IP/asyncsockets.aspx
The critical piece is the BeginReceive() and related callback functions. Any more q's, please leave comments to this answer ;) BEST OF LUCK!
You need multi threading, whenever a client establishes a connection to the server start a new thread for it and start communication send/receive.
Here are some articles explaining multithreading in c#,
c-sharpcorner
codeproject
And here's a sample server application with multithreading,
http://www.dotnetspider.com/resources/2829-A-multi-readed-server-C-which-finds-prime-num.aspx

Categories

Resources