Hi,
I try to implement a reusable socket class to send and receive data.
It seems to work but I have 2 problems :
1) I rely on Socket.Availabl e to detect that the connection is closed (no
more data to expect). Sometimes, Socket.Availabl e returns 0 but the other
end of the connection did not close it !
2) This class will be used by many other classes so I have to use the
minimum system resource. I just found that the first parameter for
Socket.Poll is in microseconds ! I thought it was milliseconds.
How can I improve/correct this class ?
Thanks in advance.
Here below, you will find the code for this class (TcpHelper).
It is used as following :
TcpHelper transport = new TcpHelper;
transport.OnCon nectionFailed += new EventHandler (...);
transport.Callb ackReceivedData += new EventHandler (...);
transport.Open (existingSocket , caller);
or
transport.Open (hostname, port);
transport.Start Reading ();
the code :
using System;
using System.Net;
using System.Net.Sock ets;
using System.Threadin g;
namespace IprRouting
{
public class TcpEventData : System.EventArg s
{
private byte [] _header;
private byte [] _data;
public TcpEventData (byte [] header, byte [] data)
{
_header = header;
_data = data;
}
public byte [] Header
{
get { return _header; }
}
public byte [] Data
{
get { return _data; }
}
}
public class TcpHelper
{
private Socket _socket = null;
private bool _mustRun = true;
private string _hostName = string.Empty;
private IPAddress _ipAddress = IPAddress.IPv6N one;
private string _caller = string.Empty;
private const int PollTimeout = 100;
public event EventHandler CallbackReceive dData;
public event EventHandler OnConnectionFai led;
private static string localHostname = string.Empty;
private static IPAddress [] localIpAddresse s = null;
public TcpHelper ()
{
}
#region Properties
public string HostName
{
get { return _hostName; }
}
public IPAddress IPAddress
{
get { return _ipAddress; }
}
public string RemoteEndPoint
{
get
{
if (_socket == null)
return "Not connected";
else
{
if (! _socket.Connect ed)
return "Not connected";
else
return _socket.RemoteE ndPoint.ToStrin g
();
}
}
}
#endregion // Properties
// remove domain part in host name (i.e. in "xxx.yyy.zz z",
// remove ".yyy.zzz"
private string StandardizeHost name (string hostname)
{
int dotIndex = hostname.IndexO f ('.');
if (dotIndex != -1)
{
return hostname.Substr ing (0, dotIndex).ToUpp er ();
}
else
return hostname;
}
public void StartReading ()
{
Thread handleTcp = new Thread (new ThreadStart
(ReadTcp));
if (_caller.Length > 0)
{
if (_hostName.Equa ls ("localhost" ))
handleTcp.Name = "TcpHelper " + _caller;
else
handleTcp.Name = String.Format ("TcpHelper {0}
{1}", _caller, _hostName);
}
else
handleTcp.Name = String.Format ("TcpHelper {0}",
_hostName);
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::St artReading " +
handleTcp.Name) ;
handleTcp.Prior ity = ThreadPriority. Normal;
handleTcp.IsBac kground = true; // thread will be closed
when application exits
handleTcp.Start ();
}
private void CloseIfActive ()
{
if (_socket != null)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Cl oseIfActive
closing existing socket " +
RemoteEndPoint) ;
Close (false);
}
}
public void Open (Socket socket, string caller)
{
IPEndPoint ipEndPoint = (IPEndPoint)
socket.RemoteEn dPoint;
_ipAddress = ipEndPoint.Addr ess;
IPHostEntry hostInfo = TcpHelper.GetHo stByAddress
(_ipAddress);
if (hostInfo != null)
_hostName = StandardizeHost name
(hostInfo.HostN ame);
else
_hostName = _ipAddress.ToSt ring ();
_caller = caller;
CloseIfActive ();
_socket = socket;
}
public short Open (string hostName, int port)
{
short returnCode = 0;
_hostName = hostName;
returnCode = Open (port);
return returnCode;
}
private short Open (int port)
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en open " +
_hostName);
if (_hostName.Leng th <= 0)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Op en invalid
host name " + _hostName);
return 4;
}
CloseIfActive ();
IPHostEntry hostInfo = TcpHelper.GetHo stInfo (_hostName);
if (hostInfo == null)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Op en cannot get
host info " + _hostName);
return 5;
}
else
{
_hostName = StandardizeHost name
(hostInfo.HostN ame);
_ipAddress = hostInfo.Addres sList [0];
}
if (TcpHelper.IsLo calHost (hostInfo.Addre ssList))
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en skip local
host " + _hostName);
return 6;
}
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en opening " +
_hostName +
", IP address " + _ipAddress + " port #" +
port.ToString ());
IPEndPoint endPoint = new IPEndPoint (_ipAddress, port);
_socket = new Socket (AddressFamily. InterNetwork,
SocketType.Stre am, ProtocolType.Tc p);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.SendTimeout, TcpServer.TcpSe ndTimeout);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.ReceiveTimeou t, TcpServer.TcpRe ceiveTimeout);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.KeepAlive, 1);
_socket.Connect (endPoint);
return 0;
}
private static bool IsLocalHost (IPAddress [] ipAddresses)
{
if (localIpAddress es == null)
{
localHostname = Dns.GetHostName ();
localIpAddresse s = Dns.GetHostByNa me
(localHostname) .AddressList;
}
foreach (IPAddress ipaddr in ipAddresses)
{
foreach (IPAddress ipaddrLocal in localIpAddresse s)
{
if (ipaddrLocal.Eq uals (ipaddr))
return true;
}
}
return false;
}
private IPHostEntry GetHostByName (string hostname)
{
IPHostEntry hostInfo = null;
// try
// {
hostInfo = Dns.GetHostByNa me (_hostName);
/* }
catch (Exception ex)
{
Util.TraceError ("Util::GetHost ByName exception
catched " + ex);
}
*/
return hostInfo;
}
private static IPHostEntry GetHostInfo (string host)
{
IPHostEntry hostInfo = null;
try
{
hostInfo = Dns.Resolve (host);
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or
(String.Format ("TcpHelper::Ge tHostInfo
{0} exception catched {1}",
host, ex.ToString ()));
}
return hostInfo;
}
public static IPHostEntry GetHostByAddres s (IPAddress
ipAddress)
{
IPHostEntry hostInfo = null;
try
{
hostInfo = Dns.GetHostByAd dress (ipAddress);
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Ge tHostByAddress exception catched " + ex);
}
return hostInfo;
}
public void ReadTcp ()
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
(String.Format
("TcpHelper::Re adTcp thread started for socket
{0}",
RemoteEndPoint) );
int bytesRead = 0;
_mustRun = true;
bool stopReading = false;
try
{
byte [] header = new byte [IprProtocol.Hea derSize];
while ((_mustRun) && (! stopReading))
{ // read header
if (_socket.Poll (PollTimeout,
SelectMode.Sele ctRead))
{
if (_socket.Availa ble == 0)
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp header no available bytes to read, probably
connection closed by peer");
stopReading = true;
break;
}
if (_socket.Availa ble >=
IprProtocol.Hea derSize)
{
bytesRead = _socket.Receive
(header, IprProtocol.Hea derSize, 0);
if (Log.Current.Is InfoEnabled)
{
Log.Current.Inf o
("TcpHelper::Re adTcp header " +
bytesRead.ToStr ing () +
" bytes received");
Log.Current.Inf o
(String.Format ("header 0
= {0} 1 = {1}",
header [0].ToString
("X2"), header [1].ToString ("X2")));
}
if (bytesRead > 0)
{ // read command
if (bytesRead !=
IprProtocol.Hea derSize)
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Re adTcp: invalid header, " + bytesRead + " bytes
received");
stopReading = true;
break ;
}
uint commandSize = header [1];
if (commandSize <= 0)
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Re adTcp invalid header, commandSize = " + commandSize);
stopReading = true;
break;
}
else
{
//
byte [] command = new byte [commandSize + 1];
//
command [0] = header [0]; // keep SES command
in command buffer
byte [] command = new
byte [commandSize];
bytesRead = 0;
while ((_mustRun) && (!
stopReading))
{
if (_socket.Poll
(PollTimeout, SelectMode.Sele ctRead))
{
if
(_socket.Availa ble == 0)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command no available bytes to
read, probably connection closed by peer");
stopReading = true;
break;
}
while
((_mustRun) && (_socket.Availa ble >= 0) && (bytesRead < commandSize))
{
//
bytesRead =
_socket.Receive (command, 1, commandSize, 0);
bytesRead
+= _socket.Receive
(command, bytesRead,
(int) (commandSize - bytesRead),
0);
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command " +
bytesRead.ToStr ing () + " bytes received");
if
(bytesRead == 0)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command no available bytes to
read, probably connection closed by peer");
stopReading = true;
break;
}
if
(bytesRead < commandSize)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp: not enough bytes available, " +
bytesRead +
" bytes received, " + commandSize + " bytes expected");
}
}
if (bytesRead
== commandSize)
{
if
(CallbackReceiv edData != null)
{
CallbackReceive dData (this, new TcpEventData (header, command));
}
else
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp no callback registered");
}
break;
}
}
}
}
}
else
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp header no more bytes to read, probably connection
closed by peer");
stopReading = true;
}
}
}
}
}
catch (Exception ex)
{
if (ex is SocketException )
{
/*
if (((SocketExcept ion)
ex).ErrorCode == (int) SocketErrorCode s.InterruptedFu nctionCall)
Util.TraceOther
("TcpHelper::Re adTcp InterruptedFunc tionCall, should be a graceful
shutdown");
else
{
*/
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp
error code = " +
((SocketExcepti on) ex).ErrorCode);
// }
}
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp
Exception catched " + ex);
}
if (_mustRun) // not graceful shutdown (not called by
Close () )
{
CloseConnection ();
TcpInfoEventArg s tcpInfo =
new TcpInfoEventArg s (_socket);
if (OnConnectionFa iled != null)
OnConnectionFai led (this, tcpInfo);
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp no
callback defined");
}
else
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp graceful
shutdown");
_mustRun = true; // reset flag for new running
}
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp handling
finished host " + _hostName);
}
private void CloseConnection ()
{
if (Log.Current.Is InfoEnabled)
{
if (_hostName.Leng th > 0)
Log.Current.Inf o
(String.Format
("TcpHelper::Cl oseConnection closing
socket {0} on host {1}",
RemoteEndPoint, _hostName));
else
Log.Current.Inf o
(String.Format
("TcpHelper::Cl oseConnection closing
socket {0}",
RemoteEndPoint) );
}
if (_socket != null)
{
if (_socket.Connec ted)
_socket.Shutdow n (SocketShutdown .Both);
_socket.Close ();
_socket = null;
}
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Cl oseConnection
socket is null");
}
public short Close (bool keepConnected)
{
if (Log.Current.Is InfoEnabled)
{
if (_hostName.Leng th > 0)
Log.Current.Inf o ("TcpHelper::Cl ose closing
host " + _hostName);
else
Log.Current.Inf o ("TcpHelper::Cl ose closing
host " + _socket.RemoteE ndPoint);
}
_mustRun = false;
// allow reading thread to terminate
Thread.Sleep (PollTimeout);
// keepConnected: typically happens after OpenCanal is
received,
// the MainCommandHand ler closes but the IprSocket that
has been
// given the Tcp socket is using it => keep it opened
if ((! keepConnected) && (_socket != null))
CloseConnection ();
return 0;
}
public int Send (byte [] data)
{
int bytesSent = 0;
try
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Se nd sending " +
data.Length +
" bytes to client " + RemoteEndPoint) ;
if ((_socket != null) && (_socket.Connec ted))
bytesSent = _socket.Send (data);
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd TCP socket
not connected");
if (bytesSent != data.Length)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd not
all bytes sent, " +
bytesSent + " != " + data.Length);
return -1;
}
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd Exception
catched: " + ex);
return -1;
}
return bytesSent;
}
}
}
I try to implement a reusable socket class to send and receive data.
It seems to work but I have 2 problems :
1) I rely on Socket.Availabl e to detect that the connection is closed (no
more data to expect). Sometimes, Socket.Availabl e returns 0 but the other
end of the connection did not close it !
2) This class will be used by many other classes so I have to use the
minimum system resource. I just found that the first parameter for
Socket.Poll is in microseconds ! I thought it was milliseconds.
How can I improve/correct this class ?
Thanks in advance.
Here below, you will find the code for this class (TcpHelper).
It is used as following :
TcpHelper transport = new TcpHelper;
transport.OnCon nectionFailed += new EventHandler (...);
transport.Callb ackReceivedData += new EventHandler (...);
transport.Open (existingSocket , caller);
or
transport.Open (hostname, port);
transport.Start Reading ();
the code :
using System;
using System.Net;
using System.Net.Sock ets;
using System.Threadin g;
namespace IprRouting
{
public class TcpEventData : System.EventArg s
{
private byte [] _header;
private byte [] _data;
public TcpEventData (byte [] header, byte [] data)
{
_header = header;
_data = data;
}
public byte [] Header
{
get { return _header; }
}
public byte [] Data
{
get { return _data; }
}
}
public class TcpHelper
{
private Socket _socket = null;
private bool _mustRun = true;
private string _hostName = string.Empty;
private IPAddress _ipAddress = IPAddress.IPv6N one;
private string _caller = string.Empty;
private const int PollTimeout = 100;
public event EventHandler CallbackReceive dData;
public event EventHandler OnConnectionFai led;
private static string localHostname = string.Empty;
private static IPAddress [] localIpAddresse s = null;
public TcpHelper ()
{
}
#region Properties
public string HostName
{
get { return _hostName; }
}
public IPAddress IPAddress
{
get { return _ipAddress; }
}
public string RemoteEndPoint
{
get
{
if (_socket == null)
return "Not connected";
else
{
if (! _socket.Connect ed)
return "Not connected";
else
return _socket.RemoteE ndPoint.ToStrin g
();
}
}
}
#endregion // Properties
// remove domain part in host name (i.e. in "xxx.yyy.zz z",
// remove ".yyy.zzz"
private string StandardizeHost name (string hostname)
{
int dotIndex = hostname.IndexO f ('.');
if (dotIndex != -1)
{
return hostname.Substr ing (0, dotIndex).ToUpp er ();
}
else
return hostname;
}
public void StartReading ()
{
Thread handleTcp = new Thread (new ThreadStart
(ReadTcp));
if (_caller.Length > 0)
{
if (_hostName.Equa ls ("localhost" ))
handleTcp.Name = "TcpHelper " + _caller;
else
handleTcp.Name = String.Format ("TcpHelper {0}
{1}", _caller, _hostName);
}
else
handleTcp.Name = String.Format ("TcpHelper {0}",
_hostName);
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::St artReading " +
handleTcp.Name) ;
handleTcp.Prior ity = ThreadPriority. Normal;
handleTcp.IsBac kground = true; // thread will be closed
when application exits
handleTcp.Start ();
}
private void CloseIfActive ()
{
if (_socket != null)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Cl oseIfActive
closing existing socket " +
RemoteEndPoint) ;
Close (false);
}
}
public void Open (Socket socket, string caller)
{
IPEndPoint ipEndPoint = (IPEndPoint)
socket.RemoteEn dPoint;
_ipAddress = ipEndPoint.Addr ess;
IPHostEntry hostInfo = TcpHelper.GetHo stByAddress
(_ipAddress);
if (hostInfo != null)
_hostName = StandardizeHost name
(hostInfo.HostN ame);
else
_hostName = _ipAddress.ToSt ring ();
_caller = caller;
CloseIfActive ();
_socket = socket;
}
public short Open (string hostName, int port)
{
short returnCode = 0;
_hostName = hostName;
returnCode = Open (port);
return returnCode;
}
private short Open (int port)
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en open " +
_hostName);
if (_hostName.Leng th <= 0)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Op en invalid
host name " + _hostName);
return 4;
}
CloseIfActive ();
IPHostEntry hostInfo = TcpHelper.GetHo stInfo (_hostName);
if (hostInfo == null)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Op en cannot get
host info " + _hostName);
return 5;
}
else
{
_hostName = StandardizeHost name
(hostInfo.HostN ame);
_ipAddress = hostInfo.Addres sList [0];
}
if (TcpHelper.IsLo calHost (hostInfo.Addre ssList))
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en skip local
host " + _hostName);
return 6;
}
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Op en opening " +
_hostName +
", IP address " + _ipAddress + " port #" +
port.ToString ());
IPEndPoint endPoint = new IPEndPoint (_ipAddress, port);
_socket = new Socket (AddressFamily. InterNetwork,
SocketType.Stre am, ProtocolType.Tc p);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.SendTimeout, TcpServer.TcpSe ndTimeout);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.ReceiveTimeou t, TcpServer.TcpRe ceiveTimeout);
_socket.SetSock etOption (SocketOptionLe vel.Socket,
SocketOptionNam e.KeepAlive, 1);
_socket.Connect (endPoint);
return 0;
}
private static bool IsLocalHost (IPAddress [] ipAddresses)
{
if (localIpAddress es == null)
{
localHostname = Dns.GetHostName ();
localIpAddresse s = Dns.GetHostByNa me
(localHostname) .AddressList;
}
foreach (IPAddress ipaddr in ipAddresses)
{
foreach (IPAddress ipaddrLocal in localIpAddresse s)
{
if (ipaddrLocal.Eq uals (ipaddr))
return true;
}
}
return false;
}
private IPHostEntry GetHostByName (string hostname)
{
IPHostEntry hostInfo = null;
// try
// {
hostInfo = Dns.GetHostByNa me (_hostName);
/* }
catch (Exception ex)
{
Util.TraceError ("Util::GetHost ByName exception
catched " + ex);
}
*/
return hostInfo;
}
private static IPHostEntry GetHostInfo (string host)
{
IPHostEntry hostInfo = null;
try
{
hostInfo = Dns.Resolve (host);
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or
(String.Format ("TcpHelper::Ge tHostInfo
{0} exception catched {1}",
host, ex.ToString ()));
}
return hostInfo;
}
public static IPHostEntry GetHostByAddres s (IPAddress
ipAddress)
{
IPHostEntry hostInfo = null;
try
{
hostInfo = Dns.GetHostByAd dress (ipAddress);
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Ge tHostByAddress exception catched " + ex);
}
return hostInfo;
}
public void ReadTcp ()
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
(String.Format
("TcpHelper::Re adTcp thread started for socket
{0}",
RemoteEndPoint) );
int bytesRead = 0;
_mustRun = true;
bool stopReading = false;
try
{
byte [] header = new byte [IprProtocol.Hea derSize];
while ((_mustRun) && (! stopReading))
{ // read header
if (_socket.Poll (PollTimeout,
SelectMode.Sele ctRead))
{
if (_socket.Availa ble == 0)
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp header no available bytes to read, probably
connection closed by peer");
stopReading = true;
break;
}
if (_socket.Availa ble >=
IprProtocol.Hea derSize)
{
bytesRead = _socket.Receive
(header, IprProtocol.Hea derSize, 0);
if (Log.Current.Is InfoEnabled)
{
Log.Current.Inf o
("TcpHelper::Re adTcp header " +
bytesRead.ToStr ing () +
" bytes received");
Log.Current.Inf o
(String.Format ("header 0
= {0} 1 = {1}",
header [0].ToString
("X2"), header [1].ToString ("X2")));
}
if (bytesRead > 0)
{ // read command
if (bytesRead !=
IprProtocol.Hea derSize)
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Re adTcp: invalid header, " + bytesRead + " bytes
received");
stopReading = true;
break ;
}
uint commandSize = header [1];
if (commandSize <= 0)
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or
("TcpHelper::Re adTcp invalid header, commandSize = " + commandSize);
stopReading = true;
break;
}
else
{
//
byte [] command = new byte [commandSize + 1];
//
command [0] = header [0]; // keep SES command
in command buffer
byte [] command = new
byte [commandSize];
bytesRead = 0;
while ((_mustRun) && (!
stopReading))
{
if (_socket.Poll
(PollTimeout, SelectMode.Sele ctRead))
{
if
(_socket.Availa ble == 0)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command no available bytes to
read, probably connection closed by peer");
stopReading = true;
break;
}
while
((_mustRun) && (_socket.Availa ble >= 0) && (bytesRead < commandSize))
{
//
bytesRead =
_socket.Receive (command, 1, commandSize, 0);
bytesRead
+= _socket.Receive
(command, bytesRead,
(int) (commandSize - bytesRead),
0);
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command " +
bytesRead.ToStr ing () + " bytes received");
if
(bytesRead == 0)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp command no available bytes to
read, probably connection closed by peer");
stopReading = true;
break;
}
if
(bytesRead < commandSize)
{
if
(Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp: not enough bytes available, " +
bytesRead +
" bytes received, " + commandSize + " bytes expected");
}
}
if (bytesRead
== commandSize)
{
if
(CallbackReceiv edData != null)
{
CallbackReceive dData (this, new TcpEventData (header, command));
}
else
{
if
(Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp no callback registered");
}
break;
}
}
}
}
}
else
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o
("TcpHelper::Re adTcp header no more bytes to read, probably connection
closed by peer");
stopReading = true;
}
}
}
}
}
catch (Exception ex)
{
if (ex is SocketException )
{
/*
if (((SocketExcept ion)
ex).ErrorCode == (int) SocketErrorCode s.InterruptedFu nctionCall)
Util.TraceOther
("TcpHelper::Re adTcp InterruptedFunc tionCall, should be a graceful
shutdown");
else
{
*/
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp
error code = " +
((SocketExcepti on) ex).ErrorCode);
// }
}
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp
Exception catched " + ex);
}
if (_mustRun) // not graceful shutdown (not called by
Close () )
{
CloseConnection ();
TcpInfoEventArg s tcpInfo =
new TcpInfoEventArg s (_socket);
if (OnConnectionFa iled != null)
OnConnectionFai led (this, tcpInfo);
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Re adTcp no
callback defined");
}
else
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp graceful
shutdown");
_mustRun = true; // reset flag for new running
}
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Re adTcp handling
finished host " + _hostName);
}
private void CloseConnection ()
{
if (Log.Current.Is InfoEnabled)
{
if (_hostName.Leng th > 0)
Log.Current.Inf o
(String.Format
("TcpHelper::Cl oseConnection closing
socket {0} on host {1}",
RemoteEndPoint, _hostName));
else
Log.Current.Inf o
(String.Format
("TcpHelper::Cl oseConnection closing
socket {0}",
RemoteEndPoint) );
}
if (_socket != null)
{
if (_socket.Connec ted)
_socket.Shutdow n (SocketShutdown .Both);
_socket.Close ();
_socket = null;
}
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Cl oseConnection
socket is null");
}
public short Close (bool keepConnected)
{
if (Log.Current.Is InfoEnabled)
{
if (_hostName.Leng th > 0)
Log.Current.Inf o ("TcpHelper::Cl ose closing
host " + _hostName);
else
Log.Current.Inf o ("TcpHelper::Cl ose closing
host " + _socket.RemoteE ndPoint);
}
_mustRun = false;
// allow reading thread to terminate
Thread.Sleep (PollTimeout);
// keepConnected: typically happens after OpenCanal is
received,
// the MainCommandHand ler closes but the IprSocket that
has been
// given the Tcp socket is using it => keep it opened
if ((! keepConnected) && (_socket != null))
CloseConnection ();
return 0;
}
public int Send (byte [] data)
{
int bytesSent = 0;
try
{
if (Log.Current.Is InfoEnabled)
Log.Current.Inf o ("TcpHelper::Se nd sending " +
data.Length +
" bytes to client " + RemoteEndPoint) ;
if ((_socket != null) && (_socket.Connec ted))
bytesSent = _socket.Send (data);
else
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd TCP socket
not connected");
if (bytesSent != data.Length)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd not
all bytes sent, " +
bytesSent + " != " + data.Length);
return -1;
}
}
catch (Exception ex)
{
if (Log.Current.Is ErrorEnabled)
Log.Current.Err or ("TcpHelper::Se nd Exception
catched: " + ex);
return -1;
}
return bytesSent;
}
}
}
Comment