TcpClient.cs 8.0 KB

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