Reconnecting to socket.io server takes long time after receiving messages using SocketIoClientDotNet - c#

I'm developing a plugin for Grasshopper for Rhino which uses a .NET framework with C# and I have a problem when reconnecting to a socket.io 1.4.5 server. I'm using SocketIoClientDotNet 0.9.13 to connect to a server and it works fine if I just want to connect/disconnect to a server but I have a problem reconnecting to a server after I received a message using an event taking a lot of time to reconnect.
Depends on the number of messages I received by the event during the connection, after I close and make a new connection it takes more than a minute (sometimes more than 10 mins if there are a lot of messages received) for the new connection.
Could anybody tell what is going wrong?
The code is written as follows:
Quobject.SocketIoClientDotNet.Client.Socket socket;
private System.Threading.ManualResetEvent manualResetEvent = null;
private bool currentState = false;
public object output = null;
public bool connected = false;
private Quobject.SocketIoClientDotNet.Client.IO.Options CreateOptions()
{
Quobject.SocketIoClientDotNet.Client.IO.Options op = new Quobject.SocketIoClientDotNet.Client.IO.Options();
op.AutoConnect = true;
op.Reconnection = true;
op.ReconnectionAttempts = 5;
op.ReconnectionDelay = 5;
op.Timeout = 20;
op.Secure = true;
op.ForceNew = true;
op.Multiplex = true;
return op;
}
private void ConnectToSocket(bool b, string address){
if(currentState != b){
if(b && !connected){
manualResetEvent = new System.Threading.ManualResetEvent(false);
var options = CreateOptions();
socket = IO.Socket(address, options);
socket.On(Quobject.SocketIoClientDotNet.Client.Socket.EVENT_CONNECT, () =>
{
connected = true;
Print("connected");
manualResetEvent.Set();
});
socket.On("slider_message", (data) =>
{
if(data != null){
var jobject = data as JToken;
try{
var sliderValue = jobject.Value<string>("slider");
output = sliderValue;
}catch{
}
}
manualResetEvent.Set();
});
socket.On(Quobject.SocketIoClientDotNet.Client.Socket.EVENT_DISCONNECT, () =>
{
connected = false;
Print("disconnected");
manualResetEvent.Set();
});
Print("connecting...");
manualResetEvent.WaitOne();
}else{
if(socket != null & connected){
manualResetEvent = new System.Threading.ManualResetEvent(false);
Print("disconnecting...");
socket.Close();
manualResetEvent.WaitOne();
socket = null;
}
}
}
currentState = b;
}

Related

C# TCP server sometimes send string containing parts of last message

I am working on my project in which i need arduinos to comunicate with my TCP server app. Eveyrthing was going fine as of now. But i just noticed that the server sometimes send invalid string to the client. (the string simply contains parts of the last string sent) Those the arduino doesnt know what to do with it.
How it should work:
Server receives: "CNN:1" (connection request from arduino #1)
Server sends: "CNN:1:CFM" (confirming that the request was recieved.
Server Recieves: "PING"
Server Sends: "PONG"
Server Recieves: "CHGTM:1:B" (arduino #1 sends request to change team to Blue)
Server Sends: "CHGTM:1:B:CFM" or "CHGTM:1:GMPAUSED" (depends on wheter the game is running or is paused)
EXAMPLE OF THE BAD BEHAVIOUR:
Server Recieves: "CNN:1"
sends: "CNN:1:CFM"
Recieves: "PING"
Sends: "PONG1:CFM" (This message contains part of the last message those is corrupted -- It doesnt happen everytime only sometimes)
Do anybody know how to fix this? I tried nulling the string variables used to contain the text before sending but no luck. I also tried flushing the networkstream after writing to it but also no luck (as i understand it, this method is just placeholder and doesnt do anything at the moment)
Here is the code that i am using for the communication:
class Comunication
{
TcpListener server = null;
public List<Majak> activeClients;
public MainWindow mw { get; set; }
public bool isConOk { get; set; }
public Comunication(string ip, int port, MainWindow _mw)
{
mw = _mw;
activeClients = new List<Majak>();
IPAddress localAddr = IPAddress.Parse(ip);
server = new TcpListener(localAddr, port);
server.Start();
StartConnectionCheck();
StartListener();
//StartConnectionCheck();
}
public void StartListener()
{
try
{
while (true)
{
TcpClient client = server.AcceptTcpClient();
if(client != null)
{
Majak m = new Majak(client);
Thread t = new Thread(new ParameterizedThreadStart(HandleDevice));
t.Start(m);
activeClients.Add(m);
}
}
}
catch(SocketException e)
{
MessageBox.Show("Nelze spustit server", e.ToString());
server.Stop();
}
}
public void HandleDevice(Object obj)
{
Majak majak = (Majak)obj;
if (majak != null && majak.isConnected)
{
var stream = majak.Client.GetStream();
string imei = String.Empty;
string data = null;
Byte[] bytes = new Byte[256];
int i;
try
{
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
string hex = BitConverter.ToString(bytes);
data = Encoding.ASCII.GetString(bytes, 0, i); //text revieved from arduino needs evaluation
DataEvaluation(data, majak);
}
}
catch (Exception e) //if there is an error than the client is closed and removed from list of connected clients and this thread is stopped
{
//MessageBox.Show(e.ToString(), "Chyba při komunikaci s majákem");
App.Current.Dispatcher.Invoke((Action)delegate // <--- HERE
{
activeClients.Remove(majak);
});
majak.isConnected = false;
majak.Client.Close();
return;
}
}
}
public void DataEvaluation(string d, Majak m)
{
//split data by ":"
string[] datasplt = d.Split(':');
switch(datasplt[0]){
case "CNN":
m.ID = int.Parse(datasplt[1]);
SendResponse(1, m);
break;
case "PONG":
isConOk = true;
break;
case "PING":
SendResponse(3, m);
break;
case "CHGTM":
m.Color = datasplt[2];
if(mw.SS.ChangeTeam(int.Parse(datasplt[1]), datasplt[2]))
{
SendResponse(2, m); //if the game is running than sends confirmation to the arduino
}
else
{
SendResponse(4, m); //if the game is paused sends to arduino string saying so
}
break;
}
}
public void SendResponse(int i, Majak m)
{
string response = null;
Byte[] response_byte = null;
switch (i)
{
case 1: //connection cofirmation
//connection validation
response = null;
response = string.Format("CNN:{0}:CFM", m.ID);
response_byte = null;
response_byte = System.Text.Encoding.ASCII.GetBytes(response);
try
{
m.Client.GetStream().Write(response_byte, 0, response_byte.Length);
m.Client.GetStream().Flush();
}
catch { }
break;
case 2: //change team confirmation
//confirms change of team
response = null;
response = string.Format("CHGTM:{0}:{1}:CFM", m.ID, m.Color);
response_byte = null;
response_byte = System.Text.Encoding.ASCII.GetBytes(response);
try
{
m.Client.GetStream().Write(response_byte, 0, response_byte.Length);
m.Client.GetStream().Flush();
}
catch { }
break;
case 3: //Sends PONG if PING is recieved
response = null;
response = "PONG";
response_byte = null;
response_byte = System.Text.Encoding.ASCII.GetBytes(response);
try
{
m.Client.GetStream().Write(response_byte, 0, response_byte.Length);
m.Client.GetStream().Flush();
}
catch { }
break;
case 4:
response = null;
response = string.Format("CHGTM:{0}:GMPAUSED", m.ID);
response_byte = null;
response_byte = System.Text.Encoding.ASCII.GetBytes(response);
try
{
m.Client.GetStream().Write(response_byte, 0, response_byte.Length);
m.Client.GetStream().Flush();
}
catch { }
break;
}
}
public void StartConnectionCheck()
{
Thread t = new Thread(new ParameterizedThreadStart(CheckConnectionStatus));
t.Start(mw);
}
public void CheckConnectionStatus(Object __mw) //every 30 seconds sends PING to the arduino in order to evaluate if the connection still exists. If the PONG is not recieved in 30 seconds than closes connection and remove client from connected clients
{
while (true)
{
string pingmsg = "PING";
Byte[] pingmsg_byte = System.Text.Encoding.ASCII.GetBytes(pingmsg);
Stopwatch s = new Stopwatch();
foreach (Majak m in activeClients.ToList<Majak>())
{
isConOk = false;
var stream = m.Client.GetStream();
Byte[] bytes = new Byte[256];
try
{
stream.Write(pingmsg_byte, 0, pingmsg_byte.Length);
s.Restart();
while (s.Elapsed < TimeSpan.FromSeconds(30) && !isConOk)
{
}
if (!isConOk)
{
m.isConnected = false;
activeClients.Remove(m);
m.Client.GetStream().Close();
m.Client.Close();
}
}
catch (Exception e)
{
m.isConnected = false;
activeClients.Remove(m);
m.Client.Close();
}
}
Thread.Sleep(30000);
}
}
}

TcpClient hangs after connection to remote host & application freezes c#

I am trying to establish a connection to a remote host via IP address and Port number. The connection does get established (even verified using cmd netstat) however when I try to close the connection in code:
clientConnection.Client.Close();
clientConnection.Client.Dispose();
clientConnection.Close();
The program crashes because the socket does not have any available data to be read from the client stream. In my windows application (client) I have a button which I click to call the ConnectToFalcon method and that calls the ReadStream method. Please let me know where have I been going wrong.
public void readStream(object argument)
{
clientConnection = (TcpClient)argument;
//TcpClient client = new TcpClient();
DateTime start_time = DateTime.Now;
TimeSpan delay = new TimeSpan(0, 0, 10);
while (clientConnection.Available == 0)
{
Application.DoEvents();
if (DateTime.Now.Subtract(start_time) > delay)
break;
}
if ((clientConnection != null) && (clientConnection.Available > 0))
{
var message = new byte[1];
Array.Resize(ref message, clientConnection.Available);
//remove below two lines and if-statement block if program crashes
clientConnection.Client.ReceiveTimeout = 20000; //Timeout after 20 seconds
clientConnection.SendTimeout = 20000;
if (clientConnection.Client.ReceiveTimeout <= 20000 || clientConnection.SendTimeout == 20000)
{
clientConnection.Client.Receive(message);
string testResult = System.Text.Encoding.Default.GetString(message);
}
else
{
MessageBox.Show("Time expired before read operation completed.");
}
}
else if (((clientConnection == null) && (clientConnection.Available <= 0)) || (clientConnection.Connected == false))
{
clientConnection.Close();
MessageBox.Show("Closing client connection due to insufficient amount of data available to be read");
}
//clientConnection.Client.Close();
//clientConnection.Client.Dispose();
//clientConnection.Close();
}}
public void ConnectToFalcon(string IPaddress, int port)
{
clientConnection = new TcpClient();
//var result = clientConnection.BeginConnect(IPaddress, port, new AsyncCallback(callback), clientConnection);
var result = clientConnection.BeginConnect(IPaddress, port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));
if (success == false)
{
MessageBox.Show("Failed to connect");
}
else
{
MessageBox.Show("Client connected...");
while (true)
{
Thread t = new Thread(readStream);
t.Start(clientConnection); //A new thread is spawned
//t.Start();
}
}
}
According to #Luaan, You must call EndConnect on the IAsyncResult in the callback function in order to acknowledge the client request.`
public void callback(IAsyncResult ar)
{
this.clientConnection.EndConnect(ar);
}
var result = clientConnection.BeginConnect(ip, port, new AsyncCallback(callback), clientConnection);

A very simple TCP server/client in C# occasionally drops packets. What can I do to prevent this?

I've got an intra-PC communication server / client set up to send and receive data from one program to another - in this case, a custom server that is listening to text commands and Unity3D.
For the most part, it works, however every once in awhile, it will drop packets, and Unity will not get them without multiple attempts. The packets seem to be sent but lost, as I do see the "Sent message" console log. The following is the code for the server and client:
SERVER:
class TCPGameServer
{
public event EventHandler Error;
public Action<Data> ADelegate;
TcpListener TCPListener;
TcpClient TCPClient;
Client ActiveClient;
NetworkStream networkStream;
StreamWriter returnWriter;
StreamReader streamReader;
Timer SystemTimer = new Timer();
Timer PingTimer = new Timer();
int Port = 8637;
public TCPGameServer()
{
TCPListener = new TcpListener(IPAddress.Loopback, Port);
SystemTimer.Elapsed += StreamTimer_Tick;
SystemTimer.AutoReset = true;
SystemTimer.Interval = 2000;
PingTimer.Elapsed += PingTimer_Tick;
PingTimer.AutoReset = true;
PingTimer.Interval = 30000;
}
public void OpenListener()
{
TCPListener.Start();
TCPListener.BeginAcceptTcpClient(AcceptTCPCallBack, null);
Console.WriteLine("Network Open.");
}
public void GameLogout()
{
SystemTimer.AutoReset = false;
SystemTimer.Stop();
PingTimer.AutoReset = false;
PingTimer.Stop();
ActiveClient = null;
returnWriter.Dispose();
streamReader.Dispose();
Console.WriteLine("The client has logged out successfully.");
}
private void AcceptTCPCallBack(IAsyncResult asyncResult)
{
TCPClient = null;
ActiveClient = null;
returnWriter = null;
streamReader = null;
try
{
TCPClient = TCPListener.EndAcceptTcpClient(asyncResult);
TCPListener.BeginAcceptTcpClient(AcceptTCPCallBack, null);
ActiveClient = new Client(TCPClient);
networkStream = ActiveClient.NetworkStream;
returnWriter = new StreamWriter(TCPClient.GetStream());
streamReader = new StreamReader(TCPClient.GetStream());
Console.WriteLine("Client Connected Successfully.");
Data Packet = new Data();
Packet.cmdCommand = Command.Login;
Packet.strName = "Server";
Packet.strMessage = "LOGGEDIN";
SendMessage(Packet);
SystemTimer.AutoReset = true;
SystemTimer.Enabled = true;
SystemTimer.Start();
Ping();
PingTimer.AutoReset = true;
PingTimer.Enabled = true;
PingTimer.Start();
} catch (Exception ex)
{
OnError(TCPListener, ex);
return;
}
}
private void StreamTimer_Tick(object source, System.Timers.ElapsedEventArgs e)
{
CheckStream();
}
private void PingTimer_Tick(object source, System.Timers.ElapsedEventArgs e)
{
Ping();
}
private void Ping()
{
if (TCPClient.Connected)
{
Data Packet = new Data();
Packet.cmdCommand = Command.Ping;
Packet.strName = "Server";
Packet.strMessage = "PING";
SendMessage(Packet);
}
}
public void CheckStream()
{
try
{
if (TCPClient.Available > 0 || streamReader.Peek() >= 0)
{
string PacketString = streamReader.ReadLine();
Data packet = JsonConvert.DeserializeObject<Data>(PacketString);
switch (packet.cmdCommand)
{
case Command.Logout:
GameLogout();
break;
case Command.Message:
if (ADelegate != null)
{
ADelegate(packet);
}
break;
case Command.Ping:
Console.WriteLine("PONG!");
break;
}
}
} catch (IOException e)
{
Console.WriteLine(e.Message);
} catch (NullReferenceException e)
{
Console.WriteLine(e.Message);
}
}
public void SendMessage(Data packet)
{
if (ActiveClient != null)
{
string packetMessage = JsonConvert.SerializeObject(packet);
returnWriter.WriteLine(packetMessage);
returnWriter.Flush();
}
}
public void OnError(object sender, Exception ex)
{
EventHandler handler = Error;
if (handler != null)
{
ErrorEventArgs e = new ErrorEventArgs(ex);
handler(sender, e);
}
}
public void RegisterActionDelegate(Action<Data> RegisterDelegate)
{
ADelegate += RegisterDelegate;
}
public void UnRegisterActionDelegate(Action<Data> UnregisterDelegate)
{
ADelegate -= UnregisterDelegate;
}
}
CLIENT:
public class TCPNetworkClient
{
public Action<Data> PacketDelegate;
public TcpClient TCPClient;
int Port = 8637;
StreamReader streamReader;
StreamWriter streamWriter;
Timer StreamTimer = new Timer();
public bool LoggedIn = false;
public void Start()
{
if (LoggedIn == false)
{
TCPClient = null;
StreamTimer.AutoReset = true;
StreamTimer.Interval = 2000;
StreamTimer.Elapsed += StreamTimer_Tick;
try
{
TCPClient = new TcpClient("127.0.0.1", Port);
streamReader = new StreamReader(TCPClient.GetStream());
streamWriter = new StreamWriter(TCPClient.GetStream());
StreamTimer.Enabled = true;
StreamTimer.Start();
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
}
private void StreamTimer_Tick(System.Object source, System.Timers.ElapsedEventArgs e)
{
if (TCPClient.Available > 0 || streamReader.Peek() >= 0)
{
string PacketString = streamReader.ReadLine();
Data packet = JsonConvert.DeserializeObject<Data>(PacketString);
PacketDelegate(packet);
}
}
public void Logout()
{
Data Packet = new Data();
Packet.cmdCommand = Command.Logout;
Packet.strMessage = "LOGOUT";
Packet.strName = "Game";
SendMessage(Packet);
if (streamReader != null && streamWriter != null)
{
streamReader.Dispose();
streamWriter.Dispose();
TCPClient.Close();
TCPClient = null;
streamReader = null;
streamWriter = null;
}
StreamTimer.Stop();
}
public void SendMessage(Data packet)
{
string packetMessage = JsonConvert.SerializeObject(packet);
try
{
streamWriter.WriteLine(packetMessage);
streamWriter.Flush();
} catch (Exception e)
{
}
}
public void RegisterActionDelegate(Action<Data> RegisterDelegate)
{
PacketDelegate += RegisterDelegate;
}
public void UnRegisterActionDelegate(Action<Data> UnregisterDelegate)
{
PacketDelegate -= UnregisterDelegate;
}
}
I'm not really sure what's going on, or if there are any more additional checks that I need to add into the system. Note: It's TCP so that "when" this fully works, I can drop the client into other programs that I might write that may not fully rely or use Unity.
new TcpClient("127.0.0.1", Port) is not appropriate for the client. Just use TcpClient(). There is no need to specify IP and port, both of which will end up being wrong.
TCPClient.Available is almost always a bug. You seem to assume that TCP is packet based. You can't test whether a full message is incoming or not. TCP only offers a boundaryless stream of bytes. Therefore, this Available check does not tell you if a whole line is available. Also, there could be multiple lines. The correct way to read is to have a reading loop always running and simply reading lines without checking. Any line that arrives will be processed that way. No need for timers etc.
The server has the same problems.
Issue (2) might have caused the appearance of lost packets somehow. You need to fix this in any case.

Broadcast from bluetooth server to multiple bluetooth clients with 32feet

I have an issue about the server-client communication.
I googled around but I did not find a solution to this.
Right now I am using 32feet in order to get in touch 2 or more (till 7) BT clients to 1 BT server.
I need to broadcast a message from the server to every device in the same time, but I don't know how to do it.
The only way I figured out was to use the list of connection in order to send the message one per time, but it means a delay between each message sent (around 100 ms per device). Unfortunately it means to have a large delay on the last one.
Can someone please give me an advice on how to solve this problem?
Is there a way to broadcast the message to all devices in the same time?
If it can be helpfull, here there is the handle of connection and reading from devices.
Thanks for your help
private void btnStartServer_Click(object sender, EventArgs e)
{
btnStartClient.Enabled = false;
ConnectAsServer();
}
private void ConnectAsServer()
{
connessioniServer = new List<BluetoothClient>();
// thread handshake
Thread bluetoothConnectionControlThread = new Thread(new ThreadStart(ServerControlThread));
bluetoothConnectionControlThread.IsBackground = true;
bluetoothConnectionControlThread.Start();
// thread connessione
Thread bluetoothServerThread = new Thread(new ThreadStart(ServerConnectThread));
bluetoothServerThread.IsBackground = true;
bluetoothServerThread.Start();
}
private void ServerControlThread()
{
while (true)
{
foreach (BluetoothClient cc in connessioniServer)
{
if (!cc.Connected)
{
connessioniServer.Remove(cc);
break;
}
}
updateConnList();
Thread.Sleep(0);
}
}
Guid mUUID = new Guid("fc5ffc49-00e3-4c8b-9cf1-6b72aad1001a");
private void ServerConnectThread()
{
updateUI("server started");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
while (true)
{
BluetoothClient conn = blueListener.AcceptBluetoothClient();
connessioniServer.Add(conn);
Thread appoggio = new Thread(new ParameterizedThreadStart(ThreadAscoltoClient));
appoggio.IsBackground = true;
appoggio.Start(conn);
updateUI(conn.RemoteMachineName+" has connected");
}
}
private void ThreadAscoltoClient(object obj)
{
BluetoothClient clientServer = (BluetoothClient)obj;
Stream streamServer = clientServer.GetStream();
streamServer.ReadTimeout=1000;
while (clientServer.Connected)
{
try
{
int bytesDaLeggere = clientServer.Available;
if (bytesDaLeggere > 0)
{
byte[] bytesLetti = new byte[bytesDaLeggere];
int byteLetti = 0;
while (bytesDaLeggere > 0)
{
int bytesDavveroLetti = streamServer.Read(bytesLetti, byteLetti, bytesDaLeggere);
bytesDaLeggere -= bytesDavveroLetti;
byteLetti += bytesDavveroLetti;
}
updateUI("message sent from "+clientServer.RemoteMachineName+": " + System.Text.Encoding.Default.GetString(bytesLetti));
}
}
catch { }
Thread.Sleep(0);
}
updateUI(clientServer.RemoteMachineName + " has gone");
}
private void updateUI(string message)
{
Func<int> del = delegate()
{
textBox1.AppendText(message + System.Environment.NewLine);
return 0;
};
Invoke(del);
}
private void updateConnList()
{
Func<int> del = delegate()
{
listaSensori.Items.Clear();
foreach (BluetoothClient d in connessioniServer)
{
listaSensori.Items.Add(d.RemoteMachineName);
}
return 0;
};
try
{
Invoke(del);
}
catch { }
}
I don't exactly understand how you do it right now (the italian names are not helping...) but maybe my solution can help you.
first of all, bluetooth classic does not support broadcast. so you have to deliver at one at a time.
i do connect to 7 serial port devices at a time, using 7 threads. then i tell every thread to send data. this is very close to same time, but of course not exactly.
let me know if that helps or if you need a code example.

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
{
}
}

Categories

Resources