TcpClient.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. // System.Net.Sockets.TcpClient.cs
  2. //
  3. // Author:
  4. // Phillip Pearson ([email protected])
  5. // Gonzalo Paniagua Javier ([email protected])
  6. // Sridhar Kulkarni ([email protected])
  7. //
  8. // Copyright (C) 2001, Phillip Pearson
  9. // http://www.myelin.co.nz
  10. // Copyright (c) 2006 Novell, Inc. (http://www.novell.com)
  11. //
  12. //
  13. // Permission is hereby granted, free of charge, to any person obtaining
  14. // a copy of this software and associated documentation files (the
  15. // "Software"), to deal in the Software without restriction, including
  16. // without limitation the rights to use, copy, modify, merge, publish,
  17. // distribute, sublicense, and/or sell copies of the Software, and to
  18. // permit persons to whom the Software is furnished to do so, subject to
  19. // the following conditions:
  20. //
  21. // The above copyright notice and this permission notice shall be
  22. // included in all copies or substantial portions of the Software.
  23. //
  24. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  25. // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  26. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  27. // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
  28. // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
  29. // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  30. // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  31. //
  32. using System;
  33. using System.Net;
  34. namespace System.Net.Sockets
  35. {
  36. public class TcpClient : IDisposable {
  37. enum Properties : uint {
  38. LingerState = 1,
  39. NoDelay = 2,
  40. ReceiveBufferSize = 4,
  41. ReceiveTimeout = 8,
  42. SendBufferSize = 16,
  43. SendTimeout = 32
  44. }
  45. // private data
  46. NetworkStream stream;
  47. bool active;
  48. Socket client;
  49. bool disposed;
  50. Properties values;
  51. int recv_timeout, send_timeout;
  52. int recv_buffer_size, send_buffer_size;
  53. LingerOption linger_state;
  54. bool no_delay;
  55. private void Init (AddressFamily family)
  56. {
  57. active = false;
  58. if(client != null) {
  59. client.Close();
  60. client = null;
  61. }
  62. client = new Socket(family, SocketType.Stream, ProtocolType.Tcp);
  63. }
  64. public TcpClient ()
  65. {
  66. Init(AddressFamily.InterNetwork);
  67. client.Bind(new IPEndPoint(IPAddress.Any, 0));
  68. }
  69. #if NET_1_1
  70. public TcpClient (AddressFamily family)
  71. {
  72. if (family != AddressFamily.InterNetwork &&
  73. family != AddressFamily.InterNetworkV6) {
  74. throw new ArgumentException ("Family must be InterNetwork or InterNetworkV6", "family");
  75. }
  76. Init (family);
  77. client.Bind (new IPEndPoint (IPAddress.Any, 0));
  78. }
  79. #endif
  80. public TcpClient (IPEndPoint local_end_point)
  81. {
  82. Init(local_end_point.AddressFamily);
  83. client.Bind(local_end_point);
  84. }
  85. public TcpClient (string hostname, int port)
  86. {
  87. Connect(hostname, port);
  88. }
  89. protected bool Active {
  90. get { return active; }
  91. set { active = value; }
  92. }
  93. #if NET_2_0
  94. public Socket Client {
  95. #else
  96. protected Socket Client {
  97. #endif
  98. get { return client; }
  99. set {
  100. client = value;
  101. stream = null;
  102. }
  103. }
  104. #if NET_2_0
  105. public int Available {
  106. get { return client.Available; }
  107. }
  108. public bool Connected {
  109. get { return client.Connected; }
  110. }
  111. #if TARGET_JVM
  112. [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
  113. #endif
  114. public bool ExclusiveAddressUse {
  115. get {
  116. return(client.ExclusiveAddressUse);
  117. }
  118. set {
  119. client.ExclusiveAddressUse = value;
  120. }
  121. }
  122. #endif
  123. internal void SetTcpClient (Socket s)
  124. {
  125. Client = s;
  126. }
  127. public LingerOption LingerState {
  128. get {
  129. if ((values & Properties.LingerState) != 0)
  130. return linger_state;
  131. return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
  132. SocketOptionName.Linger);
  133. }
  134. set {
  135. if (!client.Connected) {
  136. linger_state = value;
  137. values |= Properties.LingerState;
  138. return;
  139. }
  140. client.SetSocketOption(
  141. SocketOptionLevel.Socket,
  142. SocketOptionName.Linger, value);
  143. }
  144. }
  145. public bool NoDelay {
  146. get {
  147. if ((values & Properties.NoDelay) != 0)
  148. return no_delay;
  149. return (bool)client.GetSocketOption(
  150. SocketOptionLevel.Tcp,
  151. SocketOptionName.NoDelay);
  152. }
  153. set {
  154. if (!client.Connected) {
  155. no_delay = value;
  156. values |= Properties.NoDelay;
  157. return;
  158. }
  159. client.SetSocketOption(
  160. SocketOptionLevel.Tcp,
  161. SocketOptionName.NoDelay, value ? 1 : 0);
  162. }
  163. }
  164. public int ReceiveBufferSize {
  165. get {
  166. if ((values & Properties.ReceiveBufferSize) != 0)
  167. return recv_buffer_size;
  168. return (int)client.GetSocketOption(
  169. SocketOptionLevel.Socket,
  170. SocketOptionName.ReceiveBuffer);
  171. }
  172. set {
  173. if (!client.Connected) {
  174. recv_buffer_size = value;
  175. values |= Properties.ReceiveBufferSize;
  176. return;
  177. }
  178. client.SetSocketOption(
  179. SocketOptionLevel.Socket,
  180. SocketOptionName.ReceiveBuffer, value);
  181. }
  182. }
  183. public int ReceiveTimeout {
  184. get {
  185. if ((values & Properties.ReceiveTimeout) != 0)
  186. return recv_timeout;
  187. return (int)client.GetSocketOption(
  188. SocketOptionLevel.Socket,
  189. SocketOptionName.ReceiveTimeout);
  190. }
  191. set {
  192. if (!client.Connected) {
  193. recv_timeout = value;
  194. values |= Properties.ReceiveTimeout;
  195. return;
  196. }
  197. client.SetSocketOption(
  198. SocketOptionLevel.Socket,
  199. SocketOptionName.ReceiveTimeout, value);
  200. }
  201. }
  202. public int SendBufferSize {
  203. get {
  204. if ((values & Properties.SendBufferSize) != 0)
  205. return send_buffer_size;
  206. return (int)client.GetSocketOption(
  207. SocketOptionLevel.Socket,
  208. SocketOptionName.SendBuffer);
  209. }
  210. set {
  211. if (!client.Connected) {
  212. send_buffer_size = value;
  213. values |= Properties.SendBufferSize;
  214. return;
  215. }
  216. client.SetSocketOption(
  217. SocketOptionLevel.Socket,
  218. SocketOptionName.SendBuffer, value);
  219. }
  220. }
  221. public int SendTimeout {
  222. get {
  223. if ((values & Properties.SendTimeout) != 0)
  224. return send_timeout;
  225. return (int)client.GetSocketOption(
  226. SocketOptionLevel.Socket,
  227. SocketOptionName.SendTimeout);
  228. }
  229. set {
  230. if (!client.Connected) {
  231. send_timeout = value;
  232. values |= Properties.SendTimeout;
  233. return;
  234. }
  235. client.SetSocketOption(
  236. SocketOptionLevel.Socket,
  237. SocketOptionName.SendTimeout, value);
  238. }
  239. }
  240. // methods
  241. public void Close ()
  242. {
  243. ((IDisposable) this).Dispose ();
  244. }
  245. public void Connect (IPEndPoint remote_end_point)
  246. {
  247. try {
  248. client.Connect(remote_end_point);
  249. active = true;
  250. } finally {
  251. CheckDisposed ();
  252. }
  253. }
  254. public void Connect (IPAddress address, int port)
  255. {
  256. Connect(new IPEndPoint(address, port));
  257. }
  258. void SetOptions ()
  259. {
  260. Properties props = values;
  261. values = 0;
  262. if ((props & Properties.LingerState) != 0)
  263. LingerState = linger_state;
  264. if ((props & Properties.NoDelay) != 0)
  265. NoDelay = no_delay;
  266. if ((props & Properties.ReceiveBufferSize) != 0)
  267. ReceiveBufferSize = recv_buffer_size;
  268. if ((props & Properties.ReceiveTimeout) != 0)
  269. ReceiveTimeout = recv_timeout;
  270. if ((props & Properties.SendBufferSize) != 0)
  271. SendBufferSize = send_buffer_size;
  272. if ((props & Properties.SendTimeout) != 0)
  273. SendTimeout = send_timeout;
  274. }
  275. public void Connect (string hostname, int port)
  276. {
  277. IPHostEntry host = Dns.GetHostByName(hostname);
  278. Connect (host.AddressList, port);
  279. }
  280. #if NET_2_0
  281. public
  282. #else
  283. private
  284. #endif
  285. void Connect (IPAddress[] ipAddresses, int port)
  286. {
  287. CheckDisposed ();
  288. if (ipAddresses == null) {
  289. throw new ArgumentNullException ("ipAddresses");
  290. }
  291. for(int i = 0; i < ipAddresses.Length; i++) {
  292. try {
  293. IPAddress address = ipAddresses[i];
  294. if (address.Equals (IPAddress.Any) ||
  295. address.Equals (IPAddress.IPv6Any)) {
  296. throw new SocketException ((int)SocketError.AddressNotAvailable);
  297. }
  298. Init (address.AddressFamily);
  299. if (address.AddressFamily == AddressFamily.InterNetwork) {
  300. client.Bind (new IPEndPoint (IPAddress.Any, 0));
  301. #if NET_1_1
  302. } else if (address.AddressFamily == AddressFamily.InterNetworkV6) {
  303. client.Bind (new IPEndPoint (IPAddress.IPv6Any, 0));
  304. #endif
  305. } else {
  306. throw new NotSupportedException ("This method is only valid for sockets in the InterNetwork and InterNetworkV6 families");
  307. }
  308. Connect (new IPEndPoint (address, port));
  309. if (values != 0) {
  310. SetOptions ();
  311. }
  312. break;
  313. } catch (Exception e) {
  314. /* Reinitialise the socket so
  315. * other properties still work
  316. * (see no-arg constructor)
  317. */
  318. Init (AddressFamily.InterNetwork);
  319. /* This is the last known
  320. * address, so re-throw the
  321. * exception
  322. */
  323. if (i == ipAddresses.Length - 1) {
  324. throw e;
  325. }
  326. }
  327. }
  328. }
  329. #if NET_2_0
  330. public void EndConnect (IAsyncResult asyncResult)
  331. {
  332. client.EndConnect (asyncResult);
  333. }
  334. #if TARGET_JVM
  335. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  336. #endif
  337. public IAsyncResult BeginConnect (IPAddress address, int port,
  338. AsyncCallback callback,
  339. object state)
  340. {
  341. return(client.BeginConnect (address, port, callback,
  342. state));
  343. }
  344. #if TARGET_JVM
  345. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  346. #endif
  347. public IAsyncResult BeginConnect (IPAddress[] addresses,
  348. int port,
  349. AsyncCallback callback,
  350. object state)
  351. {
  352. return(client.BeginConnect (addresses, port, callback,
  353. state));
  354. }
  355. #if TARGET_JVM
  356. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  357. #endif
  358. public IAsyncResult BeginConnect (string host, int port,
  359. AsyncCallback callback,
  360. object state)
  361. {
  362. return(client.BeginConnect (host, port, callback,
  363. state));
  364. }
  365. #endif
  366. void IDisposable.Dispose ()
  367. {
  368. Dispose (true);
  369. GC.SuppressFinalize (this);
  370. }
  371. protected virtual void Dispose (bool disposing)
  372. {
  373. if (disposed)
  374. return;
  375. disposed = true;
  376. if (disposing) {
  377. // release managed resources
  378. NetworkStream s = stream;
  379. stream = null;
  380. if (s != null) {
  381. // This closes the socket as well, as the NetworkStream
  382. // owns the socket.
  383. s.Close();
  384. active = false;
  385. s = null;
  386. } else if (client != null){
  387. client.Close ();
  388. client = null;
  389. }
  390. }
  391. }
  392. ~TcpClient ()
  393. {
  394. Dispose (false);
  395. }
  396. public NetworkStream GetStream()
  397. {
  398. try {
  399. if (stream == null)
  400. stream = new NetworkStream (client, true);
  401. return stream;
  402. }
  403. finally { CheckDisposed (); }
  404. }
  405. private void CheckDisposed ()
  406. {
  407. if (disposed)
  408. throw new ObjectDisposedException (GetType().FullName);
  409. }
  410. }
  411. }