TcpClient.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. // System.Net.Sockets.TcpClient.cs
  2. //
  3. // Author:
  4. // Phillip Pearson ([email protected])
  5. //
  6. // Copyright (C) 2001, Phillip Pearson
  7. // http://www.myelin.co.nz
  8. //
  9. // NB: This is untested (probably buggy) code - take care if using it
  10. using System;
  11. using System.Net;
  12. namespace System.Net.Sockets
  13. {
  14. /// <remarks>
  15. /// A slightly more abstracted way to create an
  16. /// outgoing network connections than a Socket.
  17. /// </remarks>
  18. public class TcpClient : IDisposable
  19. {
  20. // private data
  21. private NetworkStream stream;
  22. private bool active;
  23. private Socket client;
  24. private bool disposed = false;
  25. // constructor
  26. /// <summary>
  27. /// Some code that is shared between the constructors.
  28. /// </summary>
  29. private void Init (AddressFamily family)
  30. {
  31. active = false;
  32. if(client != null) {
  33. client.Close();
  34. client = null;
  35. }
  36. client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
  37. }
  38. /// <summary>
  39. /// Constructs a new TcpClient with no connection set up
  40. /// </summary>
  41. public TcpClient ()
  42. {
  43. Init(AddressFamily.InterNetwork);
  44. client.Bind(new IPEndPoint(IPAddress.Any, 0));
  45. }
  46. /// <summary>
  47. /// Constructs a new TcpClient with a specified local endpoint.
  48. /// Use this if you want to have your connections originating
  49. /// from a certain port, or a certain IP (on a multi homed
  50. /// system).
  51. /// </summary>
  52. /// <param name="local_end_point">The aforementioned local endpoint</param>
  53. public TcpClient (IPEndPoint local_end_point)
  54. {
  55. Init(local_end_point.AddressFamily);
  56. client.Bind(local_end_point);
  57. }
  58. /// <summary>
  59. /// Constructs a new TcpClient and connects to a specified
  60. /// host on a specified port. A quick way to set up a network
  61. /// connection.
  62. /// </summary>
  63. /// <param name="hostname">The host to connect to, e.g.
  64. /// 192.168.0.201 or www.myelin.co.nz</param>
  65. /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
  66. public TcpClient (string hostname, int port)
  67. {
  68. Connect(hostname, port);
  69. }
  70. /// <summary>
  71. /// A flag that is 'true' if the TcpClient has an active connection
  72. /// </summary>
  73. protected bool Active
  74. {
  75. get { return active; }
  76. set { active = value; }
  77. }
  78. /// <summary>
  79. /// The socket that all network comms passes through
  80. /// </summary>
  81. protected Socket Client
  82. {
  83. get { return client; }
  84. set {
  85. client = value;
  86. stream = null;
  87. }
  88. }
  89. /// <summary>
  90. /// Internal function to allow TcpListener.AcceptTcpClient
  91. /// to work (it needs to be able to set protected property
  92. /// 'Client')
  93. /// </summary>
  94. /// <param name="s"></param>
  95. internal void SetTcpClient (Socket s)
  96. {
  97. Client = s;
  98. }
  99. /// <summary>
  100. /// If set, the socket will remain open after it has been
  101. /// instructed to close, in order to send data that remains
  102. /// in the buffer.
  103. /// </summary>
  104. public LingerOption LingerState
  105. {
  106. get {
  107. return (LingerOption)client.GetSocketOption(
  108. SocketOptionLevel.Socket,
  109. SocketOptionName.Linger);
  110. }
  111. set {
  112. client.SetSocketOption(
  113. SocketOptionLevel.Socket,
  114. SocketOptionName.Linger, value);
  115. }
  116. }
  117. /// <summary>
  118. /// <p>If set, outbound data will be sent at once rather than collected
  119. /// until enough is available to fill a packet.</p>
  120. ///
  121. /// <p>This is the TCP_NODELAY sockopt from BSD sockets and WinSock.
  122. /// For more information, look up the Nagle algorithm.</p>
  123. /// </summary>
  124. public bool NoDelay
  125. {
  126. get {
  127. return (bool)client.GetSocketOption(
  128. SocketOptionLevel.Tcp,
  129. SocketOptionName.NoDelay);
  130. }
  131. set {
  132. client.SetSocketOption(
  133. SocketOptionLevel.Tcp,
  134. SocketOptionName.NoDelay, value);
  135. }
  136. }
  137. /// <summary>
  138. /// How big the receive buffer is (from the connection socket)
  139. /// </summary>
  140. public int ReceiveBufferSize
  141. {
  142. get {
  143. return (int)client.GetSocketOption(
  144. SocketOptionLevel.Socket,
  145. SocketOptionName.ReceiveBuffer);
  146. }
  147. set {
  148. client.SetSocketOption(
  149. SocketOptionLevel.Socket,
  150. SocketOptionName.ReceiveBuffer, value);
  151. }
  152. }
  153. /// <summary>
  154. /// How long before the socket will time out on a
  155. /// Receive() call
  156. /// </summary>
  157. public int ReceiveTimeout
  158. {
  159. get {
  160. return (int)client.GetSocketOption(
  161. SocketOptionLevel.Socket,
  162. SocketOptionName.ReceiveTimeout);
  163. }
  164. set {
  165. client.SetSocketOption(
  166. SocketOptionLevel.Socket,
  167. SocketOptionName.ReceiveTimeout, value);
  168. }
  169. }
  170. /// <summary>
  171. /// How big the send buffer is (from the connection socket)
  172. /// </summary>
  173. public int SendBufferSize
  174. {
  175. get {
  176. return (int)client.GetSocketOption(
  177. SocketOptionLevel.Socket,
  178. SocketOptionName.SendBuffer);
  179. }
  180. set {
  181. client.SetSocketOption(
  182. SocketOptionLevel.Socket,
  183. SocketOptionName.SendBuffer, value);
  184. }
  185. }
  186. /// <summary>
  187. /// How long before the socket will time out on a
  188. /// Send() call
  189. /// </summary>
  190. public int SendTimeout
  191. {
  192. get {
  193. return (int)client.GetSocketOption(
  194. SocketOptionLevel.Socket,
  195. SocketOptionName.SendTimeout);
  196. }
  197. set {
  198. client.SetSocketOption(
  199. SocketOptionLevel.Socket,
  200. SocketOptionName.SendTimeout, value);
  201. }
  202. }
  203. // methods
  204. /// <summary>
  205. /// Closes the socket and disposes of all managed resources.
  206. ///
  207. /// Throws SocketException if something goes wrong while
  208. /// closing the socket.
  209. /// </summary>
  210. public void Close ()
  211. {
  212. ((IDisposable) this).Dispose ();
  213. }
  214. /// <summary>
  215. /// Connects to a specified remote endpoint
  216. ///
  217. /// Throws SocketException if something goes wrong while
  218. /// connecting.
  219. /// </summary>
  220. /// <param name="remote_end_point">The aforementioned endpoint</param>
  221. public void Connect (IPEndPoint remote_end_point)
  222. {
  223. try {
  224. client.Connect(remote_end_point);
  225. stream = new NetworkStream(client, true);
  226. active = true;
  227. } finally {
  228. CheckDisposed ();
  229. }
  230. }
  231. /// <summary>
  232. /// Connects to an IP address on a port
  233. ///
  234. /// Throws SocketException if something goes wrong while
  235. /// connecting.
  236. /// </summary>
  237. /// <param name="address">The IP address (get it from Dns.GetHostByName)</param>
  238. /// <param name="port">The port to connect to, e.g. 80 for HTTP</param>
  239. public void Connect (IPAddress address, int port)
  240. {
  241. Connect(new IPEndPoint(address, port));
  242. }
  243. /// <summary>
  244. /// Resolves a fully qualified domain name to an IP address
  245. /// and connects to it on a specified port
  246. ///
  247. /// Throws SocketException if something goes wrong while
  248. /// connecting.
  249. /// </summary>
  250. /// <param name="hostname">The hostname, e.g. www.myelin.co.nz</param>
  251. /// <param name="port">The port, e.g. 80 for HTTP</param>
  252. [MonoTODO]
  253. public void Connect (string hostname, int port)
  254. {
  255. CheckDisposed ();
  256. IPHostEntry host = Dns.GetHostByName(hostname);
  257. for(int i=0; i<host.AddressList.Length; i++)
  258. {
  259. try {
  260. Init(host.AddressList[i].AddressFamily);
  261. if(host.AddressList[i].AddressFamily == AddressFamily.InterNetwork)
  262. client.Bind(new IPEndPoint(IPAddress.Any, 0));
  263. #if NET_1_1
  264. else if(host.AddressList[i].AddressFamily == AddressFamily.InterNetworkV6)
  265. client.Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
  266. #endif
  267. Connect(new IPEndPoint(host.AddressList[i], port));
  268. break;
  269. }
  270. catch(Exception e) {
  271. if(client != null) {
  272. client.Close();
  273. client = null;
  274. }
  275. /// This is the last known address, re-throw the exception
  276. if(i == host.AddressList.Length-1)
  277. throw e;
  278. }
  279. }
  280. }
  281. /// <summary>
  282. /// Gets rid of all managed resources
  283. /// </summary>
  284. void IDisposable.Dispose ()
  285. {
  286. Dispose (true);
  287. GC.SuppressFinalize (this);
  288. }
  289. /// <summary>
  290. /// Gets rid of all unmanaged resources
  291. /// </summary>
  292. /// <param name="disposing">If this is true, it gets rid of all
  293. /// managed resources as well</param>
  294. protected virtual void Dispose (bool disposing)
  295. {
  296. if (disposed)
  297. return;
  298. disposed = true;
  299. // release unmanaged resources
  300. NetworkStream s = stream;
  301. stream = null;
  302. if (s != null) {
  303. // This closes the socket as well, as the NetworkStream
  304. // owns the socket.
  305. s.Close();
  306. active = false;
  307. s = null;
  308. }
  309. client = null;
  310. }
  311. /// <summary>
  312. /// Destructor - just calls Dispose()
  313. /// </summary>
  314. ~TcpClient ()
  315. {
  316. Dispose (false);
  317. }
  318. /// <returns>A NetworkStream object connected to the
  319. /// connection socket</returns>
  320. public NetworkStream GetStream()
  321. {
  322. try {
  323. if (stream == null)
  324. {
  325. stream = new NetworkStream (client, true);
  326. }
  327. return stream;
  328. }
  329. finally { CheckDisposed (); }
  330. }
  331. private void CheckDisposed ()
  332. {
  333. if (disposed)
  334. throw new ObjectDisposedException (GetType().FullName);
  335. }
  336. }
  337. }