Remoting獲取客戶端外網IP
領導又有了新的要求,在用戶登錄的時候記錄用戶的IP地址和機器名。
在C#中,獲取本機的機器名和IP地址,甚至網卡的MAC地址,都是很簡單的事情,有封裝好的類和方法可以使用,但現在遇到的問題是,如果客戶端的機器是在另一個局域網內,那網卡的IP地址是局域網地址,這對我們來說沒有用,這就要記錄外網的IP,但是Remoting沒有現成的方法來獲取客戶端的IP,google了一下,網上比較多的是采用在Server端注冊自定義Server Channel Sink,通過Transport Headers來獲取Request的IP。于是我就用了別人寫好的現成的Sink,以及學習了Rickie的一篇《如何定制Sink擴展.Net Remoting功能》。
Rickie的文章:http://www.cnblogs.com/rickie/archive/2004/10/21/54891.html
自定義的Sink的類:http://blog.joycode.com/tingwang/articles/39610.aspx
public class ClientIPServerSinkProvider : IServerChannelSinkProvider
{
private IServerChannelSinkProvider next = null;
public ClientIPServerSinkProvider()
{
}
public ClientIPServerSinkProvider(IDictionary properties, ICollection providerData)
{
}
public void GetChannelData(IChannelDataStore channelData)
{
}
public IServerChannelSink CreateSink(IChannelReceiver channel)
{
IServerChannelSink nextSink = null;
if (next != null)
{
nextSink = next.CreateSink(channel);
}
return new ClientIPServerSink(nextSink);
}
public IServerChannelSinkProvider Next
{
get { return next; }
set { next = value; }
}
}
public class ClientIPServerSink : BaseChannelObjectWithProperties, IServerChannelSink, IChannelSinkBase
{
private IServerChannelSink _next;
public ClientIPServerSink(IServerChannelSink next)
{
_next = next;
}
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state, IMessage msg, ITransportHeaders headers, Stream stream)
{
}
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state, IMessage msg, ITransportHeaders headers)
{
return null;
}
public System.Runtime.Remoting.Channels.ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
{
if (_next != null)
{
IPAddress ip = requestHeaders[CommonTransportKeys.IPAddress] as IPAddress;
Console.WriteLine(ip.ToString());
CallContext.SetData("ClientIPAddress", ip);
ServerProcessing spres = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
return spres;
}
else
{
responseMsg = null;
responseHeaders = null;
responseStream = null;
return new ServerProcessing();
}
}
public IServerChannelSink NextChannelSink
{
get { return _next; }
set { _next = value; }
}
}
在Remoting的服務端加入了這個類后,由于我是在IIS上承載的Remoting,所以就需要修改Web.config文件來啟用這個Sink。
<channels>
<channel port="8000" ref="http" name ="httpServer">
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
<formatter ref="binary" typeFilterLevel="Full"/>
<provider type="Galaxy.Server.Remoting.ClientIPServerSinkProvider, Galaxy.Server.Remoting" />
</serverProviders>
</channel>
<channel port="9000" ref="tcp" name ="tcpServer">
<serverProviders>
<formatter ref="soap" typeFilterLevel="Full"/>
<formatter ref="binary" typeFilterLevel="Full"/>
<provider type="Galaxy.Server.Remoting.ClientIPServerSinkProvider, Galaxy.Server.Remoting" />
</serverProviders>
</channel>
</channels>
做完這個后,以后只需在服務器端通過 ((System.Net.IPAddress)System.Runtime.Remoting.Messaging.CallContext.GetData("ClientIPAddress")).ToString() 就可以獲取Request的IP了。


浙公网安备 33010602011771号