2010-05-12 25 views
7

Chúng tôi đang gặp vấn đề lạ với .NET Remoting. Về cơ bản, chúng tôi có một máy chủ mà đăng ký hai TcpChannels với ChannelServices.RegisterChannel():.NET Tự động chuyển kênh bằng chính nó

  1. Một lắng nghe trên cổng 50000
  2. một khác lắng nghe trên cổng 15000.

Sau đó chúng tôi có một khách hàng rằng đăng ký một TcpChannel để có thể giao tiếp với máy chủ. Chúng tôi lấy một một đối tượng từ máy chủ bằng cách gọi Activator.GetObject() với URI

"tcp: // serverip: 50000/ObjectName"

và điều này hoạt động tốt, client kết nối đến máy chủ trên cổng 50000 và lấy vật thể.

Tuy nhiên, khi chúng tôi bắt đầu gọi các phương thức trên đối tượng đó, kết nối với kênh trên cổng 50000 bị ngắt và kết nối mới được thực hiện với kênh trên cổng 15000 tự động. Điều này đặt ra một vấn đề thực sự đối với chúng tôi vì chúng tôi không muốn lưu lượng trên cổng 15000 vì kênh đó có thể không bị ràng buộc với cùng một bộ điều hợp mạng như cổng 50000 trên máy chủ hoặc cổng đó có thể không mở trong tường lửa, các cuộc gọi từ xa để thất bại một cách tự nhiên. Điều này là rất lạ đối với chúng tôi vì khách hàng không có kiến ​​thức trong mã của chúng tôi rằng có tồn tại một kênh khác trên máy chủ trên cổng 15000 hoặc IP mà nó nghe, nhưng nó cố gắng kết nối với nó.

Bất kỳ giúp đỡ về vấn đề này được đánh giá rất nhiều,

Cảm ơn, Casper

Đây là mã mà bộ lên một trong những kênh máy chủ, là thường trên cổng 50000:

IDictionary props = new Hashtable(); 

props["port"] = m_tcpPort; 
props["name"] = String.Empty; 


BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

m_tcpChannel = new TcpServerChannel(props, /*clientProvider,*/ serverProvider); 
ChannelServices.RegisterChannel(m_tcpChannel, false); 

m_wellKnownObjRef = RemotingServices.Marshal(this, "[email protected]" + m_tcpPort.ToString()); 

Đây là mã thiết lập kênh máy chủ khác, thường trên cổng 15000:

IDictionary props = new Hashtable(); 

props["name"] = String.Empty; 
props["port"] = ip.Port; 
props["bindTo"] = ip.Address.ToString();      
props["timeout"] = REMOTING_TIMEOUT; // Timeout to prevent hung remoting calls. 

if (!String.IsNullOrEmpty(machineName)) 
{ 
    props["machineName"] = machineName; 
} 

    BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
    serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

    BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

    m_channel = new TcpChannel(props, clientProvider, serverProvider); 
    ChannelServices.RegisterChannel(m_channel, false); 

    m_objRef = RemotingServices.Marshal(this, QueueName); // Queuename is a GUID. 

Đây là mã trong các khách hàng kết nối với các kênh máy chủ đầu tiên, một trong đó là thường trên cổng 50000:

IDictionary props = new Hashtable(); 

props["port"] = 0; 

RemotingConfiguration.CustomErrorsMode = CustomErrorsModes.Off; 

BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider(); 
serverProvider.TypeFilterLevel = System.Runtime.Serialization.Formatters.TypeFilterLevel.Full; 

BinaryClientFormatterSinkProvider clientProvider = new BinaryClientFormatterSinkProvider(); 

m_tcpChannel = new TcpClientChannel(props, clientProvider/*, serverProvider*/); 
ChannelServices.RegisterChannel(m_tcpChannel, false); 

string address = "tcp://" + profile.RemoteIP + ":" + profile.RemoteTCP; 

m_server = (Kernel)Activator.GetObject(typeof(Server), address + "/[email protected]" + port); 
+0

Nếu bạn có bất kỳ cấu hình kênh nào trong tệp app.config thì hãy thêm nó vào câu hỏi của bạn. –

+0

Cảm ơn bạn đã trả lời. Không có cấu hình app.config vì tất cả đều được thiết lập trong mã. Tôi đã thêm mã đó vào câu hỏi ngay bây giờ. – Casper

Trả lời

7

Chúng tôi đã ghi lại một trường hợp hỗ trợ với Microsoft về điều này và rõ ràng, những gì chúng tôi đang làm ở đây không được hỗ trợ bởi .NET Remoting. Bạn chỉ được phép đăng ký một kênh của từng loại trong một AppDomain. Điều Remoting làm là nó gửi lại URI của đối tượng tới máy khách để cho nó biết nó có thể truy cập đối tượng đang được đề cập đến ở đâu. Khi nó xuất hiện, nó xem xét các kênh đã đăng ký ở cuối máy chủ và sử dụng kênh đầu tiên mà nó tìm thấy ở đó khớp với loại được yêu cầu (trong trường hợp của chúng ta là: Tcp). Nói cách khác, nó sẽ sử dụng bất kỳ kênh nào xảy ra để được đăng ký trước. Nó không quan tâm gì về những gì kênh khách hàng đã kết nối trên.

Giải pháp là triển khai IClientChannelSinkProvider của chính bạn ở phía máy khách. Khi bạn thực hiện phương thức CreateSink(), bạn có thể chọn url nào bạn muốn máy khách kết nối khi bạn tạo bồn rửa để sử dụng.

+0

Cảm ơn bạn đã giải thích! Chúng tôi đã tìm kiếm khá lâu tại sao máy chủ của chúng tôi không phải lúc nào cũng phản hồi đúng khi tạo kênh cho nhiều NIC. Lý do và giải pháp như bạn đã mô tả. – Philippe

0

tôi đã stuggle với những "backlinked" cổng cũng; Tôi nghĩ rằng nó sẽ chỉ xảy ra nếu máy chủ muốn gửi một cái gì đó trở lại (ngay cả trong một sự kiện-thủ tục). Bởi vì tôi luôn gặp vấn đề với tường lửa, tôi đã chuyển sang GenuineChannels (mặc dù tôi nghĩ rằng đó là một chút lỗi thời).

+0

Từ xa chính nó bây giờ đã lỗi thời, thay thế bằng WCF. –

+0

Thật vậy. Mã chúng tôi đang gặp phải sự cố đã được viết lại khi .NET Framework 1.0 vừa ra mắt. Không ai có vẻ đã nhận thấy vấn đề này trong suốt cả năm cho đến khi một trong những khách hàng của chúng tôi thử ràng buộc hai kênh này với các bộ điều hợp mạng khác nhau. – Casper