蛙蛙推荐:Remoting超时问题及初步解决方案

测试一
服务端

class Program
{
    
static void Main(string[] args)
    
{
        TcpChannel chan 
= new TcpChannel(8080);
        ChannelServices.RegisterChannel(chan,
false);
        RemotingConfiguration.RegisterWellKnownServiceType(
            
typeof(ServerObject),
            
"ServerObject", WellKnownObjectMode.Singleton);
        Console.WriteLine(
"server is start");
        Console.Read();
        chan.StopListening(
null);
        ChannelServices.UnregisterChannel(chan);
    }

}

public class ServerObject : MarshalByRefObject
{
    
public string SayHello(string name)
    
{
        Thread.Sleep(
5000);
        
return string.Format("Hello {0}", name);
    }

}


客户端

class Program
{
    
static void Main(string[] args)
    
{
        
try
        
{
            Hashtable props 
= new Hashtable();
            props[
"name"= "tcp_rem";
            props[
"timeout"= 1000;
            TcpChannel _tcpChannel 
= new TcpChannel(props, nullnull);
            ChannelServices.RegisterChannel(_tcpChannel, 
false);
            ServerObject so 
= (ServerObject)Activator.GetObject(typeof(ServerObject), "tcp://127.0.0.1:8080/ServerObject");
            Console.WriteLine(so.SayHello(
"onlytiancai"));
        }

        
catch (Exception ex)
        
{
            Console.WriteLine(ex);
        }

        Console.Read(); 
    }

}

一秒超时后客户端就会报以下错误
System.Net.Sockets.SocketException: 由于连接方在一段时间后没有正确答复或连接的主
机没有反应,连接尝试失败。
结论:tcpchannel的timeout设置对服务端处理时间过长时是起到超时作用的。

测试二
再做一个测试,把客户端连接的地址改成一个乱七八糟的远程地址。
ServerObject so = (ServerObject)Activator.GetObject(typeof(ServerObject), "tcp://192.192.192.192:8080/ServerObject");
这时候客户端会hang 10秒以上,也有可能hang更久。
结论:tcpchannel对连接网络慢或者网络层的执行时间太久是没有起到超时作用的。
测试三
再做一个测试,把我改进后的TcpClientTransportSink配置上,看看能不能起到超时的作用。
配置文件如下

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  
<system.runtime.remoting>
    
<application >
      
<channels>
        
<channel ref="tcp">
          
<clientProviders>
            
<formatter ref="binary"/>
            
<provider type="WawaSoft.Remoting.Channels.Tcp.TcpClientTransportSinkProvider,WawaRemoting" />
          
</clientProviders>
        
</channel>
      
</channels>
    
</application>
  
</system.runtime.remoting>
</configuration>

客户端代码如下

class Program
{
    
static void Main(string[] args)
    
{
        
try
        
{
            RemotingConfiguration.Configure(
"Client.exe.config"false);
            ServerObject so 
= (ServerObject)Activator.GetObject(typeof(ServerObject), "tcp://192.192.192.192:8080/ServerObject");
            Console.WriteLine(so.SayHello(
"onlytiancai"));
        }

        
catch (Exception ex)
        
{
            Console.WriteLine(ex);
        }

        Console.Read();
 
    }

}

一秒后出现如下错误提示
System.ApplicationException: connect timout

Server stack trace:
   在 WawaSoft.Remoting.Channels.RemoteConnection.CreateNewSocket(EndPoint ipEnd
Point) 位置 E:\huhao\project\RemotingTimeoutTest\WawaRemoting\Channels\RemoteCon
nection.cs:行号 89

结论:使用新的ClientTransportSink解决了因为网络问题hang太久的问题,但是目前的代码我只在connect上加了超时机制,send和receive还没有加超时机制,再有一个问题就是在同步调用上做超时必须另起个线程然后用join做超时,稳定性还得做压力测试来确认。

新的ClientTransportSink和测试代码见以下链接。
RemotingTimeoutTest.zip
以上代码大多都是反射与.net fx,所以稳定性应该还是很好的,只修改了RemoteConnection类的CreateNewSocket方法,如下
修改前

        private SocketHandler CreateNewSocket(EndPoint ipEndPoint)
        
{
            Socket socket 
= new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            
this.DisableNagleDelays(socket);
            socket.Connect(ipEndPoint);
            
this._lkgIPEndPoint = socket.RemoteEndPoint;
            
return this._socketCache.CreateSocketHandler(socket, this._machineAndPort);
        }

修改后

        
private SocketHandler CreateNewSocket(EndPoint ipEndPoint)
        
{
            Socket socket 
= new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            socket.SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.Debug, 
1);
            Exception pingException 
= null;
            DateTime now 
= DateTime.Now;

            System.Threading.Thread pingThread 
= new System.Threading.Thread(
                
delegate()
                
{
                    
try
                    
{
                        socket.Connect(ipEndPoint);
                        
//这里不用beginConnect,太麻烦
                    }

                    
catch (Exception ex)
                    
{
                        pingException 
= ex;
                    }

                }
);

            pingThread.Start();
            
if (pingThread.Join(1000)){
                
if (pingException == null)
                
{
                    
return this._socketCache.CreateSocketHandler(socket, this._machineAndPort);
                }

                
else{throw pingException;}
            }

            
throw new ApplicationException("connect timout");
        }
改进;超时的部分想办法不用join事先,用一个waithandle实现。
posted @ 2007-12-28 21:00  蛙蛙王子  Views(5944)  Comments(10Edit  收藏  举报