TcpClientChannel.cs

本文介绍了一个基于 TCP 协议实现的客户端通道 (TcpClientChannel),该通道用于通过 TCP 进行远程方法调用。它实现了 IChannelSender 接口,并详细描述了其构造方法、属性设置以及消息发送和接收的过程。

摘要生成于 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:       TcpClientChannel.cs
  17. //
  18. //  Summary:    Implements a channel that transmits 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. namespace System.Runtime.Remoting.Channels.Tcp
  31. {
  32.     /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel"]/*' />
  33.     public class TcpClientChannel : IChannelSender
  34.     {
  35.         private int    _channelPriority = 1;  // channel priority
  36.         private String _channelName = "tcp"// channel name
  37.         
  38.         private IClientChannelSinkProvider _sinkProvider = null// sink chain provider
  39.         
  40.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.TcpClientChannel"]/*' />
  41.         public TcpClientChannel()
  42.         {
  43.             SetupChannel();        
  44.         } // TcpClientChannel
  45.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.TcpClientChannel1"]/*' />
  46.         public TcpClientChannel(String name, IClientChannelSinkProvider sinkProvider)
  47.         {
  48.             _channelName = name;
  49.             _sinkProvider = sinkProvider;
  50.             SetupChannel();
  51.         }
  52.         // constructor used by config file
  53.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.TcpClientChannel2"]/*' />
  54.         public TcpClientChannel(IDictionary properties, IClientChannelSinkProvider sinkProvider)
  55.         {
  56.             if (properties != null)
  57.             {
  58.                 foreach (DictionaryEntry entry in properties)
  59.                 {
  60.                     switch ((String)entry.Key)
  61.                     {
  62.                     case "name": _channelName = (String)entry.Value; break;
  63.                     case "priority": _channelPriority = Convert.ToInt32(entry.Value); break;
  64.                     default
  65.                          throw new ArgumentException(
  66.                             String.Format(
  67.                                 CoreChannel.GetResourceString(
  68.                                     "Remoting_Channels_BadCtorArgs"),
  69.                                 entry.Key));
  70.                     }
  71.                 }
  72.             }
  73.             _sinkProvider = sinkProvider;
  74.             SetupChannel();
  75.         } // TcpClientChannel
  76.         private void SetupChannel()
  77.         {
  78.             if (_sinkProvider != null)
  79.             {
  80.                 CoreChannel.AppendProviderToClientProviderChain(
  81.                     _sinkProvider, new TcpClientTransportSinkProvider());                                                
  82.             }
  83.             else
  84.                 _sinkProvider = CreateDefaultClientProviderChain();
  85.         } // SetupChannel
  86.         //
  87.         // IChannel implementation
  88.         //
  89.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.ChannelPriority"]/*' />
  90.         public int ChannelPriority
  91.         {
  92.             get { return _channelPriority; }    
  93.         }
  94.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.ChannelName"]/*' />
  95.         public String ChannelName
  96.         {
  97.             get { return _channelName; }
  98.         }
  99.         // returns channelURI and places object uri into out parameter
  100.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.Parse"]/*' />
  101.         public String Parse(String url, out String objectURI)
  102.         {            
  103.             return TcpChannelHelper.ParseURL(url, out objectURI);
  104.         } // Parse
  105.         //
  106.         // end of IChannel implementation
  107.         // 
  108.         //
  109.         // IChannelSender implementation
  110.         //
  111.         /// <include file='doc/TcpClientChannel.uex' path='docs/doc[@for="TcpClientChannel.CreateMessageSink"]/*' />
  112.         public virtual IMessageSink CreateMessageSink(String url, Object remoteChannelData, out String objectURI)
  113.         {
  114.             // Set the out parameters
  115.             objectURI = null;
  116.             String channelURI = null;
  117.             
  118.             if (url != null// Is this a well known object?
  119.             {
  120.                 // Parse returns null if this is not one of our url's
  121.                 channelURI = Parse(url, out objectURI);
  122.             }
  123.             else // determine if we want to connect based on the channel data
  124.             {
  125.                 if (remoteChannelData != null)
  126.                 {
  127.                     if (remoteChannelData is IChannelDataStore)
  128.                     {
  129.                         IChannelDataStore cds = (IChannelDataStore)remoteChannelData;
  130.                         // see if this is an tcp uri
  131.                         String simpleChannelUri = Parse(cds.ChannelUris[0], out objectURI);
  132.                         if (simpleChannelUri != null)
  133.                             channelURI = cds.ChannelUris[0];
  134.                     }
  135.                 }
  136.             }
  137.             if (null != channelURI)
  138.             {
  139.                 if (url == null)
  140.                     url = channelURI;
  141.                 IClientChannelSink sink = _sinkProvider.CreateSink(this, url, remoteChannelData);
  142.                 
  143.                 // return sink after making sure that it implements IMessageSink
  144.                 IMessageSink msgSink = sink as IMessageSink;
  145.                 if ((sink != null) && (msgSink == null))
  146.                 {
  147.                     throw new RemotingException(
  148.                         CoreChannel.GetResourceString(
  149.                             "Remoting_Channels_ChannelSinkNotMsgSink"));
  150.                 }
  151.                     
  152.                 return msgSink;           
  153.             }
  154.             return null;
  155.         } // CreateMessageSink
  156.         //
  157.         // end of IChannelSender implementation
  158.         //
  159.         private IClientChannelSinkProvider CreateDefaultClientProviderChain()
  160.         {
  161.             IClientChannelSinkProvider chain = new BinaryClientFormatterSinkProvider();            
  162.             IClientChannelSinkProvider sink = chain;
  163.             
  164.             sink.Next = new TcpClientTransportSinkProvider();
  165.             
  166.             return chain;
  167.         } // CreateDefaultClientProviderChain
  168.     } // class TcpClientChannel
  169.     internal class TcpClientTransportSinkProvider : IClientChannelSinkProvider
  170.     {
  171.         internal TcpClientTransportSinkProvider()
  172.         {
  173.         }    
  174.    
  175.         public IClientChannelSink CreateSink(IChannelSender channel, String url, 
  176.                                              Object remoteChannelData)
  177.         {
  178.             // url is set to the channel uri in CreateMessageSink        
  179.             return new TcpClientTransportSink(url);
  180.         }
  181.         public IClientChannelSinkProvider Next
  182.         {
  183.             get { return null; }
  184.             set { throw new NotSupportedException(); }
  185.         }
  186.     } // class TcpClientTransportSinkProvider
  187.     internal class TcpClientTransportSink : IClientChannelSink
  188.     {
  189.         // socket cache
  190.         internal static SocketCache ClientSocketCache = 
  191.             new SocketCache(new SocketHandlerFactory(TcpClientTransportSink.CreateSocketHandler));
  192.         private static SocketHandler CreateSocketHandler(
  193.             Socket socket, SocketCache socketCache, String machineAndPort)
  194.         {
  195.             return new TcpClientSocketHandler(socket, machineAndPort);
  196.         } // CreateSocketHandler
  197.         
  198.         // transport sink state
  199.         private String m_machineName;
  200.         private int    m_port;
  201.         private String _machineAndPort;
  202.         internal TcpClientTransportSink(String channelURI)
  203.         {
  204.             String objectURI;
  205.             String simpleChannelUri = TcpChannelHelper.ParseURL(channelURI, out objectURI);
  206.         
  207.             // extract machine name and port
  208.             int start = simpleChannelUri.IndexOf("://");
  209.             start += 3;
  210.             int index = simpleChannelUri.IndexOf(':', start);
  211.             if (index == -1)
  212.             {
  213.                 // If there is no colon, then there is no port number.
  214.                 throw new RemotingException(
  215.                     String.Format(  
  216.                         CoreChannel.GetResourceString(
  217.                             "Remoting_Tcp_UrlMustHavePort"),
  218.                         channelURI));
  219.             }
  220.             
  221.             m_machineName = simpleChannelUri.Substring(start, index - start);            
  222.             m_port = Int32.Parse(simpleChannelUri.Substring(index + 1));
  223.             _machineAndPort = m_machineName + ":" + m_port;
  224.         } // TcpClientTransportSink
  225.         public void ProcessMessage(IMessage msg,
  226.                                    ITransportHeaders requestHeaders, Stream requestStream,
  227.                                    out ITransportHeaders responseHeaders, out Stream responseStream)
  228.         {
  229.             InternalRemotingServices.RemotingTrace("TcpClientTransportSink::ProcessMessage");
  230.             TcpClientSocketHandler clientSocket = 
  231.                 SendRequestWithRetry(msg, requestHeaders, requestStream);
  232.             // receive response
  233.             responseHeaders = clientSocket.ReadHeaders();
  234.             responseStream = clientSocket.GetResponseStream();    
  235.             // The client socket will be returned to the cache
  236.             //   when the response stream is closed.
  237.             
  238.         } // ProcessMessage
  239.         public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg,
  240.                                         ITransportHeaders headers, Stream stream)
  241.         {
  242.             InternalRemotingServices.RemotingTrace("TcpClientTransportSink::AsyncProcessRequest");
  243.         
  244.             TcpClientSocketHandler clientSocket = 
  245.                 SendRequestWithRetry(msg, headers, stream);
  246.             if (clientSocket.OneWayRequest)
  247.             {
  248.                 clientSocket.ReturnToCache();
  249.             }
  250.             else
  251.             {
  252.                 // do an async read on the reply
  253.                 clientSocket.DataArrivedCallback = new WaitCallback(this.ReceiveCallback);
  254.                 clientSocket.DataArrivedCallbackState = sinkStack;
  255.                 clientSocket.BeginReadMessage();
  256.             }
  257.         } // AsyncProcessRequest
  258.         public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, Object state,
  259.                                          ITransportHeaders headers, Stream stream)
  260.         {
  261.             // We don't have to implement this since we are always last in the chain.
  262.             throw new NotSupportedException();
  263.         } // AsyncProcessRequest
  264.         
  265.         
  266.         public Stream GetRequestStream(IMessage msg, ITransportHeaders headers)
  267.         {
  268.             // Currently, we require a memory stream be handed to us since we need
  269.             //   the length before sending.      
  270.             return null
  271.         } // GetRequestStream
  272.         public IClientChannelSink NextChannelSink
  273.         {
  274.             get { return null; }
  275.         } // Next
  276.         private TcpClientSocketHandler SendRequestWithRetry(IMessage msg, 
  277.                                                             ITransportHeaders requestHeaders,
  278.                                                             Stream requestStream)
  279.         {
  280.             // If the stream is seekable, we can retry once on a failure to write.
  281.             long initialPosition = 0;
  282.             bool bCanSeek = requestStream.CanSeek;
  283.             if (bCanSeek)
  284.                 initialPosition = requestStream.Position;
  285.             TcpClientSocketHandler clientSocket = null;
  286.             try
  287.             {
  288.                 clientSocket = (TcpClientSocketHandler)ClientSocketCache.GetSocket(_machineAndPort);
  289.                 clientSocket.SendRequest(msg, requestHeaders, requestStream);
  290.             }
  291.             catch (SocketException)
  292.             {
  293.                 // retry sending if possible
  294.                 if (bCanSeek)
  295.                 {
  296.                     // reset position...
  297.                     requestStream.Position = initialPosition;
  298.                     // ...and try again.
  299.                     clientSocket = (TcpClientSocketHandler)
  300.                         ClientSocketCache.GetSocket(_machineAndPort);
  301.                         
  302.                     clientSocket.SendRequest(msg, requestHeaders, requestStream);
  303.                 }
  304.             }
  305.             requestStream.Close();
  306.             return clientSocket;
  307.         } // SendRequestWithRetry
  308.         private void ReceiveCallback(Object state)
  309.         {   
  310.             TcpClientSocketHandler clientSocket = null;
  311.             IClientChannelSinkStack sinkStack = null;
  312.                 
  313.             try            
  314.             {
  315.                 clientSocket = (TcpClientSocketHandler)state;
  316.                 sinkStack = (IClientChannelSinkStack)clientSocket.DataArrivedCallbackState;
  317.             
  318.                 ITransportHeaders responseHeaders = clientSocket.ReadHeaders();
  319.                 Stream responseStream = clientSocket.GetResponseStream(); 
  320.                 
  321.                 // call down the sink chain
  322.                 sinkStack.AsyncProcessResponse(responseHeaders, responseStream);
  323.             }
  324.             catch (Exception e)
  325.             {
  326.                 try
  327.                 {
  328.                     if (sinkStack != null)
  329.                         sinkStack.DispatchException(e);
  330.                 }
  331.                 catch(Exception )
  332.                 {
  333.                     // Fatal Error.. ignore
  334.                 }
  335.             }
  336.             // The client socket will be returned to the cache
  337.             //   when the response stream is closed.
  338.             
  339.         } // ReceiveCallback
  340.                 
  341.         //
  342.         // Properties
  343.         //
  344.         public IDictionary Properties
  345.         {
  346.             get 
  347.             {
  348.                 return null;
  349.             }
  350.         } // Properties
  351.         //
  352.         // end of Properties
  353.         //
  354.     } // class TcpClientTransportSink
  355. // namespace namespace System.Runtime.Remoting.Channels.Tcp
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值