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
)
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);
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
));
340 /// This is the last known address, re-throw the exception
341 if(i
== host
.AddressList
.Length
-1)
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
);