1 // System.Net.Sockets.TcpClient.cs
4 // Phillip Pearson (pp@myelin.co.nz)
6 // Copyright (C) 2001, Phillip Pearson
7 // http://www.myelin.co.nz
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // NB: This is untested (probably buggy) code - take care if using it
36 namespace System.Net.Sockets
39 /// A slightly more abstracted way to create an
40 /// outgoing network connections than a Socket.
42 public class TcpClient : IDisposable
46 private NetworkStream stream;
48 private Socket client;
49 private bool disposed = false;
54 /// Some code that is shared between the constructors.
56 private void Init (AddressFamily family)
60 if(client != null) {
\r
65 client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
69 /// Constructs a new TcpClient with no connection set up
73 Init(AddressFamily.InterNetwork);
74 client.Bind(new IPEndPoint(IPAddress.Any, 0));
78 public TcpClient (AddressFamily family)
80 if (family != AddressFamily.InterNetwork &&
81 family != AddressFamily.InterNetworkV6) {
82 throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
86 client.Bind (new IPEndPoint (IPAddress.Any, 0));
91 /// Constructs a new TcpClient with a specified local endpoint.
92 /// Use this if you want to have your connections originating
93 /// from a certain port, or a certain IP (on a multi homed
96 /// <param name="local_end_point">The aforementioned local endpoint</param>
97 public TcpClient (IPEndPoint local_end_point)
99 Init(local_end_point.AddressFamily);
100 client.Bind(local_end_point);
104 /// Constructs a new TcpClient and connects to a specified
105 /// host on a specified port. A quick way to set up a network
108 /// <param name="hostname">The host to connect to, e.g.
109 /// 192.168.0.201 or www.myelin.co.nz</param>
110 /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
111 public TcpClient (string hostname, int port)
113 Connect(hostname, port);
117 /// A flag that is 'true' if the TcpClient has an active connection
119 protected bool Active
121 get { return active; }
122 set { active = value; }
126 /// The socket that all network comms passes through
128 protected Socket Client
130 get { return client; }
138 /// Internal function to allow TcpListener.AcceptTcpClient
139 /// to work (it needs to be able to set protected property
142 /// <param name="s"></param>
143 internal void SetTcpClient (Socket s)
149 /// If set, the socket will remain open after it has been
150 /// instructed to close, in order to send data that remains
153 public LingerOption LingerState
156 return (LingerOption)client.GetSocketOption(
157 SocketOptionLevel.Socket,
158 SocketOptionName.Linger);
161 client.SetSocketOption(
162 SocketOptionLevel.Socket,
163 SocketOptionName.Linger, value);
168 /// <p>If set, outbound data will be sent at once rather than collected
169 /// until enough is available to fill a packet.</p>
171 /// <p>This is the TCP_NODELAY sockopt from BSD sockets and WinSock.
172 /// For more information, look up the Nagle algorithm.</p>
177 return (bool)client.GetSocketOption(
178 SocketOptionLevel.Tcp,
179 SocketOptionName.NoDelay);
182 client.SetSocketOption(
183 SocketOptionLevel.Tcp,
184 SocketOptionName.NoDelay, value ? 1 : 0);
189 /// How big the receive buffer is (from the connection socket)
191 public int ReceiveBufferSize
194 return (int)client.GetSocketOption(
195 SocketOptionLevel.Socket,
196 SocketOptionName.ReceiveBuffer);
199 client.SetSocketOption(
200 SocketOptionLevel.Socket,
201 SocketOptionName.ReceiveBuffer, value);
206 /// How long before the socket will time out on a
209 public int ReceiveTimeout
212 return (int)client.GetSocketOption(
213 SocketOptionLevel.Socket,
214 SocketOptionName.ReceiveTimeout);
217 client.SetSocketOption(
218 SocketOptionLevel.Socket,
219 SocketOptionName.ReceiveTimeout, value);
224 /// How big the send buffer is (from the connection socket)
226 public int SendBufferSize
229 return (int)client.GetSocketOption(
230 SocketOptionLevel.Socket,
231 SocketOptionName.SendBuffer);
234 client.SetSocketOption(
235 SocketOptionLevel.Socket,
236 SocketOptionName.SendBuffer, value);
241 /// How long before the socket will time out on a
244 public int SendTimeout
247 return (int)client.GetSocketOption(
248 SocketOptionLevel.Socket,
249 SocketOptionName.SendTimeout);
252 client.SetSocketOption(
253 SocketOptionLevel.Socket,
254 SocketOptionName.SendTimeout, value);
262 /// Closes the socket and disposes of all managed resources.
264 /// Throws SocketException if something goes wrong while
265 /// closing the socket.
269 ((IDisposable) this).Dispose ();
273 /// Connects to a specified remote endpoint
275 /// Throws SocketException if something goes wrong while
278 /// <param name="remote_end_point">The aforementioned endpoint</param>
279 public void Connect (IPEndPoint remote_end_point)
282 client.Connect(remote_end_point);
283 stream = new NetworkStream(client, true);
291 /// Connects to an IP address on a port
293 /// Throws SocketException if something goes wrong while
296 /// <param name="address">The IP address (get it from Dns.GetHostByName)</param>
297 /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
298 public void Connect (IPAddress address, int port)
300 Connect(new IPEndPoint(address, port));
304 /// Resolves a fully qualified domain name to an IP address
305 /// and connects to it on a specified port
307 /// Throws SocketException if something goes wrong while
310 /// <param name="hostname">The hostname, e.g. www.myelin.co.nz</param>
311 /// <param name="port">The port, e.g. 80 for HTTP</param>
313 public void Connect (string hostname, int port)
317 IPHostEntry host = Dns.GetHostByName(hostname);
319 for(int i=0; i<host.AddressList.Length; i++)
322 Init(host.AddressList[i].AddressFamily);
324 if(host.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
325 client.Bind(new IPEndPoint(IPAddress.Any, 0));
327 else if(host.AddressList[i].AddressFamily == AddressFamily.InterNetworkV6)
328 client.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
331 Connect(new IPEndPoint(host.AddressList[i], port));
334 catch(Exception e) {
\r
335 if(client != null) {
\r
340 /// This is the last known address, re-throw the exception
\r
341 if(i == host.AddressList.Length-1)
\r
348 /// Gets rid of all managed resources
350 void IDisposable.Dispose ()
353 GC.SuppressFinalize (this);
357 /// Gets rid of all unmanaged resources
359 /// <param name="disposing">If this is true, it gets rid of all
360 /// managed resources as well</param>
361 protected virtual void Dispose (bool disposing)
368 // release managed resources
369 NetworkStream s = stream;
372 // This closes the socket as well, as the NetworkStream
377 } else if (client != null){
385 /// Destructor - just calls Dispose()
392 /// <returns>A NetworkStream object connected to the
393 /// connection socket</returns>
394 public NetworkStream GetStream()
399 stream = new NetworkStream (client, true);
403 finally { CheckDisposed (); }
406 private void CheckDisposed ()
409 throw new ObjectDisposedException (GetType().FullName);