C#远程处理异常:每个套接字地址(协议/网络地址/端口)通常只允许使用一次
本文关键字:端口 网络地址 一次 许使用 地址 处理 程处理 异常 套接字 协议 | 更新日期: 2023-09-27 17:58:08
我使用C#远程处理访问服务器系统上的标签,单击客户端系统上的按钮即可更改该标签的文本。我在一个名为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();
}
}
}
请有人尽快帮我解决这个异常。
问题似乎是Class1.setText
方法创建了一个新的ServerClass
。现在,由于创建Class1
实例并通过远程处理使其可用的是ServerClass
,这可能意味着当远程调用setText
方法时,您已经有了一个ServerClass
实例,因此最终将创建第二个。
这意味着ServerClass
构造函数中的所有代码都会运行两次。第二次运行时,它将第二次尝试在端口30000上注册新的TcpChannel
。由于你第一次创建的频道已经在运行,你会得到你描述的错误。
试着在ServerClass
构造函数上设置一个断点,我希望您会看到它运行两次。第一次你不会得到错误,但第二次你会得到。
解决方案是避免在setText
方法中创建新的ServerClass
。如果您的意图是远程处理调用应该修改屏幕上已经存在的表单中的标签,那么您需要将对现有ServerClass
实例的引用传递给Class1
实例。(例如,使Class1
构造函数将ServerClass
作为参数,并将其存储在字段中。使用它而不是在setText
中构造新的参数。)
顺便说一句,远程处理或多或少是不受欢迎的。WCF是目前在.NET中进行远程访问的常用方法。或者是Web API。
更新:013/02/12
抱歉,我已经有一段时间没有使用远程处理了,因为正如我所提到的,远程处理已被弃用,您不应该使用它
所以,我忘记了一件事:Remoting并没有让注册一个特定的众所周知的实例变得简单-你注册了众所周知的类型,Remoting想为你构建类型。因此,您需要想出其他方法将ServerClass
传递给Class1
。
例如:
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