TcpClient.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  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. IPAddress any = IPAddress.Any;
  78. if (family == AddressFamily.InterNetworkV6)
  79. any = IPAddress.IPv6Any;
  80. client.Bind (new IPEndPoint (any, 0));
  81. }
  82. #endif
  83. public TcpClient (IPEndPoint local_end_point)
  84. {
  85. Init(local_end_point.AddressFamily);
  86. client.Bind(local_end_point);
  87. }
  88. public TcpClient (string hostname, int port)
  89. {
  90. Connect(hostname, port);
  91. }
  92. protected bool Active {
  93. get { return active; }
  94. set { active = value; }
  95. }
  96. #if NET_2_0
  97. public Socket Client {
  98. #else
  99. protected Socket Client {
  100. #endif
  101. get { return client; }
  102. set {
  103. client = value;
  104. stream = null;
  105. }
  106. }
  107. #if NET_2_0
  108. public int Available {
  109. get { return client.Available; }
  110. }
  111. public bool Connected {
  112. get { return client.Connected; }
  113. }
  114. #if TARGET_JVM
  115. [MonoNotSupported ("Not supported as Socket.ExclusiveAddressUse is not supported")]
  116. #endif
  117. public bool ExclusiveAddressUse {
  118. get {
  119. return(client.ExclusiveAddressUse);
  120. }
  121. set {
  122. client.ExclusiveAddressUse = value;
  123. }
  124. }
  125. #endif
  126. internal void SetTcpClient (Socket s)
  127. {
  128. Client = s;
  129. }
  130. public LingerOption LingerState {
  131. get {
  132. if ((values & Properties.LingerState) != 0)
  133. return linger_state;
  134. return (LingerOption) client.GetSocketOption (SocketOptionLevel.Socket,
  135. SocketOptionName.Linger);
  136. }
  137. set {
  138. if (!client.Connected) {
  139. linger_state = value;
  140. values |= Properties.LingerState;
  141. return;
  142. }
  143. client.SetSocketOption(
  144. SocketOptionLevel.Socket,
  145. SocketOptionName.Linger, value);
  146. }
  147. }
  148. public bool NoDelay {
  149. get {
  150. if ((values & Properties.NoDelay) != 0)
  151. return no_delay;
  152. return (bool)client.GetSocketOption(
  153. SocketOptionLevel.Tcp,
  154. SocketOptionName.NoDelay);
  155. }
  156. set {
  157. if (!client.Connected) {
  158. no_delay = value;
  159. values |= Properties.NoDelay;
  160. return;
  161. }
  162. client.SetSocketOption(
  163. SocketOptionLevel.Tcp,
  164. SocketOptionName.NoDelay, value ? 1 : 0);
  165. }
  166. }
  167. public int ReceiveBufferSize {
  168. get {
  169. if ((values & Properties.ReceiveBufferSize) != 0)
  170. return recv_buffer_size;
  171. return (int)client.GetSocketOption(
  172. SocketOptionLevel.Socket,
  173. SocketOptionName.ReceiveBuffer);
  174. }
  175. set {
  176. if (!client.Connected) {
  177. recv_buffer_size = value;
  178. values |= Properties.ReceiveBufferSize;
  179. return;
  180. }
  181. client.SetSocketOption(
  182. SocketOptionLevel.Socket,
  183. SocketOptionName.ReceiveBuffer, value);
  184. }
  185. }
  186. public int ReceiveTimeout {
  187. get {
  188. if ((values & Properties.ReceiveTimeout) != 0)
  189. return recv_timeout;
  190. return (int)client.GetSocketOption(
  191. SocketOptionLevel.Socket,
  192. SocketOptionName.ReceiveTimeout);
  193. }
  194. set {
  195. if (!client.Connected) {
  196. recv_timeout = value;
  197. values |= Properties.ReceiveTimeout;
  198. return;
  199. }
  200. client.SetSocketOption(
  201. SocketOptionLevel.Socket,
  202. SocketOptionName.ReceiveTimeout, value);
  203. }
  204. }
  205. public int SendBufferSize {
  206. get {
  207. if ((values & Properties.SendBufferSize) != 0)
  208. return send_buffer_size;
  209. return (int)client.GetSocketOption(
  210. SocketOptionLevel.Socket,
  211. SocketOptionName.SendBuffer);
  212. }
  213. set {
  214. if (!client.Connected) {
  215. send_buffer_size = value;
  216. values |= Properties.SendBufferSize;
  217. return;
  218. }
  219. client.SetSocketOption(
  220. SocketOptionLevel.Socket,
  221. SocketOptionName.SendBuffer, value);
  222. }
  223. }
  224. public int SendTimeout {
  225. get {
  226. if ((values & Properties.SendTimeout) != 0)
  227. return send_timeout;
  228. return (int)client.GetSocketOption(
  229. SocketOptionLevel.Socket,
  230. SocketOptionName.SendTimeout);
  231. }
  232. set {
  233. if (!client.Connected) {
  234. send_timeout = value;
  235. values |= Properties.SendTimeout;
  236. return;
  237. }
  238. client.SetSocketOption(
  239. SocketOptionLevel.Socket,
  240. SocketOptionName.SendTimeout, value);
  241. }
  242. }
  243. // methods
  244. public void Close ()
  245. {
  246. ((IDisposable) this).Dispose ();
  247. }
  248. public void Connect (IPEndPoint remote_end_point)
  249. {
  250. try {
  251. client.Connect(remote_end_point);
  252. active = true;
  253. } finally {
  254. CheckDisposed ();
  255. }
  256. }
  257. public void Connect (IPAddress address, int port)
  258. {
  259. Connect(new IPEndPoint(address, port));
  260. }
  261. void SetOptions ()
  262. {
  263. Properties props = values;
  264. values = 0;
  265. if ((props & Properties.LingerState) != 0)
  266. LingerState = linger_state;
  267. if ((props & Properties.NoDelay) != 0)
  268. NoDelay = no_delay;
  269. if ((props & Properties.ReceiveBufferSize) != 0)
  270. ReceiveBufferSize = recv_buffer_size;
  271. if ((props & Properties.ReceiveTimeout) != 0)
  272. ReceiveTimeout = recv_timeout;
  273. if ((props & Properties.SendBufferSize) != 0)
  274. SendBufferSize = send_buffer_size;
  275. if ((props & Properties.SendTimeout) != 0)
  276. SendTimeout = send_timeout;
  277. }
  278. public void Connect (string hostname, int port)
  279. {
  280. IPAddress [] addresses = Dns.GetHostAddresses (hostname);
  281. Connect (addresses, port);
  282. }
  283. #if NET_2_0
  284. public
  285. #else
  286. private
  287. #endif
  288. void Connect (IPAddress[] ipAddresses, int port)
  289. {
  290. CheckDisposed ();
  291. if (ipAddresses == null) {
  292. throw new ArgumentNullException ("ipAddresses");
  293. }
  294. for(int i = 0; i < ipAddresses.Length; i++) {
  295. try {
  296. IPAddress address = ipAddresses[i];
  297. if (address.Equals (IPAddress.Any) ||
  298. address.Equals (IPAddress.IPv6Any)) {
  299. throw new SocketException ((int)SocketError.AddressNotAvailable);
  300. }
  301. Init (address.AddressFamily);
  302. if (address.AddressFamily == AddressFamily.InterNetwork) {
  303. client.Bind (new IPEndPoint (IPAddress.Any, 0));
  304. #if NET_1_1
  305. } else if (address.AddressFamily == AddressFamily.InterNetworkV6) {
  306. client.Bind (new IPEndPoint (IPAddress.IPv6Any, 0));
  307. #endif
  308. } else {
  309. throw new NotSupportedException ("This method is only valid for sockets in the InterNetwork and InterNetworkV6 families");
  310. }
  311. Connect (new IPEndPoint (address, port));
  312. if (values != 0) {
  313. SetOptions ();
  314. }
  315. break;
  316. } catch (Exception e) {
  317. /* Reinitialise the socket so
  318. * other properties still work
  319. * (see no-arg constructor)
  320. */
  321. Init (AddressFamily.InterNetwork);
  322. /* This is the last known
  323. * address, so re-throw the
  324. * exception
  325. */
  326. if (i == ipAddresses.Length - 1) {
  327. throw e;
  328. }
  329. }
  330. }
  331. }
  332. #if NET_2_0
  333. public void EndConnect (IAsyncResult asyncResult)
  334. {
  335. client.EndConnect (asyncResult);
  336. }
  337. #if TARGET_JVM
  338. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  339. #endif
  340. public IAsyncResult BeginConnect (IPAddress address, int port,
  341. AsyncCallback callback,
  342. object state)
  343. {
  344. return(client.BeginConnect (address, port, callback,
  345. state));
  346. }
  347. #if TARGET_JVM
  348. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  349. #endif
  350. public IAsyncResult BeginConnect (IPAddress[] addresses,
  351. int port,
  352. AsyncCallback callback,
  353. object state)
  354. {
  355. return(client.BeginConnect (addresses, port, callback,
  356. state));
  357. }
  358. #if TARGET_JVM
  359. [MonoNotSupported ("Not supported as Socket.BeginConnect is not supported")]
  360. #endif
  361. public IAsyncResult BeginConnect (string host, int port,
  362. AsyncCallback callback,
  363. object state)
  364. {
  365. return(client.BeginConnect (host, port, callback,
  366. state));
  367. }
  368. #endif
  369. void IDisposable.Dispose ()
  370. {
  371. Dispose (true);
  372. GC.SuppressFinalize (this);
  373. }
  374. protected virtual void Dispose (bool disposing)
  375. {
  376. if (disposed)
  377. return;
  378. disposed = true;
  379. if (disposing) {
  380. // release managed resources
  381. NetworkStream s = stream;
  382. stream = null;
  383. if (s != null) {
  384. // This closes the socket as well, as the NetworkStream
  385. // owns the socket.
  386. s.Close();
  387. active = false;
  388. s = null;
  389. } else if (client != null){
  390. client.Close ();
  391. client = null;
  392. }
  393. }
  394. }
  395. ~TcpClient ()
  396. {
  397. Dispose (false);
  398. }
  399. public NetworkStream GetStream()
  400. {
  401. try {
  402. if (stream == null)
  403. stream = new NetworkStream (client, true);
  404. return stream;
  405. }
  406. finally { CheckDisposed (); }
  407. }
  408. private void CheckDisposed ()
  409. {
  410. if (disposed)
  411. throw new ObjectDisposedException (GetType().FullName);
  412. }
  413. }
  414. }