In my HoloLens2 application sometimes the UDP-Package-receive rate drops instantly from 40 packages per second to 0-2 packages per second and stays there (size of packages between 2000 byte and 60000 byte. The application is made with Unity3d and .Net Sockets for networking. This behaviour sometimes happens straight from application startup, sometimes after 30 minutes, so basically quiet random. Even Restarting HoloLens2 doesn´t help in such a situation. The application logs no exception or error messages. On my Unity-Editor the Application can handle the network traffic without any problem.
It feels like some Network buffer got stuffend and drops all packages so did I miss some Cleanup command in my Networking-Code or is there another way to face Receive-Overload in my code?
Or is HoloLens2 somehow limited in it´s Bandwith when running via Ethernet (and not Wifi)?
At the same time my application also maintains a peer-to-peer Video-stream (WebRTC with MixedReality Capture). This stream works well over the whole lifetime of the application flawlessly.
using System;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;
public class UdpCommunicationDotNet : ICommunicator
{
#region Fields
private int m_PackageCountPerSecond;
private int m_PackageCountTotal;
private Thread m_PackageCounterResetRoutine;
private Socket m_SenderSocket;
private Socket m_ReceiverSocket;
private IPEndPoint m_ServerIpEndPoint;
private IPEndPoint m_ReceiverIpEndPoint;
private IPEndPoint m_ListenerIpEndPoint;
private EndPoint m_ServerEndPoint;
private EndPoint m_ReceiverEndPoint;
private byte[] m_ReceiveBuffer;
private IDataProvider m_DataProvider;
private int m_MaxBufferByteLength;
private bool m_ReceiveEnabled = true;
public IDataProvider DataProvider { get => m_DataProvider; set => m_DataProvider = value; }
#endregion
#region Constructor
public UdpCommunicationDotNet()
{
m_MaxBufferByteLength = GameManager.Instance.GetConfigurationManager.RuntimeConfig.NetworkSettings.MaxBufferByteLength;
}
#endregion
#region Public Methods
public void Initialize(DataLineConfig dataLineConfig)
{
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
m_ServerIpEndPoint = dataLineConfig.serverEndPoint;
m_ReceiverIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
m_ServerEndPoint = (EndPoint)m_ServerIpEndPoint;
m_ReceiverEndPoint = (EndPoint)m_ReceiverIpEndPoint;
m_ListenerIpEndPoint = dataLineConfig.receiverEndPoint;
}
public void StartReceiver()
{
if (InitializeReceiverSocket())
{
m_ReceiveEnabled = true;
StartReceiving();
}
}
public void EndReceiver()
{
m_ReceiveEnabled = false;
}
public void StartSender()
{
InitializeSenderSocket();
}
public void Send(Byte[] data)
{
try
{
//added this, remove it
//Debug.Log("SentMyDataPackage");
m_SenderSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, m_ServerEndPoint, new AsyncCallback(OnSendCallback), null);
}
catch (Exception e)
{
Debug.LogError("Failed to send udp data through the UdpCommunicator: " + e.Message);
}
}
#endregion
#region Private Methods
private bool InitializeReceiverSocket()
{
bool isInitialized = false;
try
{
m_ReceiverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
m_ReceiverSocket.Bind(m_ListenerIpEndPoint);
isInitialized = true;
}
catch (Exception e)
{
Debug.LogError("Failed to initialize the receiver socket in the UdpCommunicator: " + e.Message);
}
return isInitialized;
}
private void InitializeSenderSocket()
{
m_SenderSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
}
private void StartReceiving()
{
m_ReceiverSocket.BeginReceiveFrom(m_ReceiveBuffer, 0, m_ReceiveBuffer.Length, SocketFlags.None, ref m_ReceiverEndPoint, new AsyncCallback(OnReceiveCallback), m_ReceiverEndPoint);
}
private void DistributeData(object dataObject)
{
byte[] data = (byte[])dataObject;
m_DataProvider.DistributeData(data);
}
#endregion
#region Callback Methods
private void OnSendCallback(IAsyncResult asyncResult)
{
try
{
m_SenderSocket.EndSend(asyncResult);
}
catch (Exception e)
{
Debug.LogError("Failed to close the opened send connection in the UdpCommunicator: " + e.Message);
}
}
private void OnReceiveCallback(IAsyncResult asyncResult)
{
try
{
if (DebugManager.Instance.isActive)
{
DebugManager.Instance.m_PackageCounter.UpdateMainCountTotal(m_PackageCountTotal);
}
int receivedBufferSize = m_ReceiverSocket.EndReceiveFrom(asyncResult, ref m_ReceiverEndPoint);
Array.Resize(ref m_ReceiveBuffer, receivedBufferSize);
byte[] copiedBuffer = new byte[receivedBufferSize];
Buffer.BlockCopy(m_ReceiveBuffer, 0, copiedBuffer, 0, receivedBufferSize);
Thread thread = new Thread(DistributeData);
thread.SetApartmentState(ApartmentState.STA);
thread.Start(copiedBuffer);
m_ReceiveBuffer = new byte[m_MaxBufferByteLength];
}
catch (Exception e)
{
Debug.LogError("Failed to fetch the received data in the UdpCommunicator: " + e.Message);
}
finally
{
if (m_ReceiveEnabled)
{
StartReceiving();
}
else
{
m_ReceiverSocket.Shutdown(SocketShutdown.Both);
m_SenderSocket.Shutdown(SocketShutdown.Both);
m_ReceiverSocket.Close();
m_SenderSocket.Close();
}
}
}
#endregion
}
Edit:
By writing the Minimal Reproducable Example I found out the reason for the missbehaviour! I realized that if I send more than 4 Packages in one chunk (so send package1, send package2, send package3, send package4, etc, wait x ms, start again) HoloLens2 is starting to drop my udp packages.
In contrast, when I send Package1-> wait for 4 ms -> send package2 -> wait for 4 ms -> send package 3 -> wait 4ms and so on and after sending all different packages simply restart sending, it Works like a charm!
Also, when I send the packages via EthernetOverUSB (what is not a usable approach for my case), even if I send all packages in one chunk it works.
For me this behaviour is wiered and I can´t explain it to myself. Maybe somebody of you can ? Anyways, thanks for anybody who tried to help me!
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;
}
}
}
I use the following piece of code to achieve this goal:
public static bool IsServerListening()
{
var endpoint = new IPEndPoint(IPAddress.Parse("201.212.1.167"), 2593);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
socket.Connect(endpoint, TimeSpan.FromSeconds(5));
return true;
}
catch (SocketException exception)
{
if (exception.SocketErrorCode == SocketError.TimedOut)
{
Logging.Log.Warn("Timeout while connecting to UO server game port.", exception);
}
else
{
Logging.Log.Error("Exception while connecting to UO server game port.", exception);
}
return false;
}
catch (Exception exception)
{
Logging.Log.Error("Exception while connecting to UO server game port.", exception);
return false;
}
finally
{
socket.Close();
}
}
Here is my extension method to the Socket class:
public static class SocketExtensions
{
public const int CONNECTION_TIMEOUT_ERROR = 10060;
/// <summary>
/// Connects the specified socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="endpoint">The IP endpoint.</param>
/// <param name="timeout">The connection timeout interval.</param>
public static void Connect(this Socket socket, EndPoint endpoint, TimeSpan timeout)
{
var result = socket.BeginConnect(endpoint, null, null);
bool success = result.AsyncWaitHandle.WaitOne(timeout, true);
if (!success)
{
socket.Close();
throw new SocketException(CONNECTION_TIMEOUT_ERROR); // Connection timed out.
}
}
}
The problem is this piece of code works on my development environment but when I move it into production environment it always times out (regardless of whether I set the timeout interval to 5 or 20 seconds)
Is there some other way I could check if that IP is actively listening at that particular port?
What is the reason why I can't do this from my hosting environment?
You can run netstat -na from command line to see all (including listening) ports.
If you add -b you will also see linked executable to each connection/listening.
In .NET you can get all listening connections with System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().GetActiveTcpListeners()
You can check it by using this code:
TcpClient tc = new TcpClient();
try
{
tc.Connect(<server ipaddress>, <port number>);
bool stat = tc.Connected;
if (stat)
MessageBox.Show("Connectivity to server available.");
tc.Close();
}
catch(Exception ex)
{
MessageBox.Show("Not able to connect : " + ex.Message);
tc.Close();
}
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
{
}
}
When the Client tries to connect to a disconnected IP address, there is a long timeout over 15 seconds... How can we reduce this timeout? What is the method to configure it?
The code I'm using to set up a socket connection is as following:
try
{
m_clientSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(serverIp);
int iPortNo = System.Convert.ToInt16(serverPort);
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
m_clientSocket.Connect(ipEnd);
if (m_clientSocket.Connected)
{
lb_connectStatus.Text = "Connection Established";
WaitForServerData();
}
}
catch (SocketException se)
{
lb_connectStatus.Text = "Connection Failed";
MessageBox.Show(se.Message);
}
I found this. Simpler than the accepted answer, and works with .NET Framework v2
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Connect using a timeout (5 seconds)
IAsyncResult result = socket.BeginConnect( sIP, iPort, null, null );
bool success = result.AsyncWaitHandle.WaitOne( 5000, true );
if ( socket.Connected )
{
socket.EndConnect( result );
}
else
{
// NOTE, MUST CLOSE THE SOCKET
socket.Close();
throw new ApplicationException("Failed to connect server.");
}
//...
My take:
public static class SocketExtensions
{
/// <summary>
/// Connects the specified socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="endpoint">The IP endpoint.</param>
/// <param name="timeout">The timeout.</param>
public static void Connect(this Socket socket, EndPoint endpoint, TimeSpan timeout)
{
var result = socket.BeginConnect(endpoint, null, null);
bool success = result.AsyncWaitHandle.WaitOne(timeout, true);
if (success)
{
socket.EndConnect(result);
}
else
{
socket.Close();
throw new SocketException(10060); // Connection timed out.
}
}
}
I just wrote an extension class in order to allow timeouts in connections. Use it exactly as you would use the standard Connect() methods, with an extra parameter named timeout.
using System;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// Extensions to Socket class
/// </summary>
public static class SocketExtensions
{
/// <summary>
/// Connects the specified socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="host">The host.</param>
/// <param name="port">The port.</param>
/// <param name="timeout">The timeout.</param>
public static void Connect(this Socket socket, string host, int port, TimeSpan timeout)
{
AsyncConnect(socket, (s, a, o) => s.BeginConnect(host, port, a, o), timeout);
}
/// <summary>
/// Connects the specified socket.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="addresses">The addresses.</param>
/// <param name="port">The port.</param>
/// <param name="timeout">The timeout.</param>
public static void Connect(this Socket socket, IPAddress[] addresses, int port, TimeSpan timeout)
{
AsyncConnect(socket, (s, a, o) => s.BeginConnect(addresses, port, a, o), timeout);
}
/// <summary>
/// Asyncs the connect.
/// </summary>
/// <param name="socket">The socket.</param>
/// <param name="connect">The connect.</param>
/// <param name="timeout">The timeout.</param>
private static void AsyncConnect(Socket socket, Func<Socket, AsyncCallback, object, IAsyncResult> connect, TimeSpan timeout)
{
var asyncResult = connect(socket, null, null);
if (!asyncResult.AsyncWaitHandle.WaitOne(timeout))
{
try
{
socket.EndConnect(asyncResult);
}
catch (SocketException)
{ }
catch (ObjectDisposedException)
{ }
}
}
it might be too late but there is neat solution based on Task.WaitAny (c# 5 +) :
public static bool ConnectWithTimeout(this Socket socket, string host, int port, int timeout)
{
bool connected = false;
Task result = socket.ConnectAsync(host, port);
int index = Task.WaitAny(new[] { result }, timeout);
connected = socket.Connected;
if (!connected) {
socket.Close();
}
return connected;
}
I dont program in C# but in C, we solve the same problem by making the socket non-blocking and then putting the fd in a select/poll loop with a timeout value equal to the amount of time we are willing to wait for the connect to succeed.
I found this for Visual C++ and the explanation there also bends towards the select/poll mechanism I explained before.
In my experience, you cannot change connect timeout values per socket. You change it for all (by tuning OS parameters).
I solved the problem by using Socket.ConnectAsync Method instead of Socket.Connect Method.
After invoking the Socket.ConnectAsync(SocketAsyncEventArgs), start a timer (timer_connection), if time is up, check whether socket connection is connected (if(m_clientSocket.Connected)), if not, pop up timeout error.
private void connect(string ipAdd,string port)
{
try
{
SocketAsyncEventArgs e=new SocketAsyncEventArgs();
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(serverIp);
int iPortNo = System.Convert.ToInt16(serverPort);
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
//m_clientSocket.
e.RemoteEndPoint = ipEnd;
e.UserToken = m_clientSocket;
e.Completed+=new EventHandler<SocketAsyncEventArgs>(e_Completed);
m_clientSocket.ConnectAsync(e);
if (timer_connection != null)
{
timer_connection.Dispose();
}
else
{
timer_connection = new Timer();
}
timer_connection.Interval = 2000;
timer_connection.Tick+=new EventHandler(timer_connection_Tick);
timer_connection.Start();
}
catch (SocketException se)
{
lb_connectStatus.Text = "Connection Failed";
MessageBox.Show(se.Message);
}
}
private void e_Completed(object sender,SocketAsyncEventArgs e)
{
lb_connectStatus.Text = "Connection Established";
WaitForServerData();
}
private void timer_connection_Tick(object sender, EventArgs e)
{
if (!m_clientSocket.Connected)
{
MessageBox.Show("Connection Timeout");
//m_clientSocket = null;
timer_connection.Stop();
}
}
Check this out on MSDN. It does not appear that you can do this with the implemented properties in the Socket class.
The poster on MSDN actually solved his problem using threading. He had a main thread which called out to other threads which run the connection code for a couple seconds and then check the Connected property of the socket:
I created another method wich actually
connected the socket ... had the main
thread sleep for 2 seconds and then
check on the connecting method (wich
is run in a separate thread) if the
socket was connected good otherwise
throw an exception "Timed out " and
that;s all. Thanks again for the
repleies.
What are you trying to do, and why can't it wait for 15-30 seconds before timing out?
I had the Same problem when connecting to a Socket and I came up with the below solution ,It works Fine for me.
`
private bool CheckConnectivityForProxyHost(string hostName, int port)
{
if (string.IsNullOrEmpty(hostName))
return false;
bool isUp = false;
Socket testSocket = null;
try
{
testSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = null;
if (testSocket != null && NetworkingCollaboratorBase.GetResolvedConnecionIPAddress(hostName, out ip))//Use a method to resolve your IP
{
IPEndPoint ipEndPoint = new IPEndPoint(ip, port);
isUp = false;
//time out 5 Sec
CallWithTimeout(ConnectToProxyServers, 5000, testSocket, ipEndPoint);
if (testSocket != null && testSocket.Connected)
{
isUp = true;
}
}
}
}
catch (Exception ex)
{
isUp = false;
}
finally
{
try
{
if (testSocket != null)
{
testSocket.Shutdown(SocketShutdown.Both);
}
}
catch (Exception ex)
{
}
finally
{
if (testSocket != null)
testSocket.Close();
}
}
return isUp;
}
private void CallWithTimeout(Action<Socket, IPEndPoint> action, int timeoutMilliseconds, Socket socket, IPEndPoint ipendPoint)
{
try
{
Action wrappedAction = () =>
{
action(socket, ipendPoint);
};
IAsyncResult result = wrappedAction.BeginInvoke(null, null);
if (result.AsyncWaitHandle.WaitOne(timeoutMilliseconds))
{
wrappedAction.EndInvoke(result);
}
}
catch (Exception ex)
{
}
}
private void ConnectToProxyServers(Socket testSocket, IPEndPoint ipEndPoint)
{
try
{
if (testSocket == null || ipEndPoint == null)
return;
testSocket.Connect(ipEndPoint);
}
catch (Exception ex)
{
}
}
I worked with Unity and had some problem with the BeginConnect and other async methods from socket.
There is something than I don't understand but the code samples before doesn't work for me.
So I wrote this piece of code to make it work. I test it on an adhoc network with android and pc, also in local on my computer. Hope it can help.
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System;
using System.Diagnostics;
class ConnexionParameter : Guardian
{
public TcpClient client;
public string address;
public int port;
public Thread principale;
public Thread thisthread = null;
public int timeout;
private EventWaitHandle wh = new AutoResetEvent(false);
public ConnexionParameter(TcpClient client, string address, int port, int timeout, Thread principale)
{
this.client = client;
this.address = address;
this.port = port;
this.principale = principale;
this.timeout = timeout;
thisthread = new Thread(Connect);
}
public void Connect()
{
WatchDog.Start(timeout, this);
try
{
client.Connect(IPAddress.Parse(address), port);
}
catch (Exception)
{
UnityEngine.Debug.LogWarning("Unable to connect service (Training mode? Or not running?)");
}
OnTimeOver();
//principale.Resume();
}
public bool IsConnected = true;
public void OnTimeOver()
{
try
{
if (!client.Connected)
{
/*there is the trick. The abort method from thread doesn't
make the connection stop immediately(I think it's because it rise an exception
that make time to stop). Instead I close the socket while it's trying to
connect , that make the connection method return faster*/
IsConnected = false;
client.Close();
}
wh.Set();
}
catch(Exception)
{
UnityEngine.Debug.LogWarning("Connexion already closed, or forcing connexion thread to end. Ignore.");
}
}
public void Start()
{
thisthread.Start();
wh.WaitOne();
//principale.Suspend();
}
public bool Get()
{
Start();
return IsConnected;
}
}
public static class Connexion
{
public static bool Connect(this TcpClient client, string address, int port, int timeout)
{
ConnexionParameter cp = new ConnexionParameter(client, address, port, timeout, Thread.CurrentThread);
return cp.Get();
}
//http://stackoverflow.com/questions/19653588/timeout-at-acceptsocket
public static Socket AcceptSocket(this TcpListener tcpListener, int timeoutms, int pollInterval = 10)
{
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutms);
var stopWatch = new Stopwatch();
stopWatch.Start();
while (stopWatch.Elapsed < timeout)
{
if (tcpListener.Pending())
return tcpListener.AcceptSocket();
Thread.Sleep(pollInterval);
}
return null;
}
}
and there a very simple watchdog on C# to make it work:
using System.Threading;
public interface Guardian
{
void OnTimeOver();
}
public class WatchDog {
int m_iMs;
Guardian m_guardian;
public WatchDog(int a_iMs, Guardian a_guardian)
{
m_iMs = a_iMs;
m_guardian = a_guardian;
Thread thread = new Thread(body);
thread.Start(this);
}
private void body(object o)
{
WatchDog watchdog = (WatchDog)o;
Thread.Sleep(watchdog.m_iMs);
watchdog.m_guardian.OnTimeOver();
}
public static void Start(int a_iMs, Guardian a_guardian)
{
new WatchDog(a_iMs, a_guardian);
}
}
This is like FlappySock's answer, but I added a callback to it because I didn't like the layout and how the Boolean was getting returned. In the comments of that answer from Nick Miller:
In my experience, if the end point can be reached, but there is no server on the endpoint able to receive the connection, then AsyncWaitHandle.WaitOne will be signaled, but the socket will remain unconnected
So to me, it seems relying on what is returned can be dangerous - I prefer to use socket.Connected. I set a nullable Boolean and update it in the callback function. I also found it doesn't always finish reporting the result before returning to the main function - I handle for that, too, and make it wait for the result using the timeout:
private static bool? areWeConnected = null;
private static bool checkSocket(string svrAddress, int port)
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(svrAddress), port);
Socket socket = new Socket(endPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
int timeout = 5000; // int.Parse(ConfigurationManager.AppSettings["socketTimeout"].ToString());
int ctr = 0;
IAsyncResult ar = socket.BeginConnect(endPoint, Connect_Callback, socket);
ar.AsyncWaitHandle.WaitOne( timeout, true );
// Sometimes it returns here as null before it's done checking the connection
// No idea why, since .WaitOne() should block that, but it does happen
while (areWeConnected == null && ctr < timeout)
{
Thread.Sleep(100);
ctr += 100;
} // Given 100ms between checks, it allows 50 checks
// for a 5 second timeout before we give up and return false, below
if (areWeConnected == true)
{
return true;
}
else
{
return false;
}
}
private static void Connect_Callback(IAsyncResult ar)
{
areWeConnected = null;
try
{
Socket socket = (Socket)ar.AsyncState;
areWeConnected = socket.Connected;
socket.EndConnect(ar);
}
catch (Exception ex)
{
areWeConnected = false;
// log exception
}
}
Related: How to check if I'm connected?
I have tried with dotnet 6, and after accepting a connection dotnet allows you to set the timeout.
Socket clientSocket = listener.Accept();
clientSocket.ReceiveTimeout = 1000;
and the you have to manage with Receive
try
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes, 0, numByte);
break;
}
catch (System.Net.Sockets.SocketException e)
{
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
goto NewSocket;
}
Source: Microsoft
There should be a ReceiveTimeout property in the Socket class.
Socket.ReceiveTimeout Property