TcpClient.cs 8.0 KB

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