// System.Net.Sockets.TcpClient.cs // // Author: // Phillip Pearson (pp@myelin.co.nz) // // Copyright (C) 2001, Phillip Pearson // http://www.myelin.co.nz // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // NB: This is untested (probably buggy) code - take care if using it using System; using System.Net; namespace System.Net.Sockets { /// /// A slightly more abstracted way to create an /// outgoing network connections than a Socket. /// public class TcpClient : IDisposable { // private data private NetworkStream stream; private bool active; private Socket client; private bool disposed = false; // constructor /// /// Some code that is shared between the constructors. /// private void Init (AddressFamily family) { active = false; if(client != null) { client.Close(); client = null; } client = new Socket(family, SocketType.Stream, ProtocolType.Tcp); } /// /// Constructs a new TcpClient with no connection set up /// public TcpClient () { Init(AddressFamily.InterNetwork); client.Bind(new IPEndPoint(IPAddress.Any, 0)); } #if NET_1_1 public TcpClient (AddressFamily family) { if (family != AddressFamily.InterNetwork && family != AddressFamily.InterNetworkV6) { throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family"); } Init (family); client.Bind (new IPEndPoint (IPAddress.Any, 0)); } #endif /// /// Constructs a new TcpClient with a specified local endpoint. /// Use this if you want to have your connections originating /// from a certain port, or a certain IP (on a multi homed /// system). /// /// The aforementioned local endpoint public TcpClient (IPEndPoint local_end_point) { Init(local_end_point.AddressFamily); client.Bind(local_end_point); } /// /// Constructs a new TcpClient and connects to a specified /// host on a specified port. A quick way to set up a network /// connection. /// /// The host to connect to, e.g. /// 192.168.0.201 or www.myelin.co.nz /// The port to connect to, e.g. 80 for HTTP public TcpClient (string hostname, int port) { Connect(hostname, port); } /// /// A flag that is 'true' if the TcpClient has an active connection /// protected bool Active { get { return active; } set { active = value; } } /// /// The socket that all network comms passes through /// protected Socket Client { get { return client; } set { client = value; stream = null; } } /// /// Internal function to allow TcpListener.AcceptTcpClient /// to work (it needs to be able to set protected property /// 'Client') /// /// internal void SetTcpClient (Socket s) { Client = s; } /// /// If set, the socket will remain open after it has been /// instructed to close, in order to send data that remains /// in the buffer. /// public LingerOption LingerState { get { return (LingerOption)client.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.Linger); } set { client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.Linger, value); } } /// ///

If set, outbound data will be sent at once rather than collected /// until enough is available to fill a packet.

/// ///

This is the TCP_NODELAY sockopt from BSD sockets and WinSock. /// For more information, look up the Nagle algorithm.

///
public bool NoDelay { get { return (bool)client.GetSocketOption( SocketOptionLevel.Tcp, SocketOptionName.NoDelay); } set { client.SetSocketOption( SocketOptionLevel.Tcp, SocketOptionName.NoDelay, value); } } /// /// How big the receive buffer is (from the connection socket) /// public int ReceiveBufferSize { get { return (int)client.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer); } set { client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value); } } /// /// How long before the socket will time out on a /// Receive() call /// public int ReceiveTimeout { get { return (int)client.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout); } set { client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value); } } /// /// How big the send buffer is (from the connection socket) /// public int SendBufferSize { get { return (int)client.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.SendBuffer); } set { client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value); } } /// /// How long before the socket will time out on a /// Send() call /// public int SendTimeout { get { return (int)client.GetSocketOption( SocketOptionLevel.Socket, SocketOptionName.SendTimeout); } set { client.SetSocketOption( SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value); } } // methods /// /// Closes the socket and disposes of all managed resources. /// /// Throws SocketException if something goes wrong while /// closing the socket. /// public void Close () { ((IDisposable) this).Dispose (); } /// /// Connects to a specified remote endpoint /// /// Throws SocketException if something goes wrong while /// connecting. /// /// The aforementioned endpoint public void Connect (IPEndPoint remote_end_point) { try { client.Connect(remote_end_point); stream = new NetworkStream(client, true); active = true; } finally { CheckDisposed (); } } /// /// Connects to an IP address on a port /// /// Throws SocketException if something goes wrong while /// connecting. /// /// The IP address (get it from Dns.GetHostByName) /// The port to connect to, e.g. 80 for HTTP public void Connect (IPAddress address, int port) { Connect(new IPEndPoint(address, port)); } /// /// Resolves a fully qualified domain name to an IP address /// and connects to it on a specified port /// /// Throws SocketException if something goes wrong while /// connecting. /// /// The hostname, e.g. www.myelin.co.nz /// The port, e.g. 80 for HTTP [MonoTODO] public void Connect (string hostname, int port) { CheckDisposed (); IPHostEntry host = Dns.GetHostByName(hostname); for(int i=0; i /// Gets rid of all managed resources /// void IDisposable.Dispose () { Dispose (true); GC.SuppressFinalize (this); } /// /// Gets rid of all unmanaged resources /// /// If this is true, it gets rid of all /// managed resources as well protected virtual void Dispose (bool disposing) { if (disposed) return; disposed = true; if (disposing){ // release managed resources NetworkStream s = stream; stream = null; if (s != null) { // This closes the socket as well, as the NetworkStream // owns the socket. s.Close(); active = false; s = null; } else if (client != null){ client.Close (); } client = null; } } /// /// Destructor - just calls Dispose() /// ~TcpClient () { Dispose (false); } /// A NetworkStream object connected to the /// connection socket public NetworkStream GetStream() { try { if (stream == null) { stream = new NetworkStream (client, true); } return stream; } finally { CheckDisposed (); } } private void CheckDisposed () { if (disposed) throw new ObjectDisposedException (GetType().FullName); } } }