Re: problem with Socket.Available
- From: Droopy <droopytoonnospam@xxxxxxxxxxx>
- Date: 24 Aug 2005 15:33:45 GMT
OK no help here ;-(
I removed all calls to "Available".
I wonder now if I should call "Poll" ?
I mean for better performance.
I used both "Available" and "Poll" to prevent blocking calls to
"Receive" but as I am using separate threads ...
What is best ?
Thanks in advance for your help
Droopy <droopytoonnospam@xxxxxxxxxxx> wrote in
news:Xns96BBA9F069261droopytoonnospamhotm@xxxxxxxxxxxxxx:
> 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.Available to detect that the connection is closed
> (no more data to expect). Sometimes, Socket.Available 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.OnConnectionFailed += new EventHandler (...);
> transport.CallbackReceivedData += new EventHandler (...);
>
> transport.Open (existingSocket, caller);
> or
> transport.Open (hostname, port);
>
> transport.StartReading ();
>
>
> the code :
>
>
> using System;
> using System.Net;
> using System.Net.Sockets;
> using System.Threading;
>
> namespace IprRouting
> {
> public class TcpEventData : System.EventArgs
> {
> 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.IPv6None;
> private string _caller = string.Empty;
>
> private const int PollTimeout = 100;
>
> public event EventHandler CallbackReceivedData;
> public event EventHandler OnConnectionFailed;
>
> private static string localHostname = string.Empty;
> private static IPAddress [] localIpAddresses = 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.Connected)
> return "Not connected";
> else
> return _socket.RemoteEndPoint.ToString
> ();
> }
> }
> }
>
> #endregion // Properties
>
> // remove domain part in host name (i.e. in "xxx.yyy.zzz",
> // remove ".yyy.zzz"
> private string StandardizeHostname (string hostname)
> {
> int dotIndex = hostname.IndexOf ('.');
>
> if (dotIndex != -1)
> {
> return hostname.Substring (0, dotIndex).ToUpper
> ();
> }
> else
> return hostname;
> }
>
> public void StartReading ()
> {
> Thread handleTcp = new Thread (new ThreadStart
> (ReadTcp));
>
> if (_caller.Length > 0)
> {
> if (_hostName.Equals ("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.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::StartReading " +
> handleTcp.Name);
>
> handleTcp.Priority = ThreadPriority.Normal;
> handleTcp.IsBackground = true; // thread will be
> closed
> when application exits
> handleTcp.Start ();
> }
>
> private void CloseIfActive ()
> {
> if (_socket != null)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::CloseIfActive
> closing existing socket " +
> RemoteEndPoint);
> Close (false);
> }
> }
>
> public void Open (Socket socket, string caller)
> {
> IPEndPoint ipEndPoint = (IPEndPoint)
> socket.RemoteEndPoint;
> _ipAddress = ipEndPoint.Address;
>
> IPHostEntry hostInfo = TcpHelper.GetHostByAddress
> (_ipAddress);
> if (hostInfo != null)
> _hostName = StandardizeHostname
> (hostInfo.HostName);
> else
> _hostName = _ipAddress.ToString ();
>
> _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.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::Open open " +
> _hostName);
>
> if (_hostName.Length <= 0)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::Open invalid
> host name " + _hostName);
> return 4;
> }
>
> CloseIfActive ();
>
> IPHostEntry hostInfo = TcpHelper.GetHostInfo
> (_hostName);
>
> if (hostInfo == null)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::Open cannot
> get
> host info " + _hostName);
> return 5;
> }
> else
> {
> _hostName = StandardizeHostname
> (hostInfo.HostName);
> _ipAddress = hostInfo.AddressList [0];
> }
>
> if (TcpHelper.IsLocalHost (hostInfo.AddressList))
> {
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::Open skip local
> host " + _hostName);
> return 6;
> }
>
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::Open opening " +
> _hostName +
> ", IP address " + _ipAddress + " port #" +
> port.ToString ());
>
> IPEndPoint endPoint = new IPEndPoint (_ipAddress,
> port); _socket = new Socket
> (AddressFamily.InterNetwork,
> SocketType.Stream, ProtocolType.Tcp);
> _socket.SetSocketOption (SocketOptionLevel.Socket,
> SocketOptionName.SendTimeout, TcpServer.TcpSendTimeout);
> _socket.SetSocketOption (SocketOptionLevel.Socket,
> SocketOptionName.ReceiveTimeout, TcpServer.TcpReceiveTimeout);
> _socket.SetSocketOption (SocketOptionLevel.Socket,
> SocketOptionName.KeepAlive, 1);
> _socket.Connect (endPoint);
>
> return 0;
> }
>
> private static bool IsLocalHost (IPAddress [] ipAddresses)
> {
> if (localIpAddresses == null)
> {
> localHostname = Dns.GetHostName ();
> localIpAddresses = Dns.GetHostByName
> (localHostname).AddressList;
> }
>
> foreach (IPAddress ipaddr in ipAddresses)
> {
> foreach (IPAddress ipaddrLocal in
> localIpAddresses) {
> if (ipaddrLocal.Equals (ipaddr))
> return true;
> }
> }
>
> return false;
> }
>
>
> private IPHostEntry GetHostByName (string hostname)
> {
> IPHostEntry hostInfo = null;
>
> // try
> // {
> hostInfo = Dns.GetHostByName (_hostName);
> /* }
> catch (Exception ex)
> {
> Util.TraceError ("Util::GetHostByName 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.IsErrorEnabled)
> Log.Current.Error
> (String.Format ("TcpHelper::GetHostInfo
> {0} exception catched {1}",
> host, ex.ToString ()));
> }
>
> return hostInfo;
> }
>
> public static IPHostEntry GetHostByAddress (IPAddress
> ipAddress)
> {
> IPHostEntry hostInfo = null;
>
> try
> {
> hostInfo = Dns.GetHostByAddress (ipAddress);
> }
> catch (Exception ex)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error
> ("TcpHelper::GetHostByAddress exception catched " + ex);
> }
>
> return hostInfo;
> }
>
> public void ReadTcp ()
> {
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info
> (String.Format
> ("TcpHelper::ReadTcp thread started for socket
> {0}",
> RemoteEndPoint));
>
> int bytesRead = 0;
> _mustRun = true;
> bool stopReading = false;
>
> try
> {
> byte [] header = new byte
> [IprProtocol.HeaderSize];
>
> while ((_mustRun) && (! stopReading))
> { // read header
> if (_socket.Poll (PollTimeout,
> SelectMode.SelectRead))
> {
> if (_socket.Available == 0)
> {
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info
> ("TcpHelper::ReadTcp header no available bytes to read, probably
> connection closed by peer");
> stopReading = true;
> break;
> }
>
> if (_socket.Available >=
> IprProtocol.HeaderSize)
> {
> bytesRead = _socket.Receive
> (header, IprProtocol.HeaderSize, 0);
>
> if (Log.Current.IsInfoEnabled)
> {
> Log.Current.Info
> ("TcpHelper::ReadTcp header " +
> bytesRead.ToString () +
> " bytes received");
> Log.Current.Info
> (String.Format ("header 0
> = {0} 1 = {1}",
> header [0].ToString
> ("X2"), header [1].ToString ("X2")));
> }
>
> if (bytesRead > 0)
> { // read command
>
> if (bytesRead !=
> IprProtocol.HeaderSize)
> {
> if
> (Log.Current.IsErrorEnabled)
> Log.Current.Error
>
> ("TcpHelper::ReadTcp: invalid header, " + bytesRead + " bytes
> received");
> stopReading = true;
> break ;
> }
>
> uint commandSize = header [1];
>
> if (commandSize <= 0)
> {
> if
> (Log.Current.IsErrorEnabled)
> Log.Current.Error
> ("TcpHelper::ReadTcp 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.SelectRead))
> {
> if
> (_socket.Available == 0)
> {
> if
> (Log.Current.IsInfoEnabled)
>
> Log.Current.Info ("TcpHelper::ReadTcp command no available bytes
> to
> read, probably connection closed by peer");
>
> stopReading = true;
> break;
> }
>
> while
> ((_mustRun) && (_socket.Available >= 0) && (bytesRead < commandSize))
> {
> //
> bytesRead =
> _socket.Receive (command, 1, commandSize, 0);
> bytesRead
> += _socket.Receive
>
> (command, bytesRead,
>
> (int) (commandSize - bytesRead),
> 0);
>
> if
> (Log.Current.IsInfoEnabled)
>
> Log.Current.Info ("TcpHelper::ReadTcp command " +
>
> bytesRead.ToString () + " bytes received");
>
> if
> (bytesRead == 0)
> {
> if
> (Log.Current.IsInfoEnabled)
>
> Log.Current.Info ("TcpHelper::ReadTcp command no available bytes
> to
> read, probably connection closed by peer");
>
> stopReading = true;
>
> break;
> }
>
> if
> (bytesRead < commandSize)
> {
> if
> (Log.Current.IsInfoEnabled)
>
> Log.Current.Info
>
> ("TcpHelper::ReadTcp: not enough bytes available, " +
> bytesRead +
>
> " bytes received, " + commandSize + " bytes expected");
> }
> }
>
> if (bytesRead
> == commandSize)
> {
> if
> (CallbackReceivedData != null)
> {
>
> CallbackReceivedData (this, new TcpEventData (header, command));
> }
> else
> {
> if
> (Log.Current.IsErrorEnabled)
>
> Log.Current.Error ("TcpHelper::ReadTcp no callback registered");
> }
>
> break;
> }
> }
> }
> }
> }
> else
> {
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info
> ("TcpHelper::ReadTcp header no more bytes to read, probably connection
> closed by peer");
> stopReading = true;
> }
> }
> }
> }
> }
> catch (Exception ex)
> {
> if (ex is SocketException)
> {
> /*
> if (((SocketException)
> ex).ErrorCode == (int) SocketErrorCodes.InterruptedFunctionCall)
> Util.TraceOther
> ("TcpHelper::ReadTcp InterruptedFunctionCall, should be a graceful
> shutdown");
> else
> {
> */
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::ReadTcp
> error code = " +
> ((SocketException) ex).ErrorCode);
> // }
> }
> else
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::ReadTcp
> Exception catched " + ex);
> }
>
> if (_mustRun) // not graceful shutdown (not called
> by
> Close () )
> {
> CloseConnection ();
>
> TcpInfoEventArgs tcpInfo =
> new TcpInfoEventArgs (_socket);
>
> if (OnConnectionFailed != null)
> OnConnectionFailed (this, tcpInfo);
> else
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::ReadTcp no
> callback defined");
> }
> else
> {
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::ReadTcp
> graceful
> shutdown");
> _mustRun = true; // reset flag for new running
> }
>
> if (Log.Current.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::ReadTcp handling
> finished host " + _hostName);
> }
>
> private void CloseConnection ()
> {
> if (Log.Current.IsInfoEnabled)
> {
> if (_hostName.Length > 0)
> Log.Current.Info
> (String.Format
> ("TcpHelper::CloseConnection closing
> socket {0} on host {1}",
> RemoteEndPoint, _hostName));
> else
> Log.Current.Info
> (String.Format
> ("TcpHelper::CloseConnection closing
> socket {0}",
> RemoteEndPoint));
> }
>
> if (_socket != null)
> {
> if (_socket.Connected)
> _socket.Shutdown (SocketShutdown.Both);
> _socket.Close ();
>
> _socket = null;
> }
> else
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::CloseConnection
> socket is null");
> }
>
> public short Close (bool keepConnected)
> {
> if (Log.Current.IsInfoEnabled)
> {
> if (_hostName.Length > 0)
> Log.Current.Info ("TcpHelper::Close closing
> host " + _hostName);
> else
> Log.Current.Info ("TcpHelper::Close closing
> host " + _socket.RemoteEndPoint);
> }
>
> _mustRun = false;
>
> // allow reading thread to terminate
> Thread.Sleep (PollTimeout);
>
> // keepConnected: typically happens after OpenCanal is
> received,
> // the MainCommandHandler 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.IsInfoEnabled)
> Log.Current.Info ("TcpHelper::Send sending "
> +
> data.Length +
> " bytes to client " + RemoteEndPoint);
>
> if ((_socket != null) && (_socket.Connected))
> bytesSent = _socket.Send (data);
> else
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::Send TCP
> socket
> not connected");
>
> if (bytesSent != data.Length)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::Send not
> all bytes sent, " +
> bytesSent + " != " + data.Length);
> return -1;
> }
> }
> catch (Exception ex)
> {
> if (Log.Current.IsErrorEnabled)
> Log.Current.Error ("TcpHelper::Send Exception
> catched: " + ex);
> return -1;
> }
>
> return bytesSent;
> }
> }
> }
>
.
- Follow-Ups:
- Re: problem with Socket.Available
- From: Droopy
- Re: problem with Socket.Available
- References:
- problem with Socket.Available
- From: Droopy
- problem with Socket.Available
- Prev by Date: [AutoComplete] and nested function calls
- Next by Date: Bug with multiselect ListBox?
- Previous by thread: problem with Socket.Available
- Next by thread: Re: problem with Socket.Available
- Index(es):
Relevant Pages
|