Re: problem with Socket.Available



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

.



Relevant Pages

  • Re: Sockets debugging tools
    ... > to peer for a long time. ... I'll just stick to looking out for ETIMEDOUT from the socket I/O ... > during write it'll get SIGPIPE because the pipe is closed by OS already. ... EPIPE is send's analogue to recv returning 0, or rather, I found out ...
    (comp.unix.programmer)
  • Re: Recv and fwding in multi-threaded sockets programming
    ... I am new to socket programming in Java and I have a newbie question. ... > would forward it to the other 4 connections. ... listen for incoming message from peer and forward it to other thread. ... A sender that recieves messages from the queue and sends them ...
    (comp.lang.java.programmer)
  • Re: Another socket programming question
    ... When you close one side peer, the second side can fill that only if it do ... closing of peer socket, but accepted one only if it will do mentioned op. ... One for listening that can be started and stopped and one for sending data ... BeginReceiveCallback loop listening for data, ...
    (microsoft.public.win32.programmer.networks)
  • Re: close and O_NONBLOCK on TCP/IP socket in Linux
    ... >> reading what i am interested in from the peer. ... If they don't read, but only write, then they won't see FIN, and ... >> to report the FD as writable after nonblocking shutdown of write?. ... OP the socket is closed after he got what he wanted. ...
    (comp.unix.programmer)
  • Re: CANNOT receive UDP data in SERVICE program
    ... UDP" is really a powerful command I didn't know before. ... Broadcast online request which brings local command socket port ... Call setsockopt to set a 5000ms TIMEOUT option on #SOCK1; ... In fact I can see the command data in Sniffer, ...
    (microsoft.public.win32.programmer.networks)