TcpServerChannel.cs

本文介绍了一个基于 TCP 协议的服务器通道实现细节,包括如何接收远程方法调用、配置参数解析、默认消息序列化机制及监听流程。

摘要生成于 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. //  File:       TcpServerChannel.cs
  17. //
  18. //  Summary:    Implements a channel that receives method calls over TCP.
  19. //
  20. //==========================================================================
  21. using System;
  22. using System.Collections;
  23. using System.IO;
  24. using System.Net;
  25. using System.Net.Sockets;
  26. using System.Runtime.Remoting;
  27. using System.Runtime.Remoting.Channels;
  28. using System.Runtime.Remoting.Messaging;
  29. using System.Threading;
  30. using System.Runtime.InteropServices;
  31. namespace System.Runtime.Remoting.Channels.Tcp
  32. {
  33.     /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel"]/*' />
  34.     public class TcpServerChannel : IChannelReceiver
  35.     {
  36.         private int               _channelPriority = 1;  // priority of channel (default=1)
  37.         private String            _channelName = "tcp";  // channel name
  38.         private String            _machineName = null;   // machine name
  39.         private int               _port = -1;            // port to listen on
  40.         private ChannelDataStore  _channelData = null;   // channel data
  41.         private String _forcedMachineName = null// an explicitly configured machine name
  42.         private bool _bUseIpAddress = true// by default, we'll use the ip address.
  43.         private IPAddress _bindToAddr = IPAddress.Any; // address to bind to.
  44.         private bool _bSuppressChannelData = false;  // should we hand out null for our channel data
  45.         
  46.         private IServerChannelSinkProvider _sinkProvider = null;
  47.         private TcpServerTransportSink    _transportSink = null;
  48.         
  49.         private TcpListener _tcpListener;
  50.         private Thread      _listenerThread;
  51.         private bool        _bListening = false;
  52.         private Exception   _startListeningException = null// if an exception happens on the listener thread when attempting
  53.                                                          //   to start listening, that will get set here.
  54.         private AutoResetEvent  _waitForStartListening = new AutoResetEvent(false);
  55.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.TcpServerChannel"]/*' />
  56.         public TcpServerChannel(int port)
  57.         {
  58.             _port = port;
  59.             SetupMachineName();
  60.             SetupChannel();
  61.         } // TcpServerChannel
  62.     
  63.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.TcpServerChannel1"]/*' />
  64.         public TcpServerChannel(String name, int port)
  65.         {
  66.             _channelName =name;
  67.             _port = port;
  68.             SetupMachineName();
  69.             SetupChannel();
  70.         } // TcpServerChannel
  71.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.TcpServerChannel2"]/*' />
  72.         public TcpServerChannel(String name, int port, IServerChannelSinkProvider sinkProvider)
  73.         {
  74.             _channelName = name;
  75.             _port = port;
  76.             _sinkProvider = sinkProvider;
  77.             SetupMachineName();
  78.             SetupChannel();
  79.         } // TcpServerChannel
  80.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.TcpServerChannel3"]/*' />
  81.         public TcpServerChannel(IDictionary properties, IServerChannelSinkProvider sinkProvider)
  82.         {                   
  83.             if (properties != null)
  84.             {
  85.                 foreach (DictionaryEntry entry in properties)
  86.                 {
  87.                     switch ((String)entry.Key)
  88.                     {
  89.                     case "name": _channelName = (String)entry.Value; break;  
  90.                     case "bindTo": _bindToAddr = IPAddress.Parse((String)entry.Value); break;
  91.                     case "port": _port = Convert.ToInt32(entry.Value); break;
  92.                     case "priority": _channelPriority = Convert.ToInt32(entry.Value); break;
  93.                     case "machineName": _forcedMachineName = (String)entry.Value; break;
  94.                     case "rejectRemoteRequests":
  95.                     {
  96.                         bool bReject = Convert.ToBoolean(entry.Value);
  97.                         if (bReject)
  98.                             _bindToAddr = IPAddress.Loopback;
  99.                         break;
  100.                     }
  101.                     
  102.                     case "suppressChannelData": _bSuppressChannelData = Convert.ToBoolean(entry.Value); break;
  103.                     case "useIpAddress": _bUseIpAddress = Convert.ToBoolean(entry.Value); break;
  104.                 
  105.                     default
  106.                          throw new ArgumentException(
  107.                             String.Format(
  108.                                 CoreChannel.GetResourceString(
  109.                                     "Remoting_Channels_BadCtorArgs"),
  110.                                 entry.Key));
  111.                     }
  112.                 }
  113.             }
  114.             _sinkProvider = sinkProvider;
  115.             SetupMachineName();
  116.             SetupChannel();
  117.         } // TcpServerChannel
  118.         private void SetupMachineName()
  119.         {
  120.             if (_forcedMachineName != null)
  121.             {
  122.                 // an explicitly configured machine name was used
  123.                 _machineName = CoreChannel.DecodeMachineName(_forcedMachineName);
  124.             }
  125.             else
  126.             {
  127.                 if (!_bUseIpAddress)
  128.                     _machineName = CoreChannel.GetMachineName();
  129.                 else
  130.                 {
  131.                     if (_bindToAddr == IPAddress.Any)
  132.                         _machineName = CoreChannel.GetMachineIp();
  133.                     else
  134.                         _machineName = _bindToAddr.ToString();
  135.                 }
  136.             }
  137.         } // SetupMachineName
  138.         private void SetupChannel()
  139.         {   
  140.             // set channel data
  141.             // (These get changed inside of StartListening(), in the case where the listen
  142.             //   port is 0, because we can't determine the port number until after the
  143.             //   TcpListener starts.)
  144.             
  145.             _channelData = new ChannelDataStore(null);
  146.             if (_port > 0)
  147.             {
  148.                 _channelData.ChannelUris = new String[1];
  149.                 _channelData.ChannelUris[0] = GetChannelUri();
  150.             }
  151.             // set default provider (soap formatter) if no provider has been set
  152.             if (_sinkProvider == null)
  153.                 _sinkProvider = CreateDefaultServerProviderChain();
  154.             CoreChannel.CollectChannelDataFromServerSinkProviders(_channelData, _sinkProvider);
  155.             // construct sink chain
  156.             IServerChannelSink sink = ChannelServices.CreateServerChannelSinkChain(_sinkProvider, this);
  157.             _transportSink = new TcpServerTransportSink(sink);
  158.             
  159.             if (_port >= 0)
  160.             {
  161.                 // Open a TCP port and create a thread to start listening
  162.                 _tcpListener = new TcpListener(_bindToAddr, _port);
  163.                 ThreadStart t = new ThreadStart(this.Listen);
  164.                 _listenerThread = new Thread(t);
  165.                 _listenerThread.IsBackground = true;
  166.                 // Wait for thread to spin up
  167.                 StartListening(null);
  168.             }
  169.         } // SetupChannel
  170.         private IServerChannelSinkProvider CreateDefaultServerProviderChain()
  171.         {
  172.             IServerChannelSinkProvider chain = new BinaryServerFormatterSinkProvider();            
  173.             IServerChannelSinkProvider sink = chain;
  174.             
  175.             sink.Next = new SoapServerFormatterSinkProvider();
  176.             
  177.             return chain;
  178.         } // CreateDefaultServerProviderChain
  179.         //
  180.         // IChannel implementation
  181.         //
  182.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.ChannelPriority"]/*' />
  183.         public int ChannelPriority
  184.         {
  185.             get { return _channelPriority; }
  186.         }
  187.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.ChannelName"]/*' />
  188.         public String ChannelName
  189.         {
  190.             get { return _channelName; }
  191.         }
  192.         // returns channelURI and places object uri into out parameter
  193.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.Parse"]/*' />
  194.         public String Parse(String url, out String objectURI)
  195.         {            
  196.             return TcpChannelHelper.ParseURL(url, out objectURI);
  197.         } // Parse
  198.         //
  199.         // end of IChannel implementation
  200.         //
  201.         //
  202.         // IChannelReceiver implementation
  203.         //
  204.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.ChannelData"]/*' />
  205.         public Object ChannelData
  206.         {
  207.             get
  208.             {
  209.                 if (_bSuppressChannelData || !_bListening)
  210.                 {
  211.                     return null;
  212.                 }
  213.                 else
  214.                 {
  215.                     return _channelData;
  216.                 }
  217.             }
  218.         } // ChannelData
  219.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.GetChannelUri"]/*' />
  220.         public String GetChannelUri()
  221.         {
  222.             return "tcp://" + _machineName + ":" + _port;
  223.         } // GetChannelUri
  224.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.GetUrlsForUri"]/*' />
  225.         public virtual String[] GetUrlsForUri(String objectUri)
  226.         {
  227.             String[] retVal = new String[1];
  228.             if (!objectUri.StartsWith("/"))
  229.                 objectUri = "/" + objectUri;
  230.             retVal[0] = GetChannelUri() + objectUri;
  231.             return retVal;
  232.         } // GetURLsforURI
  233.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.StartListening"]/*' />
  234.         public void StartListening(Object data)
  235.         {
  236.             InternalRemotingServices.RemotingTrace("HTTPChannel.StartListening");
  237.             if (_port >= 0)
  238.             {
  239.                 if (_listenerThread.IsAlive == false)
  240.                 {
  241.                     _listenerThread.Start();
  242.                     _waitForStartListening.WaitOne(); // listener thread will signal this after starting TcpListener
  243.                     if (_startListeningException != null)
  244.                     {
  245.                         // An exception happened when we tried to start listening (such as "socket already in use)
  246.                         Exception e = _startListeningException;
  247.                         _startListeningException = null;
  248.                         throw e;
  249.                     }
  250.                     _bListening = true;
  251.                     // get new port assignment if a port of 0 was used to auto-select a port
  252.                     if (_port == 0)
  253.                     {
  254.                         _port = ((IPEndPoint)_tcpListener.LocalEndpoint).Port;
  255.                         if (_channelData != null)
  256.                         {
  257.                             _channelData.ChannelUris = new String[1];
  258.                             _channelData.ChannelUris[0] = GetChannelUri();
  259.                         }
  260.                     }
  261.                 }
  262.             }
  263.         } // StartListening
  264.         /// <include file='doc/TcpServerChannel.uex' path='docs/doc[@for="TcpServerChannel.StopListening"]/*' />
  265.         public void StopListening(Object data)
  266.         {
  267.             InternalRemotingServices.RemotingTrace("HTTPChannel.StopListening");
  268.             if (_port > 0)
  269.             {
  270.                 _bListening = false;
  271.                 // Ask the TCP listener to stop listening on the port
  272.                 if(null != _tcpListener)
  273.                 {
  274.                     _tcpListener.Stop();
  275.                 }
  276.             }
  277.         } // StopListening
  278.         //
  279.         // end of IChannelReceiver implementation
  280.         //
  281.         //
  282.         // Server helpers
  283.         //
  284.         // Thread for listening
  285.         void Listen()
  286.         {
  287.             bool bOkToListen = false;
  288.         
  289.             try
  290.             {
  291.                 _tcpListener.Start();
  292.                 bOkToListen = true;
  293.             }
  294.             catch (Exception e)
  295.             {
  296.                 _startListeningException = e;
  297.             }   
  298.             _waitForStartListening.Set(); // allow main thread to continue now that we have tried to start the socket
  299.             InternalRemotingServices.RemotingTrace( "Waiting to Accept the Socket on Port: " + _port);
  300.             //
  301.             // Wait for an incoming socket
  302.             //
  303.             Socket socket;
  304.             while (bOkToListen)
  305.             {
  306.                 InternalRemotingServices.RemotingTrace("TCPChannel::Listen - tcpListen.Pending() == true");
  307.                 try
  308.                 {
  309.                     socket = _tcpListener.AcceptSocket();
  310.                     if (socket == null)
  311.                     {
  312.                         throw new RemotingException(
  313.                             String.Format(
  314.                                 CoreChannel.GetResourceString("Remoting_Socket_Accept"),
  315.                                 Marshal.GetLastWin32Error().ToString()));
  316.                     }                
  317.                 
  318.                     // disable nagle delay
  319.                     socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.NoDelay, 1);
  320.                     // set linger option
  321.                     LingerOption lingerOption = new LingerOption(true, 3);
  322.                     socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lingerOption);
  323.                 
  324.                     TcpServerSocketHandler streamManager = new TcpServerSocketHandler(socket, CoreChannel.RequestQueue);
  325.                     streamManager.DataArrivedCallback = new WaitCallback(_transportSink.ServiceRequest);
  326.                     streamManager.BeginReadMessage();
  327.                 }
  328.                 catch (Exception e)
  329.                 {
  330.                     if (!_bListening)
  331.                     {
  332.                         // We called Stop() on the tcp listener, so gracefully exit.
  333.                         bOkToListen = false;                        
  334.                     }
  335.                     else
  336.                     {
  337.                         // we want the exception to show up as unhandled since this
  338.                         //   is an unexpected failure.
  339.                         if (!(e is SocketException))
  340.                         {
  341.                             //throw;                      
  342.                         }
  343.                     }
  344.                 }
  345.             }
  346.         }
  347.     } // class TcpServerChannel
  348.     internal class TcpServerTransportSink : IServerChannelSink
  349.     {
  350.         //private const int _defaultChunkSize = 4096;
  351.         private const int s_MaxSize =  (2 << 24); // Max size of the payload
  352.         // sink state
  353.         private IServerChannelSink _nextSink;
  354.         public TcpServerTransportSink(IServerChannelSink nextSink)
  355.         {
  356.             _nextSink = nextSink;
  357.         } // TcpServerTransportSink
  358.         
  359.     
  360.         internal void ServiceRequest(Object state)
  361.         {
  362.             TcpServerSocketHandler streamManager = (TcpServerSocketHandler)state;
  363.             ITransportHeaders headers = streamManager.ReadHeaders();
  364.             Stream requestStream = streamManager.GetRequestStream();
  365.             RemotingServices.LogRemotingStage(CoreChannel.SERVER_MSG_RECEIVE);
  366.             // process request
  367.             ServerChannelSinkStack sinkStack = new ServerChannelSinkStack();
  368.             sinkStack.Push(this, streamManager);
  369.             IMessage responseMessage;
  370.             ITransportHeaders responseHeaders;
  371.             Stream responseStream;
  372.             ServerProcessing processing = 
  373.                 _nextSink.ProcessMessage(sinkStack, null, headers, requestStream, 
  374.                                          out responseMessage,
  375.                                          out responseHeaders, out responseStream);
  376.             // handle response
  377.             switch (processing)
  378.             {                    
  379.             case ServerProcessing.Complete:
  380.             {
  381.                 // Send the response. Call completed synchronously.
  382.                 sinkStack.Pop(this);
  383.                 RemotingServices.LogRemotingStage(CoreChannel.SERVER_RET_END);
  384.                 streamManager.SendResponse(responseHeaders, responseStream);
  385.                 break;
  386.             } // case ServerProcessing.Complete
  387.             
  388.             case ServerProcessing.OneWay:
  389.             {                       
  390.                 // No response needed, but the following method will make sure that
  391.                 //   we send at least a skeleton reply if the incoming request was
  392.                 //   not marked OneWayRequest (client/server metadata could be out of
  393.                 //   sync).
  394.                 streamManager.SendResponse(responseHeaders, responseStream);
  395.                 break;
  396.             } // case ServerProcessing.OneWay
  397.             case ServerProcessing.Async:
  398.             {
  399.                 sinkStack.StoreAndDispatch(this, streamManager);
  400.                 break;
  401.             }// case ServerProcessing.Async
  402.             } // switch (processing) 
  403.                    
  404.             // async processing will take care if handling this later
  405.             if (processing != ServerProcessing.Async)
  406.             {
  407.                 if (streamManager.CanServiceAnotherRequest())
  408.                     streamManager.BeginReadMessage();
  409.                 else
  410.                     streamManager.Close();
  411.             }
  412.             
  413.         } // ServiceRequest               
  414.         //
  415.         // IServerChannelSink implementation
  416.         //
  417.         public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack,
  418.             IMessage requestMsg,
  419.             ITransportHeaders requestHeaders, Stream requestStream,
  420.             out IMessage responseMsg, out ITransportHeaders responseHeaders,
  421.             out Stream responseStream)
  422.         {
  423.             // NOTE: This doesn't have to be implemented because the server transport
  424.             //   sink is always first.
  425.             throw new NotSupportedException();
  426.         }
  427.            
  428.         public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state,
  429.                                          IMessage msg, ITransportHeaders headers, Stream stream)                 
  430.         {
  431.             TcpServerSocketHandler streamManager = null;
  432.             streamManager = (TcpServerSocketHandler)state;
  433.             // send the response
  434.             streamManager.SendResponse(headers, stream);
  435.             
  436.             if (streamManager.CanServiceAnotherRequest())
  437.                 streamManager.BeginReadMessage();
  438.             else
  439.                 streamManager.Close(); 
  440.         } // AsyncProcessResponse
  441.         public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state,
  442.                                         IMessage msg, ITransportHeaders headers)
  443.         {            
  444.             // We always want a stream to read from.
  445.             return null;
  446.         } // GetResponseStream
  447.         public IServerChannelSink NextChannelSink
  448.         {
  449.             get { return _nextSink; }
  450.         }
  451.         public IDictionary Properties
  452.         {
  453.             get { return null; }
  454.         } // Properties
  455.         
  456.         //
  457.         // end of IServerChannelSink implementation
  458.         //
  459.         
  460.     } // class TcpServerTransportSink
  461. // namespace System.Runtime.Remoting.Channels.Tcp
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值