TcpClient.cs 10 KB

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