0

サーバー システムのラベルにアクセスするために C# リモーティングを使用しています。そのラベルのテキストは、クライアント システムのボタンをクリックすることで変更されます。RemoteObject という名前のクラス ライブラリでリモート可能オブジェクトを作成し、このクラス ライブラリの参照をクライアント システムとサーバー システムの両方に追加しましたが、サーバー システムとクライアント システムの両方をデバッグするときに、「各ソケット アドレスの使用は 1 つだけ (プロトコル/ネットワーク アドレス/ポート) は通常許可されます」

この問題を修正するために私を助けてください..

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();
        }
    }
}

この例外の解決策をできるだけ早く教えてください。

4

1 に答える 1

3

問題は、Class1.setTextメソッドが新しいを作成することのようServerClassです。のインスタンスを作成し、Class1リモーティングを介して利用できるようにするのはServerClass、おそらく、setTextメソッドがリモートで呼び出されるまでにServerClass、のインスタンスが1つあるため、2つ目のインスタンスが作成されることを意味します。 。

これは、ServerClassコンストラクター内のすべてのコードが2回実行されることを意味します。TcpChannel2回目の実行では、ポート30000に新しいものを2回登録しようとします。最初に作成したチャネルはすでに実行されているため、説明したエラーが発生します。

ServerClassコンストラクターにブレークポイントを設定してみてください。2回実行されると思います。1回目はエラーが発生しませんが、2回目はエラーが発生します。

ServerClass解決策は、そのsetTextメソッドで新しいものを作成しないようにすることです。リモーティング呼び出しがすでに画面に表示されているフォームのラベルを変更することになっている場合は、既存のServerClassインスタンスへの参照をインスタンスに渡す必要がありClass1ます。(たとえば、Class1コンストラクターに引数としてaを取り、ServerClassそれをフィールドに格納します。で新しいコンストラクターを作成する代わりに、それを使用しsetTextます。)

ちなみに、リモーティングは多かれ少なかれ非推奨です。WCFは、最近の.NETでリモートアクセスを行うための通常の方法です。それまたはWebAPIのいずれか。

更新: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 に答える