TcpStreams.cs

本文详细解析了 .NET Framework 中 TCP 通道所使用的 Streams 类,包括 TcpReadingStream 的抽象基类及其两个具体实现:TcpFixedLengthReadingStream 和 TcpChunkedReadingStream。探讨了如何处理固定长度和分块的数据读取过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1. // ==++==
  2. // 
  3. //   
  4. //    Copyright (c) 2002 Microsoft Corporation.  All rights reserved.
  5. //   
  6. //    The use and distribution terms for this software are contained in the file
  7. //    named license.txt, which can be found in the root of this distribution.
  8. //    By using this software in any fashion, you are agreeing to be bound by the
  9. //    terms of this license.
  10. //   
  11. //    You must not remove this notice, or any other, from this software.
  12. //   
  13. // 
  14. // ==--==
  15. //============================================================
  16. //
  17. // File:    TcpStreams.cs
  18. //
  19. // Summary: Defines streams used by TCP channel.
  20. //
  21. //============================================================
  22. using System;
  23. using System.Collections;
  24. using System.IO;
  25. using System.Net;
  26. using System.Net.Sockets;
  27. using System.Text;
  28. using System.Threading;
  29. namespace System.Runtime.Remoting.Channels.Tcp
  30. {
  31.     internal abstract class TcpReadingStream : Stream
  32.     {
  33.         public void ReadToEnd()
  34.         {
  35.             // This method should never be called where it would be valid
  36.             //   to use this data, so it is ok to throw the excess bytes
  37.             //   away.
  38.             byte[] buffer = new byte[64];
  39.             int readCount;
  40.             do
  41.             {
  42.                 readCount = Read(buffer, 0, 64);
  43.             } while (readCount > 0);
  44.         }
  45.     
  46.         public virtual bool FoundEnd { get { return false; } }
  47.         
  48.         public override bool CanRead {  get { return true; } }
  49.         public override bool CanSeek { get { return false; } }
  50.         public override bool CanWrite { get { return false; } }
  51.        
  52.         public override long Length {  get { throw new NotSupportedException(); } }
  53.         public override long Position
  54.         {
  55.              getthrow new NotSupportedException(); }
  56.              setthrow new NotSupportedException(); }
  57.         }
  58.         public override  void Flush() { throw new NotSupportedException(); }
  59.         
  60.         public override  long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); }
  61.         public override  void SetLength(long value) { throw new NotSupportedException(); }
  62.         public override void Write(byte[] buffer, int offset, int count)
  63.         {
  64.             throw new NotSupportedException();
  65.         }        
  66.     } // TcpReadingStream
  67.     internal class TcpFixedLengthReadingStream : TcpReadingStream
  68.     { 
  69.         private SocketHandler _inputStream; 
  70.         private int _bytesLeft;   // bytes left to read
  71.         internal TcpFixedLengthReadingStream(SocketHandler inputStream, 
  72.                                              int contentLength)
  73.         {
  74.             _inputStream = inputStream;
  75.             _bytesLeft = contentLength;
  76.         } // TcpFixedLengthReadingStream
  77.         public override bool FoundEnd { get { return _bytesLeft == 0; } }
  78.         public override void Close()
  79.         {
  80.             _inputStream.OnInputStreamClosed();
  81.         }
  82.         
  83.         public override int Read(byte[] buffer, int offset, int count)
  84.         {
  85.             if (_bytesLeft == 0)
  86.                 return 0;
  87.         
  88.             int readCount = _inputStream.Read(buffer, offset, Math.Min(_bytesLeft, count));
  89.             if (readCount > 0)
  90.                 _bytesLeft -= readCount;
  91.             
  92.             return readCount;
  93.         } // Read
  94.         public override int ReadByte()
  95.         {
  96.             if (_bytesLeft == 0)
  97.                 return -1;
  98.             _bytesLeft -= 1;
  99.             return _inputStream.ReadByte();
  100.         } // ReadByte
  101.                 
  102.     } // TcpFixedLengthReadingStream
  103.     internal class TcpChunkedReadingStream : TcpReadingStream
  104.     {   
  105.         private SocketHandler _inputStream = null// read chunked tcp data from here
  106.         
  107.         private int    _bytesLeft;          // bytes left in current chunk
  108.         private bool   _bFoundEnd = false;  // has end of stream been reached?
  109.         private byte[] _byteBuffer = new byte[1]; // buffer for reading bytes
  110.         
  111.         
  112.         internal TcpChunkedReadingStream(SocketHandler inputStream)
  113.         {
  114.             _inputStream = inputStream;
  115.             
  116.             _bytesLeft = 0;
  117.         } // HttpChunkedRequestStream
  118.         public override bool FoundEnd { get { return _bFoundEnd; } }
  119.         public override void Close() 
  120.         {
  121.         } // Close
  122.         
  123.         private int min(int a, int b) { return a < b ? a : b;}
  124.         
  125.         public override int Read(byte[] buffer, int offset, int count)
  126.         {
  127.             int bytesRead = 0;
  128.         
  129.             while (!_bFoundEnd && (count > 0))
  130.             {
  131.                 // see if we need to start reading a new chunk
  132.                 if (_bytesLeft == 0)
  133.                 {
  134.                     _bytesLeft = _inputStream.ReadInt32();
  135.                                         
  136.                     if (_bytesLeft == 0)
  137.                     {
  138.                         ReadTrailer();                        
  139.                         _bFoundEnd = true;
  140.                     }
  141.                 }
  142.                 if (!_bFoundEnd)
  143.                 {
  144.                     int readCount = min(_bytesLeft, count);
  145.                     int bytesReadThisTime = _inputStream.Read(buffer, offset, readCount);
  146.                     if (bytesReadThisTime <= 0)
  147.                     {
  148.                         throw new RemotingException(
  149.                             CoreChannel.GetResourceString(
  150.                                 "Remoting_Tcp_ChunkedEncodingError"));
  151.                     }
  152.                     
  153.                     _bytesLeft -= bytesReadThisTime;
  154.                     count -= bytesReadThisTime;
  155.                     offset += bytesReadThisTime;
  156.                     bytesRead += bytesReadThisTime;
  157.                 
  158.                     // see if the end of the chunk was found
  159.                     if (_bytesLeft == 0)
  160.                     {
  161.                         ReadTrailer();
  162.                     }
  163.                 }
  164.             } // while (count > 0)  
  165.             return bytesRead;
  166.         } // Read        
  167.         public override int ReadByte()
  168.         {
  169.             int readCount = Read(_byteBuffer, 0, 1);
  170.             if (readCount == 0)
  171.                 return -1;
  172.                 
  173.             return _byteBuffer[0];         
  174.         } // ReadByte
  175.         private void ReadTrailer()
  176.         {
  177.             // read trailer bytes "/r/n" and throw an exception if they aren't correct.
  178.             int ch = _inputStream.ReadByte();
  179.             if (ch != '/r')
  180.             {
  181.                 throw new RemotingException(
  182.                     CoreChannel.GetResourceString(
  183.                         "Remoting_Tcp_ChunkedEncodingError"));
  184.             }
  185.             ch = _inputStream.ReadByte();
  186.             if (ch != '/n')
  187.             {
  188.                 throw new RemotingException(
  189.                     CoreChannel.GetResourceString(
  190.                         "Remoting_Tcp_ChunkedEncodingError"));
  191.             }
  192.         }
  193.         
  194.     } // TcpChunkedReadingStream
  195.     
  196.      // Maintains control of a socket connection.
  197.     internal class TcpServerSocketHandler : TcpSocketHandler
  198.     {
  199.         // prebaked bytes
  200.         private static byte[] s_endOfLineBytes = Encoding.ASCII.GetBytes("/r/n");
  201.         
  202.     
  203.         // Used to keep track of socket connections
  204.         private static Int64 _connectionIdCounter = 0;        
  205.         
  206.         private Int64 _connectionId;   // id for this connection
  207.         private bool _bOneWayRequest;  // is the incoming request one way?
  208.         private bool _bChunked;        // is the incoming request chunked?
  209.         private int  _contentLength;   // content length of incoming request
  210.         TcpReadingStream _requestStream; // the request stream
  211.         
  212.         internal TcpServerSocketHandler(Socket socket, RequestQueue requestQueue) : base(socket, requestQueue)
  213.         {                 
  214.             _connectionId = Interlocked.Increment(ref _connectionIdCounter);
  215.         } // TcpServerSocketHandler
  216.         // Determine if it's possible to service another request
  217.         public bool CanServiceAnotherRequest()
  218.         {
  219.             return true;
  220.         } // CanServiceAnotherRequest
  221.         
  222.         // Prepare for reading a new request off of the same socket
  223.         protected override void PrepareForNewMessage()
  224.         {
  225.             if (_requestStream != null)
  226.             {
  227.                 if (!_requestStream.FoundEnd)
  228.                     _requestStream.ReadToEnd();
  229.                 _requestStream = null;
  230.             }
  231.         } // PrepareForNewRequest
  232.             
  233.         protected override void SendErrorMessageIfPossible(Exception e)
  234.         {        
  235.             // A fatal exception occurred. We communicate this error by
  236.             // writing an error message and empty message body.
  237.             try
  238.             {
  239.                 SendErrorResponse(e, true);
  240.             }
  241.             catch
  242.             {
  243.                 // the connection must be dead, so it doesn't really matter.
  244.             }
  245.         } // SendErrorMessageIfPossible
  246.             
  247.         // read headers
  248.         public ITransportHeaders ReadHeaders()
  249.         {        
  250.             BaseTransportHeaders headers = new BaseTransportHeaders();
  251.             UInt16 operation;
  252.             ReadVersionAndOperation(out operation);
  253.             // make sure the operation is Request or OneWayRequest.
  254.             if (operation == TcpOperations.Request)
  255.             {
  256.                 _bOneWayRequest = false;
  257.             }
  258.             else
  259.             if (operation == TcpOperations.OneWayRequest)
  260.             {
  261.                 _bOneWayRequest = true;
  262.             }
  263.             else
  264.             {
  265.                 throw new RemotingException(
  266.                     String.Format(
  267.                         CoreChannel.GetResourceString("Remoting_Tcp_ExpectingRequestOp"),
  268.                         operation.ToString()));
  269.             }            
  270.             // content length must come next (may be chunked or a specific length)
  271.             ReadContentLength(out _bChunked, out _contentLength);
  272.             // read to end of headers  
  273.             ReadToEndOfHeaders(headers);   
  274.                            
  275.             // add IP address and Connection Id to headers
  276.             headers.IPAddress = ((IPEndPoint)NetSocket.RemoteEndPoint).Address;
  277.             headers.ConnectionId = _connectionId;
  278.             
  279.             return headers;
  280.         } // ReadHeaders
  281.         public Stream GetRequestStream()
  282.         {
  283.             if (!_bChunked)
  284.                 _requestStream =  new TcpFixedLengthReadingStream(this, _contentLength);
  285.             else
  286.                 _requestStream =  new TcpChunkedReadingStream(this);
  287.             return _requestStream;
  288.         } // GetRequestStream
  289.       
  290.         public void SendResponse(ITransportHeaders headers, Stream contentStream)
  291.         {           
  292.             // bail out if the original request was OneWay (means the client doesn't even
  293.             //   want or expect to receive responses or error messages)
  294.             if (_bOneWayRequest)
  295.                 return;            
  296.         
  297.             // build up headers and send      
  298.             ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool);
  299.             // output preamble and version
  300.             WritePreambleAndVersion(headerStream);
  301.             // output opcode
  302.             WriteUInt16(TcpOperations.Reply, headerStream);
  303.             // output content length delimiter
  304.             WriteUInt16(TcpContentDelimiter.ContentLength, headerStream);
  305.             WriteInt32((int)contentStream.Length, headerStream);
  306.             // No status code header is needed because if we're in this code path
  307.             //   the data transfer succeeded as far as the transport protocol is
  308.             //   concerned (and the success status code is optional).
  309.             WriteHeaders(headers, headerStream);
  310.             
  311.             headerStream.WriteTo(NetStream);
  312.             headerStream.Close();
  313.             StreamHelper.CopyStream(contentStream, NetStream);          
  314.                          
  315.             contentStream.Close();            
  316.         } // SendResponse
  317.         public void SendErrorResponse(Exception e, bool bCloseConnection)
  318.         {
  319.             // bail out if the original request was OneWay (means the client doesn't even
  320.             //   want or expect to receive responses or error messages)
  321.             if (_bOneWayRequest)
  322.                 return;
  323.         
  324.             // build up headers and send      
  325.             ChunkedMemoryStream headerStream = new ChunkedMemoryStream(CoreChannel.BufferPool);
  326.             // output preamble and version
  327.             WritePreambleAndVersion(headerStream);
  328.             // output opcode
  329.             WriteUInt16(TcpOperations.Reply, headerStream);
  330.             // output content length delimiter (0-length stream)
  331.             WriteUInt16(TcpContentDelimiter.ContentLength, headerStream);
  332.             WriteInt32(0, headerStream);
  333.             // output status code and reason
  334.             WriteUInt16(TcpHeaders.StatusCode, headerStream);
  335.             WriteByte(TcpHeaderFormat.UInt16, headerStream);
  336.             WriteUInt16(TcpStatusCode.GenericError, headerStream);
  337.             // we purposely don't include the stack trace to avoid giving
  338.             //   out too much information for security purposes.
  339.             WriteUInt16(TcpHeaders.StatusPhrase, headerStream);
  340.             WriteByte(TcpHeaderFormat.CountedString, headerStream);
  341.             WriteCountedString(e.Message, headerStream);
  342.             // indicate that we are about to close the connection
  343.             WriteUInt16(TcpHeaders.CloseConnection, headerStream);
  344.             WriteByte(TcpHeaderFormat.Void, headerStream);
  345.             // end of headers
  346.             WriteUInt16(TcpHeaders.EndOfHeaders, headerStream);
  347.             
  348.             headerStream.WriteTo(NetStream);
  349.             headerStream.Close();
  350.         } // SendErrorResponse
  351.                
  352.     } // class TcpServerSocketHandler
  353.     
  354.     
  355. // namespace System.Runtime.Remoting.Channels.Tcp
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值