NetworkStreamExtensions.cs 2.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. using System;
  2. using System.IO;
  3. using System.Net.Sockets;
  4. namespace Telepathy
  5. {
  6. public static class NetworkStreamExtensions
  7. {
  8. // .Read returns '0' if remote closed the connection but throws an
  9. // IOException if we voluntarily closed our own connection.
  10. //
  11. // let's add a ReadSafely method that returns '0' in both cases so we don't
  12. // have to worry about exceptions, since a disconnect is a disconnect...
  13. public static int ReadSafely(this NetworkStream stream, byte[] buffer, int offset, int size)
  14. {
  15. try
  16. {
  17. return stream.Read(buffer, offset, size);
  18. }
  19. // IOException happens if we voluntarily closed our own connection.
  20. catch (IOException)
  21. {
  22. return 0;
  23. }
  24. // ObjectDisposedException can be thrown if Client.Disconnect()
  25. // disposes the stream, while we are still trying to read here.
  26. // catching it fixes https://github.com/vis2k/Telepathy/pull/104
  27. catch (ObjectDisposedException)
  28. {
  29. return 0;
  30. }
  31. }
  32. // helper function to read EXACTLY 'n' bytes
  33. // -> default .Read reads up to 'n' bytes. this function reads exactly
  34. // 'n' bytes
  35. // -> this is blocking until 'n' bytes were received
  36. // -> immediately returns false in case of disconnects
  37. public static bool ReadExactly(this NetworkStream stream, byte[] buffer, int amount)
  38. {
  39. // there might not be enough bytes in the TCP buffer for .Read to read
  40. // the whole amount at once, so we need to keep trying until we have all
  41. // the bytes (blocking)
  42. //
  43. // note: this just is a faster version of reading one after another:
  44. // for (int i = 0; i < amount; ++i)
  45. // if (stream.Read(buffer, i, 1) == 0)
  46. // return false;
  47. // return true;
  48. int bytesRead = 0;
  49. while (bytesRead < amount)
  50. {
  51. // read up to 'remaining' bytes with the 'safe' read extension
  52. int remaining = amount - bytesRead;
  53. int result = stream.ReadSafely(buffer, bytesRead, remaining);
  54. // .Read returns 0 if disconnected
  55. if (result == 0)
  56. return false;
  57. // otherwise add to bytes read
  58. bytesRead += result;
  59. }
  60. return true;
  61. }
  62. }
  63. }