我正在研究一個相當直接的分佈式應用程序。服務器部分暴露名爲FuelCommands的遠程對象,該對象允許客戶端與燃油泵進行交互(即授權,取消授權,重置,獲取狀態等)。客戶端是一個Windows窗體應用程序,它具有與泵交互並查看其狀態的GUI。客戶端需要與泵進行交互時,必須通過服務器上暴露的遠程對象執行此操作。問題在於,某些Windows 8計算機上的通信並不總是成功。我的開發機器總能正常工作,但在運行Windows 8的其他工作站上,我遇到套接字錯誤。具體而言,錯誤消息下面是:嘗試調用C#中的遠程對象時出現Socket問題#
************** Exception Text **************
System.Net.Sockets.SocketException: An operation was attempted on something that is not a socket
Server stack trace:
at System.Net.Sockets.Socket.Send(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Runtime.Remoting.Channels.SocketStream.Write(Byte[] buffer, Int32 offset, Int32 count)
at System.Runtime.Remoting.Channels.ChunkedMemoryStream.WriteTo(Stream stream)
at System.Runtime.Remoting.Channels.Tcp.TcpClientSocketHandler.GetRequestStream(IMessage msg, Int32 contentLength, ITransportHeaders headers)
at System.Runtime.Remoting.Channels.Tcp.TcpClientSocketHandler.SendRequest(IMessage msg, ITransportHeaders headers, Stream contentStream)
at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.SendRequestWithRetry(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream)
at System.Runtime.Remoting.Channels.Tcp.TcpClientTransportSink.ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, ITransportHeaders& responseHeaders, Stream& responseStream)
at System.Runtime.Remoting.Channels.BinaryClientFormatterSink.SyncProcessMessage(IMessage msg)
下面,是應表現出遠程對象是如何暴露和訪問一些相關的代碼段。有人可以看看並告訴我爲什麼我可能會得到這個異常?
服務器應用
// Expose remote object
TcpChannel tcpChan = new TcpChannel(8090);
ChannelServices.RegisterChannel(tcpChan, false);
FuelCommands fuelcommands = new FuelCommands();
ObjRef o = RemotingServices.Marshal(fuelcommands, "objecturi");
客戶
// Main form contains a fuel panel which contains a static reference to remote object
public static FDServer.FuelCommands fuelClass = null;
//Initialize the fuelClass object via the remote Fuel Server
//All code below is executed in Load event for this control which sits on main form for client
RemotingConfiguration.RegisterWellKnownClientType(Type.GetType("FDServer.FuelCommands, Fuel_Server"), "tcp://localhost:8090/objecturi");
fuelClass = new FuelCommands();
//fuelClass = (FDServer.FuelCommands)Activator.GetObject(typeof(FDServer.FuelCommands), GlobalSettings.FdProtocol + "://" + GlobalSettings.FdServerAddress + ":" + GlobalSettings.FdPortNum.ToString() + "/" + typeof(FDServer.FuelCommands).ToString());
//Test connection
fdServerConnGood = true;
// First use of remote object works without any issues
bool testConnection = fuelClass.aliveCheck();
// Client contains a bank of PumpWidget controls which are objects that encapsulate information about each pump
// This is where remote calls are failing with exception above
// The code below is executed from within a getStatus method every 2000ms fired by timer control
try
{
tempStatus = FuelPanel.fuelClass.get_FuelingPositionInformation(pumpNumberInt, 1); // FAILS with socket exception
}
catch (System.Net.Sockets.SocketException socketException)
{
logger.Error(socketException.Message);
throw;
}
總之,我很困惑的原因有兩個。首先,我不明白爲什麼每次在我的開發機器上工作,這是與目標機器相同的操作系統(Windows 8)。其次,我不明白爲什麼第一次調用遠程對象,第二次失敗。它是訪問遠程對象的不同類。 FuelPanel基本上是一個位於主窗體上的用戶控件。 PumpWidget(產生套接字錯誤的對象)位於FuelPanel上。任何人都可以給我一些提示?我知道應用程序最終應該轉向WCF,但是,我們需要現在就開始工作。
順便說一句,我已經證實,沒有防火牆的方式,並且當客戶端拋出此異常時,服務器仍在偵聽正確的端口。
它可能是一個底層的套接字描述符(它是一個不透明的句柄),當套接字實際上已關閉時,它被重用「原樣」。也許是由於你的代碼中存在靜態的東西,比如fuelClass,或者/和一個多線程問題。沒有完整的複製代碼很難說。 –
@Grasshopper如果你有一個複製問題的小完整例子,這將會有所幫助。 –