TCP - C# - Server Client Chat Compare - c#

I have managed to create a Server/Client chat system, where the client sends a message to the server and the the server sends the message to all the clients.
I want to extend this so that the Server compares the messages and then sends a message to the client.
For Example: If client 1 sends 10 and client 2 sends 20 the server will compare these and the server will send a message saying 20 is more than 10.
Is this possible to do? And if so how?
Server Code:
namespace Server
{
public partial class Form1 : Form
{
private const int m_iMaxConnections = 2;
struct Connection_Struct // Define a structure to hold details about a single connection
{
public Socket ClientSpecific_Socket;
public bool bInUse;
};
Socket m_ListenSocket;
Socket m_SendSocket;
Connection_Struct[] m_Connection_Array = new Connection_Struct[m_iMaxConnections]; // Define an array to hold a number of connections
System.Net.IPEndPoint m_LocalIPEndPoint;
static int m_iNumberOfConnectedClients;
private static System.Windows.Forms.Timer m_CommunicationActivity_Timer;
public Form1()
{
InitializeComponent();
Initialise_ConnectionArray();
m_CommunicationActivity_Timer = new System.Windows.Forms.Timer(); // Check for communication activity on Non-Blocking sockets every 200ms
m_CommunicationActivity_Timer.Tick += new EventHandler(OnTimedEvent_PeriodicCommunicationActivityCheck); // Set event handler method for timer
m_CommunicationActivity_Timer.Interval = 100; // Timer interval is 1/10 second
m_CommunicationActivity_Timer.Enabled = false;
string szLocalIPAddress = GetLocalIPAddress_AsString(); // Get local IP address as a default value
txtIPAddress.Text = szLocalIPAddress; // Place local IP address in IP address field
txtPort.Text = "8000"; // Default port number
m_iNumberOfConnectedClients = 0;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
try
{ // Create the Listen socket, for TCP use
m_ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ListenSocket.Blocking = false;
m_SendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Tcp);
}
catch (SocketException se)
{ // If an exception occurs, display an error message
MessageBox.Show(se.Message);
}
}
private void Initialise_ConnectionArray()
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
m_Connection_Array[iIndex].bInUse = false;
}
}
private void btnEnableServer_Click(object sender, EventArgs e)
{
// Bind to the selected port and start listening / receiving
try
{
// Get the Port number from the appropriate text box
String szPort = txtPort.Text;
int iPort = System.Convert.ToInt16(szPort, 10);
// Create an Endpoint that will cause the listening activity to apply to all the local node's interfaces
m_LocalIPEndPoint = new System.Net.IPEndPoint(IPAddress.Any, iPort);
// Bind to the local IP Address and selected port
m_ListenSocket.Bind(m_LocalIPEndPoint);
txtLog.Text = "Bind succeded";
// Prevent any further changes to the port number
txtPort.ReadOnly = true;
}
catch // Catch any errors
{ // If an exception occurs, display an error message
txtLog.Text = "Bind failed";
}
try
{
txtLog.Text = "Listening";
m_ListenSocket.Listen(2); // Listen for connections, with a backlog / queue maximum of 2
}
catch (SocketException se)
{
// If an exception occurs, display an error message
MessageBox.Show(se.Message);
}
catch // Silently handle any other exception
{
}
m_CommunicationActivity_Timer.Start(); // Start the timer to perform periodic checking for connection requests
txtLog.Text = "Accepting (waiting for connection attempt)";
btnEnableServer.Enabled = false;
}
private void OnTimedEvent_PeriodicCommunicationActivityCheck(Object myObject, EventArgs myEventArgs)
{ // Periodic check whether a connection request is pending or a message has been received on a connected socket
// First, check for pending connection requests
int iIndex;
iIndex = GetnextAvailable_ConnectionArray_Entry(); // Find an available array entry for next connection request
if (-1 != iIndex)
{ // Only continue with Accept if there is an array entry available to hold the details
try
{
m_Connection_Array[iIndex].ClientSpecific_Socket = m_ListenSocket.Accept(); // Accept a connection (if pending) and assign a new socket to it (AcceptSocket)
// Will 'catch' if NO connection was pending, so statements below only occur when a connection WAS pending
m_Connection_Array[iIndex].bInUse = true;
m_Connection_Array[iIndex].ClientSpecific_Socket.Blocking = false; // Make the new socket operate in non-blocking mode
m_iNumberOfConnectedClients++;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
txtLog.Text = "A new client connected";
SendUpdateMesageToAllConnectedclients();
}
catch (SocketException se) // Handle socket-related exception
{ // If an exception occurs, display an error message
if (10053 == se.ErrorCode || 10054 == se.ErrorCode) // Remote end closed the connection
{
CloseConnection(iIndex);
}
else if (10035 != se.ErrorCode)
{ // Ignore error messages relating to normal behaviour of non-blocking sockets
MessageBox.Show(se.Message);
}
}
catch // Silently handle any other exception
{
}
}
// Second, check for received messages on each connected socket
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
try
{
EndPoint localEndPoint = (EndPoint)m_LocalIPEndPoint;
byte[] ReceiveBuffer = new byte[1024];
int iReceiveByteCount;
iReceiveByteCount = m_Connection_Array[iIndex].ClientSpecific_Socket.ReceiveFrom(ReceiveBuffer, ref localEndPoint);
string szReceivedMessage;
if (0 < iReceiveByteCount)
{ // Copy the number of bytes received, from the message buffer to the text control
szReceivedMessage = Encoding.ASCII.GetString(ReceiveBuffer, 0, iReceiveByteCount);
if ("QuitConnection" == szReceivedMessage)
{
CloseConnection(iIndex);
}
else
{
txtLog.AppendText(szReceivedMessage + Environment.NewLine);
// Send message to each connected client.
// int iIndex2;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
string szMessage;
szMessage = szReceivedMessage;
txtLog.Text = m_Connection_Array[m_iMaxConnections].ToString();
byte[] SendMessage = System.Text.Encoding.ASCII.GetBytes(szMessage);
m_Connection_Array[iIndex].ClientSpecific_Socket.Send(SendMessage, SocketFlags.None);
}
}
}
}
}
catch (SocketException se) // Handle socket-related exception
{ // If an exception occurs, display an error message
if (10053 == se.ErrorCode || 10054 == se.ErrorCode) // Remote end closed the connection
{
CloseConnection(iIndex);
}
else if (10035 != se.ErrorCode)
{ // Ignore error messages relating to normal behaviour of non-blocking sockets
MessageBox.Show(se.Message);
}
}
catch // Silently handle any other exception
{
}
}
}
}
private void SendUpdateMesageToAllConnectedclients()
{ // Send message to each connected client informing of the total number of connected clients
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (true == m_Connection_Array[iIndex].bInUse)
{
string szMessage;
if (1 == m_iNumberOfConnectedClients)
{
szMessage = string.Format("There is now {0} client connected", m_iNumberOfConnectedClients);
}
else
{
szMessage = string.Format("There are now {0} clients connected", m_iNumberOfConnectedClients);
}
byte[] SendMessage = System.Text.Encoding.ASCII.GetBytes(szMessage);
m_Connection_Array[iIndex].ClientSpecific_Socket.Send(SendMessage, SocketFlags.None);
}
}
}
private void CloseConnection(int iIndex)
{
try
{
m_Connection_Array[iIndex].bInUse = false;
m_Connection_Array[iIndex].ClientSpecific_Socket.Shutdown(SocketShutdown.Both);
m_Connection_Array[iIndex].ClientSpecific_Socket.Close();
m_iNumberOfConnectedClients--;
txtClientNo.Text = System.Convert.ToString(m_iNumberOfConnectedClients);
txtLog.Text = "A Connection was closed";
SendUpdateMesageToAllConnectedclients();
}
catch // Silently handle any exceptions
{
}
}
private void Close_And_Quit()
{ // Close the sockets and exit the application
try
{
m_ListenSocket.Close();
}
catch
{
}
try
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
m_Connection_Array[iIndex].ClientSpecific_Socket.Shutdown(SocketShutdown.Both);
m_Connection_Array[iIndex].ClientSpecific_Socket.Close();
}
}
catch
{
}
try
{
Close();
}
catch
{
}
}
public string GetLocalIPAddress_AsString()
{
string szHost = Dns.GetHostName();
string szLocalIPaddress = "127.0.0.1"; // Default is local loopback address
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress IP in IPHost.AddressList)
{
if (IP.AddressFamily == AddressFamily.InterNetwork) // Match only the IPv4 address
{
szLocalIPaddress = IP.ToString();
break;
}
}
return szLocalIPaddress;
}
private int GetnextAvailable_ConnectionArray_Entry()
{
int iIndex;
for (iIndex = 0; iIndex < m_iMaxConnections; iIndex++)
{
if (false == m_Connection_Array[iIndex].bInUse)
{
return iIndex; // Return the index value of the first not-in-use entry found
}
}
return -1; // Signal that there were no available entries
}
}
}
Client Code:
namespace Client
{
public partial class Form1 : Form
{
Socket m_ClientSocket;
System.Net.IPEndPoint m_remoteEndPoint;
IPEndPoint m_localIPEndPoint;
Socket m_ReceiveSocket;
private static System.Windows.Forms.Timer m_CommunicationActivity_Timer;
public Form1()
{
InitializeComponent();
m_CommunicationActivity_Timer = new System.Windows.Forms.Timer(); // Check for communication activity on Non-Blocking sockets every 200ms
m_CommunicationActivity_Timer.Tick += new EventHandler(OnTimedEvent_PeriodicCommunicationActivityCheck); // Set event handler method for timer
m_CommunicationActivity_Timer.Interval = 100; // Timer interval is 1/10 second
m_CommunicationActivity_Timer.Enabled = false;
string szLocalIPAddress = GetLocalIPAddress_AsString(); // Get local IP address as a default value
txtIPAddress.Text = szLocalIPAddress; // Place local IP address in IP address field
txtPort.Text = "8000"; // Default port number
}
private void btnConnect_Click(object sender, EventArgs e)
{
// Connect the Socket with a remote endpoint
try
{
// Create the socket, for TCP use
m_ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_ClientSocket.Blocking = true; // Socket operates in Blocking mode initially
}
catch // Handle any exceptions
{
Close_Socket_and_Exit();
}
try
{
// Get the IP address from the appropriate text box
String szIPAddress = txtIPAddress.Text;
System.Net.IPAddress DestinationIPAddress = System.Net.IPAddress.Parse(szIPAddress);
// Get the Port number from the appropriate text box
String szPort = txtPort.Text;
int iPort = System.Convert.ToInt16(szPort, 10);
// Combine Address and Port to create an Endpoint
m_remoteEndPoint = new System.Net.IPEndPoint(DestinationIPAddress, iPort);
m_ClientSocket.Connect(m_remoteEndPoint);
m_ClientSocket.Blocking = false; // Socket is now switched to Non-Blocking mode for send/ receive activities
txtLog.Text = "Connected";
m_CommunicationActivity_Timer.Start(); // Start the timer to perform periodic checking for received messages
}
catch // Catch all exceptions
{ // If an exception occurs, display an error message
txtLog.Text = "(Connect attempt failed)\nRetry Connect";
}
}
private void OnTimedEvent_PeriodicCommunicationActivityCheck(Object myObject, EventArgs myEventArgs)
{ // Periodic check whether a message has been received
try
{
EndPoint RemoteEndPoint = (EndPoint)m_remoteEndPoint;
byte[] ReceiveBuffer = new byte[1024];
int iReceiveByteCount;
iReceiveByteCount = m_ClientSocket.ReceiveFrom(ReceiveBuffer, ref RemoteEndPoint);
string szReceivedMessage;
if (0 < iReceiveByteCount)
{ // Copy the number of bytes received, from the message buffer to the text control
szReceivedMessage = Encoding.ASCII.GetString(ReceiveBuffer, 0, iReceiveByteCount);
txtResult.Text = szReceivedMessage;
}
}
catch // Silently handle any exceptions
{
}
}
private void Close_Socket_and_Exit()
{
try
{
m_ClientSocket.Shutdown(SocketShutdown.Both);
}
catch // Silently handle any exceptions
{
}
try
{
m_ClientSocket.Close();
}
catch // Silently handle any exceptions
{
}
this.Close();
}
private void btnDisconnect_Click(object sender, EventArgs e)
{
try
{
String szData = "QuitConnection"; // Special code to signal 'close connection' to the server
// This ensures that the server is aware the Client wants to close the connection
// (TCP should otherwise automatically detect disconnection, but this approach ensures a clean disconnect)
byte[] byData = System.Text.Encoding.ASCII.GetBytes(szData);
m_ClientSocket.Send(byData, SocketFlags.None);
m_ClientSocket.Shutdown(SocketShutdown.Both);
m_ClientSocket.Close();
btnConnect.Text = "Connect";
txtResult.Text = "";
}
catch // Silently handle any exceptions
{
}
}
private string GetLocalIPAddress_AsString()
{
string szHost = Dns.GetHostName();
string szLocalIPaddress = "127.0.0.1"; // Default is local loopback address
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress IP in IPHost.AddressList)
{
if (IP.AddressFamily == AddressFamily.InterNetwork) // Match only the IPv4 address
{
szLocalIPaddress = IP.ToString();
break;
}
} return szLocalIPaddress;
}
}
}

Related

Ping Class issue to get all Local IP's

I am trying to get the IP's of devices attached to my network(WLAN to which i am connected) .Firstly i used Command Line in Win8 and pinging there serially while knowing my own IP (incrementing it each time and pinging ) .To get programmatically do it like WnetWatcher I am utilizing Ping Class by calling a function passing attempts=4 and timeout=3 but a blue screen saying PROCESS_HAS_BLOCKED_PAGESand found it an underlying API issue. Anyone has a better idea than this to get all the devices IP's because several threads at SO finds it using Dns Class but that works for a single PC(mine) .
1). What is the laternate of Ping and if it's Ping then how to get around API issue.
2).Also, how can i get the Router IP ,so that I maybe able to run the loop for other IP's on an network or is there any better alternative to it?
public static void Ping(string host, int attempts, int timeout)
{
new Thread(delegate()
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
}
catch
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}).Start();
}
private static void PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
// Logic for Ping Reply Success
// Console.WriteLine(String.Format("Host: {0} ping successful", ip));
lstlocal.listViewItem //Error ...the intellisense is not accepting it here
}
else
{
// Logic for Ping Reply other than Success
}
}
//function caller code from a button
lstLocal.Items.Clear();
lstLocal.FullRowSelect = true;
bool value;
for (int i = 0; i <= 254; i++)
{
string ping_var = "192.168.1" + "." + i;
value = Ping(ping_var, 4, 3);
// MessageBox.Show("Ping response for"+ping_var +"is" + value);
if(value==true)
{
ListViewItem items=new ListViewItem(ping_var.ToString());
lstLocal.Items.Add(items);
}
}
}
1) You may call SendAsync method of the Ping class instead of Send to avoid blocking:
public void Ping(string host, int attempts, int timeout)
{
for (int i = 0; i < attempts; i++)
{
new Thread(delegate()
{
try
{
System.Net.NetworkInformation.Ping ping = new System.Net.NetworkInformation.Ping();
ping.PingCompleted += new PingCompletedEventHandler(PingCompleted);
ping.SendAsync(host, timeout, host);
}
catch
{
// Do nothing and let it try again until the attempts are exausted.
// Exceptions are thrown for normal ping failurs like address lookup
// failed. For this reason we are supressing errors.
}
}).Start();
}
}
And take care of the ping response in the PingCompleted EventHandler delegate:
private void PingCompleted(object sender, PingCompletedEventArgs e)
{
string ip = (string)e.UserState;
if (e.Reply != null && e.Reply.Status == IPStatus.Success)
{
// Logic for Ping Reply Success
ListViewItem item = new ListViewItem(ip);
if (this.InvokeRequired)
{
this.Invoke(new Action(() =>
{
lstLocal.Items.Add(item);
}));
}
else
{
lstLocal.Items.Add(item);
}
// Logic for Ping Reply Success
// Console.WriteLine(String.Format("Host: {0} ping successful", ip));
}
else
{
// Logic for Ping Reply other than Success
}
}
2) To get your Router IP or gateway:
static string NetworkGateway()
{
string ip = null;
foreach (NetworkInterface f in NetworkInterface.GetAllNetworkInterfaces())
{
if (f.OperationalStatus == OperationalStatus.Up)
{
foreach (GatewayIPAddressInformation d in f.GetIPProperties().GatewayAddresses)
{
ip = d.Address.ToString();
}
}
}
Console.WriteLine(string.Format("Network Gateway: {0}", ip));
return ip;
}

TCP Socket BeginReceive stops after receiving few messages

This is my scenario:
Client :
Send xml data in pieces continuously 24/7 - (It is working fine and it is not in my control).
Server - My Code:
1. Listen continuously.
2. Receive the incoming message, buffer it and create valid xml from buffer.
3. Send it to the MSMQ ( Host will do this )
I wrote a tcp server code (adding pieces of code from google), which will be hosted in windows service. Everything works fine when I run the service in local but when I place it PROD, it listens upto 73K messages and it stops receiving. It is not throwing any exception. It just blocks at BeginReceive function. I have tried using ReceiveTimeOut also. I have seen netstat also and the connections is still in established stat.
When I restart the service, it again works fine. Here I am posting my server code. Please help on this.
StringBuilder content = new StringBuilder();
public event MessageReceiveEventHandler MessageReceived;
// An ArrayList is used to keep track of worker sockets that are designed
// to communicate with each connected client. Make it a synchronized ArrayList
// For thread safety
private System.Collections.ArrayList workerSocketList =
ArrayList.Synchronized(new System.Collections.ArrayList());
private int m_clientCount = 0;
private Socket m_mainSocket = null;
private AsyncCallback ReadCallback;
private AsyncCallback ConnectionCallback;
public MedDeviceListener(string ipAddress, int port, int maxConnections=100)
{
ProfileProvider.Instance.LogInformationIf(_debug);
this._port = port;
this._ipAddress = ipAddress;
this._maxConnections = maxConnections;
ReadCallback = new AsyncCallback(Receive_handler);
ConnectionCallback = new AsyncCallback(Connection_handler);
lenghtofStartMsg = header.Length;
lengthOfEndMsg = footer.Length;
}
public void Start()
{
ProfileProvider.Instance.LogInformationIf(_debug);
// Data buffer for incoming data.
byte[] bytes = new Byte[_bufferSize];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(_ipAddress), _port);
// Create a TCP/IP socket.
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
m_mainSocket.Bind(localEndPoint);
m_mainSocket.Listen(100);
InstrumentationProvider.Instance.LogInformation("MedDeviceListener successfully connected to IP:" + _ipAddress+"\nPort :"+_port);
m_mainSocket.BeginAccept(ConnectionCallback, m_mainSocket);
}
catch (Exception e)
{
InstrumentationProvider.Instance.LogException("MedDeviceListener.Start", e);
throw e;
}
}
private void Connection_handler(IAsyncResult ar)
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
Socket listener = (Socket)ar.AsyncState;
Socket workerSocket = listener.EndAccept(ar);
// Now increment the client count for this client
// in a thread safe manner
Interlocked.Increment(ref m_clientCount);
// Add the workerSocket reference to our ArrayList
workerSocketList.Add(workerSocket);
SendConnectedAck(_clientConnectAckMessage, m_clientCount);
WaitForData(workerSocket, m_clientCount);
//Resume the listening callback loop
listener.BeginAccept(Connection_handler, listener);
}
catch (ObjectDisposedException)
{
InstrumentationProvider.Instance.LogInformation("The listener socket has been closed");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("Connection_handler", ex);
throw;
}
}
private void Receive_handler(IAsyncResult ar)
{
ProfileProvider.Instance.LogInformationIf(_debug);
StateObject state = (StateObject)ar.AsyncState;
try
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
Socket workSocket = state.workSocket;
// Read data from the client socket.
int bytesRead = workSocket.EndReceive(ar);
if (bytesRead > 0)
{
//InstrumentationProvider.Instance.LogInformationIf(_debug, bytesRead+" read..");
// There might be more data, so parse the data received so far.
string data= Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
try
{
ParseIncomingMessage(data, workSocket);
}
catch(Exception parseEx)
{
content.Clear();
InstrumentationProvider.Instance.LogException("ParseIncomingMessage", parseEx);
}
}
WaitForData(state.workSocket, state.clientNumber);
}
catch (ObjectDisposedException)
{
InstrumentationProvider.Instance.LogInformation("Receive_handler: The listener socket has been closed");
}
catch (SocketException se)
{
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
}
private void WaitForData(Socket workerSocket, int clientNumber)
{
ProfileProvider.Instance.LogInformationIf(_debug);
try
{
StateObject theSocPkt = new StateObject(workerSocket, clientNumber);
workerSocket.ReceiveTimeout = 2000;
workerSocket.BeginReceive(theSocPkt.buffer, 0,
theSocPkt.buffer.Length,
SocketFlags.None,
Receive_handler,
theSocPkt);
}
catch(TimeoutException ex)
{
InstrumentationProvider.Instance.LogException("WaitForData - TimeOutException", ex);
}
catch (SocketException se)
{
InstrumentationProvider.Instance.LogException("MedDeviceListener.WaitForData", se);
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("WaitForData",ex);
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
}
private void ParseIncomingMessage(string msg,Socket wrkSocket)
{
Socket workSocket = wrkSocket;
bool hasStartTag = isMsgContainsStartTag(msg);
bool hasEndTag = isMsgContainsEndTag(msg);
int startTagIndex = indexOfStartTag(msg);
int endTagIndex = indexOfEndTag(msg);
// If the incomming message dont have either start or end tag
if (hasStartTag == false && hasEndTag == false)
{
content.Append(msg);
}
//check for the starttag first
//if message contains startTag
else if (hasStartTag)
{
if (startTagIndex != 0)//there is something before starttag
{
string subStr = msg.Substring(0, startTagIndex);
content.Append(subStr);
//Check and send the content
CheckSendMessage(workSocket);
//Parse the remaining message from start tag to end of the message
ParseIncomingMessage(msg.Substring(startTagIndex, msg.Length - subStr.Length), wrkSocket);
}
else if (startTagIndex == 0)
{
content.Clear();
if (hasEndTag)
{
int endOfEndTag = endTagIndex + lengthOfEndMsg;
string subStr = msg.Substring(0, endOfEndTag); //message statrs with start tag and ends contains full end tag so first get that string and send that.
content.Append(subStr);
CheckSendMessage(workSocket);
//Parse the remaining message from endtag+1 to end
ParseIncomingMessage(msg.Substring(endOfEndTag, msg.Length - endOfEndTag), wrkSocket);
}
else
{
content.Append(msg);
}
}
}
//if message contains EndTag ALONE
else if (hasEndTag)
{
int endOfEndTag = endTagIndex + lengthOfEndMsg;
string subStr = msg.Substring(0, endOfEndTag);
content.Append(subStr);
CheckSendMessage(workSocket);
//Parse remaining message after end tag
ParseIncomingMessage(msg.Substring(endOfEndTag, msg.Length - endOfEndTag), wrkSocket);
}
}
private void CheckSendMessage(Socket workSocket)
{
string msg=content.ToString().Trim();
//if content contains both start and end tag then send the content
if (isMsgContainsStartTag(msg) && isMsgContainsEndTag(msg) &&
indexOfStartTag(msg) == 0 && indexOfEndTag(msg) + lengthOfEndMsg == msg.Length)
{
//Send the message
using (MedDeviceListenerEventArgs e = new MedDeviceListenerEventArgs(msg))
{
OnReceiveComplete(e);
SendReceiveAck(workSocket, _receiveAckMessage);
}
}
}
private void SendReceiveAck(Socket handler, String data)
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.Send(byteData);
InstrumentationProvider.Instance.LogInformationIf(_debug, "Message received acknowledgement:" + _receiveAckMessage + " has been sent successfully");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("SendReceiveAck", ex);
}
}
private void SendConnectedAck(string msg, int clientNumber)
{
ProfileProvider.Instance.LogInformationIf(_debug);
try
{
// Convert the reply to byte array
byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);
Socket workerSocket = (Socket)workerSocketList[clientNumber - 1];
workerSocket.Send(byData);
InstrumentationProvider.Instance.LogInformationIf(_debug, "Client Connected acknowledgement:" + _clientConnectAckMessage + " has been sent successfully");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("SendConnectedAck", ex);
throw;
}
}
public void CloseSockets()
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
if (m_mainSocket != null)
{
if (m_mainSocket.Connected)
{
m_mainSocket.Shutdown(SocketShutdown.Both);
m_mainSocket.Close();
m_mainSocket = null;
}
}
Socket workerSocket = null;
for (int i = 0; i < workerSocketList.Count; i++)
{
workerSocket = (Socket)workerSocketList[i];
if (workerSocket != null)
{
workerSocket.Shutdown(SocketShutdown.Both);
workerSocket.Close();
workerSocket = null;
}
}
}
catch(Exception ex)
{
InstrumentationProvider.Instance.LogException("CloseSockets",ex);
}
}
protected virtual void OnReceiveComplete(MedDeviceListenerEventArgs e)
{
if (MessageReceived != null)
{
MessageReceived(this, e);
}
}
private int indexOfStartTag(string msg)
{
return msg.IndexOf(header);
}
private int indexOfEndTag(string msg)
{
return msg.IndexOf(footer);
}
private bool isMsgContainsStartTag(string msg)
{
return msg.Contains(header);
}
private bool isMsgContainsEndTag(string msg)
{
return msg.Contains(footer);
}
public delegate void MessageReceiveEventHandler(object sender,MedDeviceListenerEventArgs e);
public class MedDeviceListenerEventArgs : EventArgs,IDisposable
{
private string _receivedData;
public MedDeviceListenerEventArgs(string receivedData)
{
_receivedData = receivedData;
}
public string ReceivedData
{
get
{
return _receivedData;
}
}
public void Dispose()
{ }
}
}
I have read similar posts, tried everything but with no luck. Please help :)
Thanks
-MM

How many times should C# .BeginReceive() be called to receive 3 chunks sent be 3 calls to Linux C write() across TCP?

Do 3 chunks sent by 3 calls to Linux 'C' write(), through TCP, get received as the same, 3 chunks by Windows C# .BeginReceive(), or a single, contiguous chunk, or however many have been received when .BeginReceived is called?
A 'C' app on Linux sends a message by 3 calls to write(), through TCP connection, to a Windows C# app, which receives using BeginReceive().
Does BeginReceive() need to be called three times, to receive each of the three chunks sent by write()? Or is the size received by BeginReceive() equal to the size of what Windows has received when BeginReceive() is called? Which could be all bytes sent by the 3 writes(), or a partial amount, so .BeginReceive() should be called UNTIL all are received?
The Linux C app is running on an embedded TI ARM, and inside the same box the Windows C# app is running a Single Board Computer. The ARM has a direct Ethernet connection to the SBC.
The communication between the ARM and SBC sometimes fails to start at boot time, and I'm reverse engineering the source code to check for bad design.
ARM side is TCP listener, and Windows client initiates the TCP connection.
Using MontaVista(R) Linux(R) Professional Edition 5.0.0 (0702774)
and Windows-7 Visual-Studio 2010 Visual-C#.
Here is the ARM sending software, and the Windows receiving software........................
LINX 'C'
char msgBuffer[64];
sprintf(msgBuffer, START_MSG_ENVELOPE, msgId++, ack);
write(connection->fd, msgBuffer, strlen(msgBuffer));
write(connection->fd, msg, strlen(msg));
write(connection->fd, END_MSG_ENVELOPE, strlen(END_MSG_ENVELOPE));
HERE IS THE WINDOWS C# SIDE OF IT.............................................
private static void makeConnection(Socket clientSocket, int iPortNo)
{
TimeoutObject.Reset();
socketexception = null;
IPAddress ip;
//create the end point
IPEndPoint ipEndPoint;
ip = IPAddress.Parse(ipAddress);
try
{
ipEndPoint = new IPEndPoint(ip, iPortNo);
//connect to the remote host...
clientSocket.BeginConnect(ip, iPortNo, new AsyncCallback(CallBackMethod), clientSocket);
if (TimeoutObject.WaitOne(5 * 1000, false)) //5 secs connection timeout
{
if (!IsConnectionSuccessful)
{
string msg = VNResourceManager.Instance.GetString(VNMessages.DAM_NOT_FOUND);
if (socketexception != null)
msg += ": " + socketexception.Message;
throw new Exception(msg);
}
}
else
{
clientSocket.Close();
throw new TimeoutException(VNResourceManager.Instance.GetString(VNMessages.CONNECTION_TO_DAM_TIMED_OUT));
}
//watch for data ( asynchronously )...
WaitForData();
}
catch (SocketException e)
{
socketexception = e;
throw;
}
}
private static void CallBackMethod(IAsyncResult asyncresult)
{
try
{
IsConnectionSuccessful = false;
Socket socket = asyncresult.AsyncState as Socket;
if (socket.Connected)
{
socket.EndConnect(asyncresult);
IsConnectionSuccessful = true;
}
}
catch (Exception ex)
{
IsConnectionSuccessful = false;
socketexception = ex;
}
finally
{
TimeoutObject.Set();
}
}
public static void WaitForData()
{
try
{
if (asyncCallBack == null)
{
asyncCallBack = new AsyncCallback(OnDataReceived);
}
CSocketPacket theSocPkt = new CSocketPacket();
theSocPkt.thisSocket = clientSocket;
asyncResult = clientSocket.BeginReceive(theSocPkt.dataBuffer, 0, theSocPkt.dataBuffer.Length, SocketFlags.None, asyncCallBack, theSocPkt);
}
catch (SocketException se)
{
notifyErrorEventSubscribers(se);
}
}
public static void send(string message)
{
try
{
byte[] byData = System.Text.Encoding.ASCII.GetBytes(message);
clientSocket.Send(byData);
}
catch (SocketException se)
{
notifyErrorEventSubscribers(se);
throw;
}
}
//[MethodImpl(MethodImplOptions.Synchronized)]
public static void OnDataReceived(IAsyncResult result)
{
try
{
CSocketPacket theSockId = (CSocketPacket)result.AsyncState;
//end receive...
int messageSize = 0;
messageSize = theSockId.thisSocket.EndReceive(result);
Console.WriteLine(">>>>>>>>> messageSize = " + messageSize); // !!!
char[] chars = new char[messageSize + 1];
System.Text.Decoder d = System.Text.Encoding.ASCII.GetDecoder();
int charLen = d.GetChars(theSockId.dataBuffer, 0, messageSize, chars, 0);
string replyMessage = new System.String(chars);
lock (syncLock) //LastIndexOf function accesses the current culture info and we clear it in WM_TIMECHANGE handler (protecting from that race condition here)
{
if (replyMessage.LastIndexOf("\0") > 0)
replyMessage = replyMessage.Remove(replyMessage.LastIndexOf("\0"), 1);
if (replyMessage.LastIndexOf(Terminator) > 0)
replyMessage = replyMessage.Remove(replyMessage.LastIndexOf(Terminator), 1);
}
// Continue the waiting for data on the Socket
WaitForData();
receivedMsg += replyMessage;
// only serialize when we feel we have a message or we have reached the message line limit
if (((receivedMsg.Contains("message") && receivedMsg.Contains("/>")) || receivedMsg.Contains("</message>")) /* || (mRecvdMsgLineCount == Message.kMaxLines) */ )
{
List<XmlMessage> msgList = new List<XmlMessage>();
int index = -1;
do
{
index = receivedMsg.IndexOf("</message>");
if (index != -1)
{
XmlMessage message;
string strMessage = receivedMsg.Substring(0, index + "</message>".Length);
//MessageBox.Show(strMessage);
strMessage = strMessage.TrimStart(new char[] { '\r', '\n' });
receivedMsg = receivedMsg.Remove(0, index + "</message>".Length);
try
{
message = (XmlMessage)XmlMessage.GetXmlSerializer().Deserialize(XmlReader.Create(new StringReader(strMessage)));
}
catch (InvalidOperationException error)
{
string strErrorMessage = error.Message;
if (error.InnerException != null)
strErrorMessage += "\r\n" + error.InnerException.Message;
notifyErrorEventSubscribers(new Exception(strErrorMessage + "\r\n-----------------------------------------------------------------\r\n" + strMessage));
return;
}
msgList.Add(message);
}
} while (index != -1);
StringWriter sw = new StringWriter();
string serializedXml = string.Empty;
string strXmlMessage = string.Empty;
foreach (XmlMessage message in msgList)
{
if (message.ack_required && (message.update == null))
{
XmlMessage messageAcknowledge = new XmlMessage();
messageAcknowledge.ack_required = false;
messageAcknowledge.ack = new ack();
messageAcknowledge.ack.success = true;
messageAcknowledge.ack.id = message.id;
try
{
sendMessage(messageAcknowledge);
}
catch(Exception ex)
{
Logger.Log(EnumLoggingLevel.Error, "SocketCommunicationXMl.OnDataReceived", ex.Message);
}
}
if (dataReceivedEvent != null)
{
dataReceivedEvent(new object(), new DataReceivedEventArgs(message));
}
if ((ackRequiredMsg != null) && (message.ack != null))
{
if ((message.ack.id == ackRequiredMsg.id) && message.ack.success)
{
eventWaitForAck.Set();
}
}
}
}
}
catch (ObjectDisposedException objectDisposedException)
{
// Dispatcher.dispatchDebug(Debug.Level_3,"Socket has been closed", this);
notifyErrorEventSubscribers(objectDisposedException);
}
catch (SocketException se)
{
if (se.ErrorCode == 10054)
{
/*
for (int i = 0; i < 50; i++)
{
Thread.Sleep(1000);
}
try
{
SocketCommunicationDaq.Reconnect();
}
catch(Exception ex)
{
VNMsgBox.Show(ex.Message, MsgButtonType.OkOnly, MsgIconType.Error);
return;
}
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
for (int i = 0; i < 3; i++)
{
try
{
connect();
break;
}
catch (Exception ex)
{
System.Threading.Thread.Sleep(5000);
}
}
*/
Logger.Log(EnumLoggingLevel.Error, "OnDataReceived: ", se.ToString());
}
else
{
notifyErrorEventSubscribers(se);
}
}
}
As others have mentioned, TCP is a streaming protocol, so you never can tell how many DataReceived callbacks it will take to get all 100 bytes. Could be 1, could be 100.
The receive code is fairly complex and performance could be improved (too many string operations). Hard to tell if there are control-flow issues. I would suggest breaking the DataReceived method up to simplify. Here's a reasonable skeleton:
public static void OnDataReceived(IAsyncResult result)
{
//1) copy all data received into a buffer of some sort, like MemoryStream
//2) Dispatch any/all full messages that have been received
// to a queue or handler method (maybe handle on another thread)
//(hold onto any leftover bytes received that are part of the next message)
//Call BeginReceive() again
}
Also, it can help simplify Framing if you use a Length-Prefixed message format.
As #nos already stated, number of receives does not equal the number of sends, regardless of the client application was written in.
See also When does TcpClient's NetworkStream finish one read operation?

How to determine if the tcp is connected or not?

I have tcpclient object and i want to determine if it's connected or not.
i use connected property of tcpclient but it returns the state of last operation. so its not useful.
then i use this code :
bool flag;
flag = (tcp.Client.Poll(10000, SelectMode.SelectWrite));
and
if( tcp.Client.Poll( 0, SelectMode.SelectRead ) )
{
byte[] buff = new byte[1];
if( tcp.Client.Receive( buff, SocketFlags.Peek ) == 0 )
{
flag = false;
}
}
but it does not work properly.
Any idea?
this is my code in server side :
private ArrayList _ClientList = new ArrayList();
public ClsServer(int port)
{
_TCPListener = new TcpListener(IPAddress.Any, port);
_TCPListener.Start();
Thread ListenThread = new Thread(new ThreadStart(ListenForClients));
ListenThread.IsBackground = true;
ListenThread.Start();
}
private void ListenForClients()
{
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this._TCPListener.AcceptTcpClient();
client.ReceiveTimeout = 0;
//create a thread to handle communication with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.IsBackground = true;
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
try
{
TcpClient tcpClient = (TcpClient)client;
AddObject(tcpclient);
int bytesRead;
string message = "";
byte[] RecievedPack = new byte[1024 * 1000];
NetworkStream clientStream = tcpClient.GetStream();
while (true)
{
bytesRead = 0;
try
{
////blocks until a client sends a message
bytesRead = clientStream.Read(RecievedPack, 0, RecievedPack.Length);
int Len = BitConverter.ToInt32(RecievedPack, 0);
message = UTF8Encoding.UTF8.GetString(RecievedPack, 0, Len);
}
catch (Exception er)
{
//When Client is disconnected
if (er.GetType() == typeof(IOException))
{
RemoveObject(client);
break;
}
}
//message has successfully been received
// do something
}
RemoveObject(client);
}
catch(Exception e)
{
// RemoveObject(client);
}
}
private void AddObject(object obj)
{
int totalcount, index;
totalcount = _ClientList.Count;
index = 0;
while (index < totalcount)
{
TcpClient alcobj = (TcpClient)_ClientList[index];
try
{
if (IPAddress.Equals(((IPEndPoint)alcobj.Client.RemoteEndPoint).Address,
((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address))
{
_ClientList.Remove(alcobj);
break;
}
index++;
}
catch (Exception er)
{
if (er.GetType() == typeof(ObjectDisposedException))
RemoveObject(alcobj);
}
finally
{
totalcount = _ClientList.Count;
}
}
_ClientList.Add(obj);
}
private void RemoveObject(object obj)
{
if (_ClientList.IndexOf(obj) > -1)
{
_ClientList.Remove(obj);
SendClientState(IP, false);
}
}
and this is the client side :
public bool IsConnected
{
try
{
if (_TcpClient != null && _TcpClient.Client != null && _TcpClient.Client.Connected)
{
// Detect if client disconnected
if (_TcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_TcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
private void clsClient()
{
if(!IsConnected())
{
Connecttoserver()
}
}
private void ConnectToServer()
{
try
{
NetworkStream _NetworkStream = _TcpClient.GetStream();
byte[] _RecievedPack = new byte[1024 * 1000];
string _Message = string.Empty;
int _BytesRead;
int _Length;
while (true)
{
_BytesRead = _NetworkStream.Read(_RecievedPack, 0, _RecievedPack.Length);
_Length = BitConverter.ToInt32(_RecievedPack, 0);
_Message = UTF8Encoding.UTF8.GetString(_RecievedPack, 4, _Length);
if (_BytesRead != 0)
{
if (OnReceive != null)
// do something
_NetworkStream.Flush();
}
}
}
catch (Exception exp)
{
// do something
}
}
in client side, IsConnected() always return false and try to connecttoserver, so the server listener always try to add the client in a list
Use this code instead, I have tested it and using it in real production software:
public bool IsConnected
{
get
{
try
{
if (_tcpClient != null && _tcpClient.Client != null && _tcpClient.Client.Connected)
{
/* pear to the documentation on Poll:
* When passing SelectMode.SelectRead as a parameter to the Poll method it will return
* -either- true if Socket.Listen(Int32) has been called and a connection is pending;
* -or- true if data is available for reading;
* -or- true if the connection has been closed, reset, or terminated;
* otherwise, returns false
*/
// Detect if client disconnected
if (_tcpClient.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (_tcpClient.Client.Receive(buff, SocketFlags.Peek) == 0)
{
// Client disconnected
return false;
}
else
{
return true;
}
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
}
Edit: However you can't rely on just checking the connection and if true proceed, because it returning the status of connection at time this property executed, for instance after you check IsConnected and it returns true, and while you are in the middle of communication, the connection maybe lost there! we just use it in the first place to reduce the probability of failure, So you have to wrap the whole communication in a try/catch and expect the connection to be lost at any time!
I suggest not relaying on such methods.
For my opinion, the best way is to implement some kind of keep-alive mechanism.
Every X seconds, send a small message and wait for an answer.
You're probably disconnected when:
1. You catch an exception when trying to send a keep-alive message (if you're the client side).
2. You don't get a keep-alive message/response for some period of time.
I also suggest not to count on the built-in TCP keep-alive, I found it very not-reliable.
Updated: Found a nice post for this matter: Post
The only way to know whether or not the other end of a socket connection is still connected is by catching the result of a read or write operation or possibly catching an exception.
For more information please refer to this StackOverflow question:
Instantly detect client disconnection from server socket
Here is a small snippet of code that is simply using a Socket in non-blocking mode and connected to a server.
try
{
bytesRead = nambSok.Receive(message, 4096, SocketFlags.None);
}
catch (SocketException e)
{
//a socket error has occured
switch (e.SocketErrorCode)
{
case System.Net.Sockets.SocketError.TimedOut:
case System.Net.Sockets.SocketError.WouldBlock:
if (doDisconnect == false)
{
continue;
}
break;
case System.Net.Sockets.SocketError.ConnectionReset:
case System.Net.Sockets.SocketError.ConnectionAborted:
isConnected = false;
break;
}
}
if (bytesRead > 0)
{
/* do something with data */
}
The "keep-alive" method Lior Ohana proposed is also a great idea. Force each client to "check in" every X seconds. The client can detect the server is gone if an exception occurs on the write, and the server knows the client has gone away if a "keep-alive" message hasn't been received in X seconds.
I agree with Lior Ohana because I had this problem with remote devices that were used GPRS Tcp connection. when device is turn off or disconnected, it did not alert to the sever. There for I used this code: I send Specific time to the clients
void AnalyzeForHandShaking(Socket socketin, string Message)
{
Socket handler = socketin;
try
{
Message = Message.Trim();
if (!string.IsNullOrEmpty(Message.Trim()))
// if (Message.Equals("~"))
{
// string Serial = getSerialFromSocket(socketin).Trim();
DateTime dt = DateTime.Now;
if (handler!=null)
//if there is serial in hastable
if (!arrIPTimeHandShaking.ContainsKey(handler))
{
arrIPTimeHandShaking.Add(handler, dt);
}
else
{
arrIPTimeHandShaking[handler] = dt;
}
}
}
catch
{
}
}

Constantly running server

When a client disconnects, the server closes. Tell me how to leave the ability to connect new customers after the close of the first session .Thanks in advance.
namespace tcpserver
{
class Program
{
static void Main(string[] args)
{
string cmd;
int port = 56568;
Server Serv = new Server(); // Создаем новый экземпляр класса
// сервера
Serv.Create(port);
while (true)
{
cmd = Console.ReadLine(); // Ждем фразы EXIT когда
// понадобится выйти из приложения.
// типа интерактивность.
if (cmd == "EXIT")
{
Serv.Close(); // раз выход – значит выход. Серв-нах.
return;
}
}
//while (Serv.Close() == true) { Serv.Create(port); }
}
public class Server // класс сервера.
{
private int LocalPort;
private Thread ServThread; // экземпляр потока
TcpListener Listener; // листенер))))
public void Create(int port)
{
LocalPort = port;
ServThread = new Thread(new ThreadStart(ServStart));
ServThread.Start(); // запустили поток. Стартовая функция –
// ServStart, как видно выше
}
public void Close() // Закрыть серв?
{
Listener.Stop();
ServThread.Abort();
return;
}
private void ServStart()
{
Socket ClientSock; // сокет для обмена данными.
string data;
byte[] cldata = new byte[1024]; // буфер данных
Listener = new TcpListener(LocalPort);
Listener.Start(); // начали слушать
Console.WriteLine("Waiting connections on " + Convert.ToString(LocalPort) + " port");
try
{
ClientSock = Listener.AcceptSocket(); // пробуем принять клиента
}
catch
{
ServThread.Abort(); // нет – жаль(
return;
}
int i = 0;
if (ClientSock.Connected)
{
while (true)
{
try
{
i = ClientSock.Receive(cldata); // попытка чтения
// данных
}
catch
{
}
try
{
if (i > 0)
{
data = Encoding.ASCII.GetString(cldata).Trim();
Console.WriteLine("<" + data);
if (data == "CLOSE") // если CLOSE –
// вырубимся
{
ClientSock.Send(Encoding.ASCII.GetBytes("Closing the server..."));
ClientSock.Close();
Listener.Stop();
Console.WriteLine("Server closed. Reason: client wish! Type EXIT to quit the application.");
ServThread.Abort();
return;
}
else
{ // нет – шлем данные взад.
ClientSock.Send(Encoding.ASCII.GetBytes("Your data: " + data));
}
}
}
catch
{
ClientSock.Close(); //
Listener.Stop();
Console.WriteLine("Client disconnected. Server closed.");
ServThread.Abort();
}
}
}
}
}
}
}
Typical threaded server code will read more like this (in a pseudo code, because I don't know enough Java details to write it exactly, and because C is a bit stifling):
socket s = new socket
bind s to an optional IP, port
listen s
while true
cli = accept s
t = new thread(handle_client, cli)
maybe disown thread, so no need to join it later
t.start
The important point is that creating the socket, binding it to an address, and listen are all handled outside the loop, and accept() and starting threads are inside the loop.
You may want to wrap this entire block inside another thread; that is acceptable. The important part is separating the listen from the accept and per-client thread. This allows your code to stop accepting new connections but handle existing clients until they disconnect, or disconnect existing connections when they use their allotment of resources but continue accepting connections, etc. (Note how your last catch block will terminate the server if any single client socket throws an exception; that kind of code is easy to avoid with the usual server layout.)
replace
ServThread.Abort();
return;
with a continue instead, this will not break the while loop and yet stop the current "round". Please consider reading this: http://www.codeproject.com/KB/IP/serversocket.aspx nice project to build from

Categories

Resources