2

我正在开发一个相当简单的分布式应用程序。服务器部分公开了一个名为 FuelCommands 的远程对象,它允许客户端与燃料泵交互(即授权、取消授权、重置、获取状态等)。客户端是一个 Windows 窗体应用程序,具有用于与泵交互并查看其状态的 GUI。每当客户端需要与泵进行交互时,它必须通过服务器上暴露的远程对象来完成。问题是某些 Windows 8 机器上的通信并不总是成功的。我的开发机器总是可以工作,但是在其他运行 Windows 8 的工作站上,我得到了套接字错误。具体来说,错误消息如下:

************** 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,但是,我们现在需要让它工作。

顺便说一句,我已经验证了没有防火墙,并且当客户端抛出此异常时,服务器仍在侦听正确的端口。

4

2 回答 2

7

我只能给你一个提示,在哪里寻找问题,这个问题没有提供足够的细节来缩小范围。异常的错误消息直接来自 Windows,与 .NET Framework 代码无关。或者就此而言,您的代码。从 WinError.h SDK 头文件复制/粘贴:

//
// MessageId: WSAENOTSOCK
//
// MessageText:
//
// An operation was attempted on something that is not a socket.
//
#define WSAENOTSOCK                      10038L

这是一个环境错误,还有一些其他软件会破坏你的一天。解释它是危险的,但粗略的概述是创建用于在机器之间进行通信的 TCP 套接字成功,但随后,不知何故,套接字被关闭或损坏。所以低级网络驱动程序不再将其识别为已连接的套接字。它举手并返回错误代码 10038,“它不是套接字!” .NET Framework 使用预先准备好的 Windows 错误消息将其转换为异常。

这样的错误将高度特定于您尝试运行代码的机器或位置。您可能会在另一台机器上立即获得更好的运气。不太可能,这往往是与安全相关的软件搞砸了。总是有很多它挂在套接字的末端,网络经常被恶意软件利用,因此它可以通过多层保护进行战斗。了解更多关于机器上运行的内容和站点采用的安全措施对于解决问题至关重要,请务必与本地 LAN 管理员交谈。

还有其他 SE 站点可以让您获得更好的帮助,这个站点可能非常适合 serverfault.com。请确保在您提问时可以更好地记录您的问题。

于 2014-04-06T12:37:28.197 回答
0

由于各种环境沙盒和安全性,在开发环境中工作的解决方案可能无法在生产环境中工作。因此,让我们排除这种情况,因为您已经涵盖了所有内容。

我不是插座大师。但是,以下是我将要遵循的一些方向;

一个。您是否设法提取跟踪日志?(您可以使用msdn refstackoverflow ref来执行此操作。

湾。在进行第二次调用之前,您能否确保第一次调用的所有使用过的句柄在完成后都被清理/关闭?这是为了确保您的第一个调用在进行第二个调用之前正确关闭套接字。

C。您是否在定义的时间内发送了较大的数据包。如果传输大量数据,您可以增加时间限制。

d。您还可以使用msdn ref检查服务器上的 Socket 损坏。

让我们在进一步更新此线程之前检查上述内容。

于 2014-04-03T08:42:00.113 回答