0

我正在使用 C# 远程访问服务器系统上的标签,并且该标签的文本将通过单击客户端系统上的按钮来更改。我在一个名为 RemoteObject 的类库中创建了一个远程对象,并将这个类库的引用添加到客户端和服务器系统,但是在调试服务器系统和客户端系统时,我收到异常“每个套接字地址只有一次使用(协议/网络地址/端口)通常是允许的”

请帮助我解决这个问题..

远程对象.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();
        }
    }
}

请有人尽快帮助我解决此异常。

4

1 回答 1

3

看起来问题在于您的Class1.setText方法创建了一个新的ServerClass. 现在,由于创建 的实例并通过远程Class1处理使其可用的东西ServerClass是.setTextServerClass

这意味着ServerClass构造函数中的所有代码都会运行两次。第二次运行时,它将第二次尝试TcpChannel在端口 30000 上注册一个新的。由于您第一次创建的频道已经在运行,您会收到您描述的错误。

尝试在您的构造函数上放置一个断点ServerClass,我希望您会看到它运行两次。第一次你不会得到错误,但第二次你会。

解决方案是避免ServerClass在该setText方法中创建新的。如果您的意图是远程调用应该修改已经在屏幕上的表单中的标签,那么您需要将对现有ServerClass实例的引用传递给Class1实例。(例如,让Class1构造函数将 aServerClass作为参数,并将其存储在一个字段中。使用它而不是在 中构造一个新的setText。)

顺便说一句,远程处理或多或少已被弃用。WCF 是当今在 .NET 中进行远程访问的常用方法。无论是那个还是 Web API。

更新:013/02/12

抱歉,我使用 Remoting 已经有一段时间了,因为正如我所提到的,Remoting 已被弃用,您不应该使用它!

所以,我忘记了: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

于 2013-02-07T18:17:20.587 回答