[转]Remoting之同步—异步调用

原文地址:http://challengerking.cnblogs.com/articles/364997.html

一. 前言

关于Remoting程序的调用效率问题,在刚做完项目中并未作为考虑因素加以考虑,无意中看到一篇关于Remoting的同步/异步调用方式的讨论的引论,于是打算对这个问题作一些解读,并通过程序来证明异步调用在提高Remoting效率方面的作用。

二. 简介

.NET Framework提供了三种调用远程对象的方法(不论是Server activated object, 或者是Client activated object), 你可以通过同步调用,异步调用,或者异步[OneWay]的方式来调用远程对象。

同步调用是一种基本的调用方式,在《Remoting随想》中涉及的所有的调用方式都是同步调用方式,客户端调用远程服务器端的方法如同调用本地方法一样。当服务器端接到客户端的调用请求后开始运行被调用的方法,而客户端必须的等待服务器端的方法执行完毕方可再发出请求。如果在远程方法调用过程中出现异常,则在你所调用的服务器端抛出异常。

异步调用分为两个步骤,第一个步骤是触发远程方法执行,而不必等待远程方法的返回值。客户端程序继续向下执行。当客户端收到被调用方法回复(response)后,这时须调用另一个专门用于检查服务器端是否已经执行完成了对客户端请求的业务;如果没有完成,则客户端等待,直到服务器端程序完成。在此过程中如果有异常发生,异常将会在被调用方法中出错的位置被抛出,即使你事先未被告知服务器端已在脱机状态下。

最后一种调用方式与前一种调用方式稍有不同,在[OneWay]调用方式下,若服务器端出现问题(如脱机,或者被调用方法未能完成业务功能),客户端程序(即调用方)将得不到返回值、异常原因。.NET Framework将试图在远端服务器端调用这个方法。

三.同步调用

前面已经提及,同步调用是.NET Framework的调用方法的通常方式。服务器端和被客户端直接通信,客户端程序将被阻塞,直到服务器端的方法运行完毕。如果服务器端不可用或者异常出现而无法满足客户段的需求,异常将会被抛出。

具体的各种Remoting部署方案可以参考我所写的《Remoting随想》那篇文章,采取任何一种类型都不会影响本文的讨论。这里我们列举一种是用接口的方式来说明同步/异步调用调用。接口的使用可以用关键字interface来定义一个接口,同样也可以用抽象类来实现。

3.1 接口定义

我们新建一个Class library工程,并在随后的服务器端和客户端添加对此DLL的引用。下面代码就是被引用DLL所需的接口定义。

定义RecordingManager.dll

None.gifusing  System;
None.gif
using
 System.Runtime.Remoting.Messaging;
None.gif
namespace
 RecordingManager
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public abstract class
 BaseRemoteObject : MarshalByRefObject
ExpandedSubBlockStart.gifContractedSubBlock.gif
dot.gif
{
InBlock.gif    
public abstract
 DataSet GetRecordingsMe();
InBlock.gif    
public abstract
 DataSet GetRecordingsYou();
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

3.2 同步调用模式下的服务器端程序

新建一个控制台程序,在服务器端来实现接口定义的方法,这个实现接口的类可以与服务器端主程序写在一起,也可以单独写成一个类,我们这里单独写为一个类,这样逻辑更佳清楚。

None.gifusing  System;
None.gif
using
 System.Data;
None.gif
using
 System.Data.OracleClient;
None.gif
using
 System.Runtime.Remoting;
None.gif
using
 RecordingManager;
None.gif
using
 System.Runtime.Remoting.Messaging;
None.gif
using
 System.Collections;
None.gif
namespace
 TcpServer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{    
InBlock.gif    
//
 Implementations of syncronized patterns.
InBlock.gif    
// This class extends the abstract class "BaseRemoteObject".

InBlock.gif
    [Serializable]
InBlock.gif    
public class
 SynRemotingServices : BaseRemoteObject
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{        
InBlock.gif        
public
 SynRemotingServices()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            System.Console.WriteLine(
"New Reference Added through a interface, syncronized!"
);
ExpandedSubBlockEnd.gif        }

InBlock.gif            
InBlock.gif        
public override DataSet GetRecordingsMe()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            DataSet ds 
= new
 DataSet();
InBlock.gif            
try

ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{                
InBlock.gif                
// simulate a long running action

InBlock.gif
                Console.WriteLine("Get data from table 'ME', please waitdot.gif");
InBlock.gif                
// get data from database 

InBlock.gif
                String selectCmd = "select * from ME";  
InBlock.gif                OracleConnection myConnection 
= new
 OracleConnection(
InBlock.gif                    
"Data Source = DB00; User Id = jakey; Password = jakey"
);
InBlock.gif                OracleDataAdapter myAdapter 
= new
 
InBlock.gifOracleDataAdapter(selectCmd, myConnection);
InBlock.gif
InBlock.gif                myAdapter.Fill(ds, 
"ME"
);    
InBlock.gif                Console.WriteLine(
"get datatable 'ME' from database successful!"
);    
ExpandedSubBlockEnd.gif            }
    
InBlock.gif            
catch
(OracleException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Oracle error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(RemotingException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Remoting error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Unknown error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return ds;
ExpandedSubBlockEnd.gif        }
        
InBlock.gif
InBlock.gif        
public override
 DataSet GetRecordingsYou()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            DataSet ds 
= new
 DataSet();
InBlock.gif            
try

ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
// simulate a long running action

InBlock.gif
                Console.WriteLine("Get data from table 'YOU', please waitdot.gif");
InBlock.gif                
// get data from database 

InBlock.gif
                String selectCmd = "select * from YOU";  
InBlock.gif                OracleConnection myConnection 
= new
 OracleConnection(
InBlock.gif                    
"Data Source = DB00; User Id = jakey; Password = jakey"
);
InBlock.gif                OracleDataAdapter myAdapter 
= new
 
InBlock.gifOracleDataAdapter(selectCmd, myConnection);
InBlock.gif                myAdapter.Fill(ds, 
"YOU"
);    
InBlock.gif                Console.WriteLine(
"get datatable 'YOU' from database successful!"
);    
ExpandedSubBlockEnd.gif            }
    
InBlock.gif            
catch
(OracleException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Oracle error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(RemotingException ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Remoting error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch(Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Unknown error!" +
 ex.Message);
ExpandedSubBlockEnd.gif            }

InBlock.gif            
return ds;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


None.gifusing  System;
None.gif
using
 System.Runtime.Remoting;
None.gif
using
 System.Runtime.Remoting.Channels;
None.gif
using
 System.Runtime.Remoting.Channels.Tcp;
None.gif
using
 RecordingManager;
None.gif
using
 System.Data.OracleClient;
None.gif
using
 System.Data;
None.gif
using
 System.Runtime.Remoting.Messaging; 
None.gif
using
 System.Collections;
None.gif
namespace
 TcpServer
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**/
/// <summary>
InBlock.gif    
/// Server application of remoting.
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    class TcpServer
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{        
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**/
/// <summary>
InBlock.gif        
/// The main entry point for the application.
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        [STAThread]
InBlock.gif        
public static void Main(string
 [] args) 
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            
try

ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
//Normal method (use interface) start, synchronized patterns.

InBlock.gif
                TcpChannel channel = new TcpChannel(8888);
InBlock.gif                ChannelServices.RegisterChannel(channel);
InBlock.gif
InBlock.gif                RemotingConfiguration.RegisterWellKnownServiceType 
InBlock.gif                    (
typeof(SynRemotingServices),//first parameter is the realization of method of the interface

InBlock.gif
                    "myServer",//second parameter is the name of remote service name
InBlock.gif
                    WellKnownObjectMode.Singleton);//third parameter is type of activation type (server/client)
InBlock.gif                
//
WellKnownObjectMode.SingleCall,server instance object to each user 
InBlock.gif                
//WellKnownObjectMode.SingleTone,there is only one instance to all user

InBlock.gif
                        
InBlock.gif                Console.WriteLine(
"Server Started"
);
InBlock.gif                Console.ReadLine();            
ExpandedSubBlockEnd.gif            }

InBlock.gif        
InBlock.gif            
catch( NullReferenceException nullExp )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine( 
"Server null reference error!" +
 nullExp.Message );
ExpandedSubBlockEnd.gif            }

InBlock.gif            
catch( RemotingException remExp )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine( 
"Server remoting error!" +
 remExp.Message );
ExpandedSubBlockEnd.gif            }
 
InBlock.gif            
catch
(Exception x)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"Server Other error:" +
 x.Message);
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif

3.3 同步调用模式下的客户端程序

新建一个控制台程序,调用服务器端方法。

None.gifusing  System;
None.gif
using
 System.Runtime.Remoting;
None.gif
using
 System.Runtime.Remoting.Channels.Tcp;
None.gif
using
 System.Runtime.Remoting.Channels.Http;
None.gif
using
 System.Runtime.Remoting.Channels;
None.gif
using
 System.Runtime.Remoting.Proxies;
None.gif
using
 System.Data;
None.gif
using
 System.Data.OracleClient;
None.gif
using
 RecordingManager;
None.gif
None.gif
namespace
 synchronizeTest
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**/
/// <summary>
InBlock.gif    
/// This class is used for synchronization test of remoting 
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    class synchronizeClient
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        
// Define a variable

InBlock.gif
        private static DataSet myDataSet;
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**/
/// <summary>
InBlock.gif        
/// The main entry point for the application.
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        [STAThread]
InBlock.gif        
static void Main(string
[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            
// synchronization start

InBlock.gif
            DateTime start = System.DateTime.Now;
InBlock.gif            
int
 recordCount;
InBlock.gif            
//Register channel

InBlock.gif
            TcpChannel tcpChannel = new TcpChannel();
InBlock.gif            ChannelServices.RegisterChannel(tcpChannel); 
//
 Carete a TCP client channel,
InBlock.gif            
// this channel is not bind one port

InBlock.gif

InBlock.gif            RecordingManager.BaseRemoteObject myobj 
= 
InBlock.gif                (RecordingManager.BaseRemoteObject)Activator.GetObject 
// Server activated user GetObject()

InBlock.gif
                (typeof(RecordingManager.BaseRemoteObject)// First parameter is the remote object type,
InBlock.gif
                ,"tcp://localhost:8888/myServer"); // Second parameter is the remote object's URI。
InBlock.gif

InBlock.gif            Console.WriteLine(
"synchronizeClient.Main(): Reference to remoting obj. acquired");    
InBlock.gif            
// get data from table me

InBlock.gif
            Console.WriteLine("synchronizeClient.Main(): Get data from table 'ME'");
InBlock.gif            myDataSet 
=
 myobj.GetRecordingsMe();
InBlock.gif            recordCount 
= myDataSet.Tables["ME"
].Rows.Count;
InBlock.gif            Console.WriteLine(
"The counts of table 'ME' is: {0}"
, recordCount);
InBlock.gif
InBlock.gif            
// get data from table you

InBlock.gif
            Console.WriteLine("synchronizeClient.Main(): Get data from table 'YOU'");
InBlock.gif            myDataSet 
=
 myobj.GetRecordingsYou();
InBlock.gif            recordCount 
= myDataSet.Tables["YOU"
].Rows.Count;
InBlock.gif            Console.WriteLine(
"The counts of table 'YOU' is: {0}"
, recordCount);
InBlock.gif
InBlock.gif            DateTime end 
=
 System.DateTime.Now;
InBlock.gif            TimeSpan duration 
=
 end.Subtract(start);
InBlock.gif            Console.WriteLine(
"synchronizeClient.Main(): Execution took {0} seconds."
,
InBlock.gif                duration.Seconds);
InBlock.gif            
// wait for any key press

InBlock.gif
            Console.ReadLine();
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

InBlock.gif


编译程序,先启动服务器端程序,在启动客户段程序,我们可以看到如图所示的结果,客户端调用两个方法用了5秒钟的时间(Fig 3-1),我们注意观察服务器端程序控制台所示(Fig 3-2),服务器端的两个程序是先后被调用的,与客户端调用次序一致,这证明服务器端程序当第一个方法被调用执行完成后,第二个方法才开始执行。

 


Fig 3- 1
同步调用时客户端程序控制台显示内容

 


Fig 3- 2 同步调用时服务器端控制台显示内容

四.异步调用

在同步调用的例子里面我们可以看到,客户端程序独立调用服务器端的两个方法时,由于程序之间的相互等待导致了性能大打折扣。我们可以通过独立的线程(Thread)去分别调用它们,然而,即便是在.NET中使用线程很容易,但是这样做使得Remoting反而变得复杂,从而得不偿失。

.NET Framework提供了一种方法,叫做异步代理(asynchronous delegates),它容许方法以异步方式被调用。

服务器将异步操作拆分成两个逻辑部分:采用来自客户端的输入并调用异步操作的部分,向客户端提供异步操作结果的部分。

除了异步操作所需的输入外,第一部分还采用在完成异步操作时后要被调用的 AsyncCallback 委托。第一部分返回一个可等待的对象,该对象实现客户端使用的 IAsyncResult 接口来确定异步操作的状态。

服务器还使用它返回到客户端的可等待对象来维护与异步操作关联的任何状态。通过提供可等待的对象,客户端使用第二部分获取异步操作的结果。

4.1 异步调用模式下的客户端程序

异步调用模式下,接口定义和服务器端程序不作修改,客户端程序需要有较大变动。

None.gifusing  System;
None.gif
using
 System.Runtime.Remoting;
None.gif
using
 System.Runtime.Remoting.Channels.Tcp;
None.gif
using
 System.Runtime.Remoting.Channels.Http;
None.gif
using
 System.Runtime.Remoting.Channels;
None.gif
using
 System.Runtime.Remoting.Proxies;
None.gif
using
 System.Data;
None.gif
using
 System.Data.OracleClient;
None.gif
using
 Recording;
None.gif
None.gif
namespace
 asynchronousClient
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
ExpandedSubBlockStart.gifContractedSubBlock.gif    
/**/
/// <summary>
InBlock.gif    
/// This class is used for asynchronous test of remoting 
ExpandedSubBlockEnd.gif    
/// </summary>

InBlock.gif    class asynchronousClient
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        
// Define a variable

InBlock.gif
        private static DataSet myDataSet;
InBlock.gif
InBlock.gif        
// Define two delegate

InBlock.gif
        delegate DataSet GetDataTableMeDelegate();
InBlock.gif        
delegate
 DataSet GetDataTableYouDelegate();
InBlock.gif
ExpandedSubBlockStart.gifContractedSubBlock.gif        
/**/
/// <summary>
InBlock.gif        
/// The main entry point for the application.
ExpandedSubBlockEnd.gif        
/// </summary>

InBlock.gif        [STAThread]
InBlock.gif        
static void Main(string
[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{            
InBlock.gif            
try

ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif{
InBlock.gif                
// Using Asynchronous Delegates start

InBlock.gif
                DateTime start = System.DateTime.Now;
InBlock.gif                
int
 recordCount;
InBlock.gif
InBlock.gif                
//Register channel

InBlock.gif
                TcpChannel tcpChannel = new TcpChannel();
InBlock.gif                ChannelServices.RegisterChannel(tcpChannel); 
//
 Carete a TCP client channel,
InBlock.gif                
// this channel is not bind one port

InBlock.gif

InBlock.gif                RecordingManager.BaseRemoteObject myobj 
= 
InBlock.gif                    (RecordingManager.BaseRemoteObject)Activator.GetObject 
// Server activated user GetObject()

InBlock.gif
                    (typeof(RecordingManager.BaseRemoteObject)// First parameter is the remote object type,
InBlock.gif
                    ,"tcp://localhost:8888/myServer"); // Second parameter is the remote object's URI。
InBlock.gif

InBlock.gif                Console.WriteLine(
"asynchronousClient.Main(): Reference to remoting obj. acquired");
InBlock.gif    
InBlock.gif                
// get data from table me

InBlock.gif
                Console.WriteLine("asynchronousClient.Main(): Get data from table 'ME'");
InBlock.gif                GetDataTableMeDelegate meDelegate 
= new
 GetDataTableMeDelegate(myobj.GetRecordingsMe);
InBlock.gif                IAsyncResult meAsyncres 
= meDelegate.BeginInvoke(nullnull
);
InBlock.gif            
InBlock.gif                
// get data from table you

InBlock.gif
                Console.WriteLine("asynchronousClient.Main(): Get data from table 'YOU'");
InBlock.gif                GetDataTableYouDelegate youDelegate 
= new
 GetDataTableYouDelegate(myobj.GetRecordingsYou);
InBlock.gif                IAsyncResult youAsyncres 
= youDelegate.BeginInvoke(nullnull
);
InBlock.gif
InBlock.gif                
// get the counts of records

InBlock.gif
                Console.WriteLine("asynchronousClient.Main(): EndInvoke for me");
InBlock.gif                myDataSet 
=
 meDelegate.EndInvoke(meAsyncres);
InBlock.gif                recordCount 
= myDataSet.Tables["ME"
].Rows.Count;
InBlock.gif                Console.WriteLine(
"The counts of table 'ME' is: {0}"
, recordCount);
InBlock.gif
InBlock.gif                
// get the counts of records

InBlock.gif
                Console.WriteLine("asynchronousClient.Main(): EndInvoke for you");
InBlock.gif                myDataSet 
=
 youDelegate.EndInvoke(youAsyncres);
InBlock.gif                recordCount 
= myDataSet.Tables["YOU"
].Rows.Count;
InBlock.gif                Console.WriteLine(
"The counts of table 'YOU' is: {0}"
, recordCount);
InBlock.gif
InBlock.gif                DateTime end 
=
 System.DateTime.Now;
InBlock.gif                TimeSpan duration 
=
 end.Subtract(start);
InBlock.gif                Console.WriteLine(
"asynchronousClient.Main(): Execution took {0} seconds."
,
InBlock.gif                    duration.Seconds);
InBlock.gif                
// Using Asynchronous Delegates end

ExpandedSubBlockEnd.gif
            }

InBlock.gif            
catch(Exception ex)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                Console.WriteLine(
"asynchronousClient.Main(): EXCEPTION during EndInvoke " +
 ex.Message);
ExpandedSubBlockEnd.gif            }
            
InBlock.gif            
// wait for any key press            

InBlock.gif
            Console.ReadLine();
ExpandedSubBlockEnd.gif        }
        
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


编译程序,先启动服务器端程序,在启动客户段程序,我们可以看到如图所示的结果,客户端调用两个方法用了2秒钟的时间(Fig 4-1),我们注意观察服务器端程序控制台所示(Fig 4-2),服务器端的两个程序是同时被调用的,这证明服务器端程序当第一个方法被调用执行的同时,第二个方法也开始执行,这样就完成了异步调用。

 


Fig 4- 1 异步调用时客户端程序控制台显示内容

 


Fig 4- 2异步调时用服务器端控制台显示内容

五.异步[OneWay]调用

异步One-Way(单向)调用与异步调用稍有不同,.NET Framework并不保障One-Way调用方式的执行。此外,用这种调用方式的方法不能有返回值或out参数。客户端仍然可以用代理(delegate)来调用One-Way方法,但是EndIncoke()方法不会检查服务器端程序是否已经完成而直接退出。即便是服务器死机或脱机状态下异常也不会被抛出,客户端更是无法知道请求失败的原因。在一些不重要的记录日志或跟踪应用中,可以考虑采用异步One-Way调用,这样Remote method的执行情况就不会影响到其他业务代码的执行。

异步One-Way调用的实现很简单,只需要在接口定义的方法之前加上属性(attribute)[OneWay()]即可,其他程序不需要修改。

None.gifpublic abstract class  BaseRemoteObject : MarshalByRefObject
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    [OneWay()]
InBlock.gif    
public abstract
 DataSet GetRecordingsMe();
InBlock.gif    
public abstract
 DataSet GetRecordingsYou();
ExpandedBlockEnd.gif}

None.gif


注意:请始终牢记使用了异步One-Way调用方式时,客户端将忽视服务器端的返回值,并且不会去检查服务器端的运行状态。

六.小结

综合上述观点我们知道,的确,通过异步调用远程对象可以提高程序运行的效率,降低了由于某个方法的错误而造成整个应用程序崩溃的风险。

转载于:https://www.cnblogs.com/wuweizhi/archive/2007/08/16/857517.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Remoting客户是指使用远程调用技术进行通信的客户端。远程调用是一种在分布式系统中的通信方式,它允许在不同的计算机之间进行方法的调用和数据的传输。 Remoting客户通过建立与远程服务器的连接,可以像调用本地对象一样调用远程对象的方法。这样的客户端可以将请求发送给远程服务器,获得结果并将其返回给调用方。Remoting客户端可以通过网络传输数据,实现跨平台和跨语言的通信。 Remoting客户端通常通过使用远程代理(Proxy)来访问远程对象。远程代理充当了客户端和服务器之间的中间层,隐藏了底层通信的细节。客户端通过远程代理来调用远程对象的方法,而不需要了解底层的网络通信协议或者具体的通信细节。 Remoting客户端还可以通过配置文件或者编程方式来指定远程服务器的地址和端口以及其他的通信参数。这样的配置方式使得客户端可以灵活地连接到不同的远程服务器上。 在使用Remoting客户端时,需要注意网络的稳定性和安全性。网络不稳定可能造成通信中断或者性能降低,而网络安全问题可能导致数据泄露或者被篡改。因此,在设计和实现Remoting客户端时,需要考虑这些问题,并采取相应的措施。 总之,Remoting客户端是一种使用远程调用技术进行通信的客户端,它可以像调用本地对象一样调用远程对象的方法。通过使用远程代理,客户端可以隐藏底层通信的细节,并通过配置文件或者编程方式连接到远程服务器。在使用Remoting客户端时,需要注意网络的稳定性和安全性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值