我正在使用C#remoting访问服务器系统上的Label,并且只需单击客户端系统上的按钮即可更改该标签的文本。我在命名RemoteObject的类库中创建了一个远程对象,并将此类库的引用添加到客户端和服务器系统,但在调试服务器系统和客户端系统时,我得到异常“每个套接字地址只有一次使用(协议/网络地址/端口通常是允许的“
请帮我解决这个问题。
RemotableObject.dll
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace RemoteObject
{
public class Class1 : MarshalByRefObject
{
public Class1()
{
}
public void setText()
{
ServerClass bs = new ServerClass();
Label lbl = bs.Controls["label1"] as Label;
lbl.Text = "New Text";
}
}
}
服务器端代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RemoteObject;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Server
{
public partial class ServerClass : Form
{
private Class1 myremoteobject;
public ServerClass()
{
InitializeComponent();
myremoteobject = new Class1();
TcpChannel channel = new TcpChannel(30000);
ChannelServices.RegisterChannel(channel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Class1), "CSBU", WellKnownObjectMode.SingleCall);
}
}
}
客户端代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using RemoteObject;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
namespace Client
{
public partial class ClientClass : Form
{
private Class1 remoteobject = new Class1();
public ClientClass()
{
InitializeComponent();
TcpChannel chan = new TcpChannel();
ChannelServices.RegisterChannel(chan,true);
remoteobject = (Class1)Activator.GetObject(typeof(Class1), "tcp://localhost:30000/CSBU");
}
private void changeTextBtn_Click(object sender, EventArgs e)
{
remoteobject.setText();
}
}
}
请尽快帮助我解决此异常的解决方案。
答案 0 :(得分:3)
看起来问题是您的Class1.setText
方法会创建新的ServerClass
。现在,由于创建Class1
实例并通过远程处理使其可用的内容为ServerClass
,大概这意味着当您远程调用setText
方法时,您已经已经有一个ServerClass
的实例,所以最终会创建第二个。
这意味着ServerClass
构造函数中的所有代码都会运行两次。第二次运行时,它将尝试第二次在端口30000上注册新的TcpChannel
。由于您第一次创建的频道已经在运行,因此您会收到您描述的错误。
尝试在ServerClass
构造函数上放置一个断点,我希望你会看到它运行两次。第一次你不会得到错误,但第二次你会。
解决方案是避免在ServerClass
方法中创建新的setText
。如果您的意图是远程调用应该修改屏幕上已有的表单中的标签,那么您需要将对现有ServerClass
实例的引用传递给Class1
实例。 (例如,让Class1
构造函数将ServerClass
作为参数,并将其存储在一个字段中。使用它而不是在setText
中构建一个新的。)
顺便说一句,远程处理或多或少已被弃用。 WCF是目前在.NET中进行远程访问的常用方法。无论是那个还是Web API。
<强>更新:013/02/12 强>
很抱歉,我使用Remoting已经有一段时间了,因为正如我所提到的, Remoting已被弃用,您不应该使用它!
所以,我忘了这件事:Remoting并不能直接注册一个众所周知的实例 - 你注册了众所周知的类型并且Remoting想要构建你的类型。因此,您需要提出一些将ServerClass
传递给Class1
的方法。
E.g:
public class Class1 : MarshalByRefObject
{
public static ServerClass MyServer { get; set; }
public void setText()
{
ServerClass bs = MyServer;
Label lbl = bs.Controls["label1"] as Label;
lbl.Text = "New Text";
}
}
然后您的ServerClass
变为:
public partial class ServerClass : Form
{
public ServerClass()
{
InitializeComponent();
Class1.MyServer = this;
TcpChannel channel = new TcpChannel(30000);
ChannelServices.RegisterChannel(channel, true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Class1), "CSBU", WellKnownObjectMode.SingleCall);
}
}
然后你将点击你的下一个错误InvalidOperationException
,错误“跨线程操作无效:控制'label1'从除创建它之外的线程访问。”
这是因为远程处理调用进入工作线程,但您只能从其拥有的UI线程更新Windows窗体UI元素。
同样,请不要使用这个,因为,正如我之前提到的那样重新开始远程操作并且您不应该使用它;使用WCF 但是对于它的价值,这里是如何处理它:
public void setText()
{
MyServer.BeginInvoke((Action) setTextOnUiThread);
}
private void setTextOnUiThread()
{
ServerClass bs = MyServer;
Label lbl = bs.Controls["label1"] as Label;
lbl.Text = "New Text";
}
这应该有用。
又一次, 不要这样做 - 重新启动不再是当前的技术。查看WCF INSTEAD