Created
January 22, 2021 12:09
-
-
Save yallie/af9b4d4936820d67377ef2780b867cf3 to your computer and use it in GitHub Desktop.
TcpEx: server-side connection locking issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// http://zyan.com.de | |
// | |
// Compile using: csc test.cs /r:Zyan.Communication.dll | |
// | |
// Start up test.exe several times. | |
// The first process is the server, the rest are clients. | |
// | |
using System; | |
using System.Collections.Concurrent; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Reflection; | |
using System.Threading; | |
using Zyan.Communication; | |
using Zyan.Communication.Protocols.Tcp; | |
class GlobalLockSuspicionTest | |
{ | |
static void Main() | |
{ | |
try | |
{ | |
StartServer(); | |
} | |
catch | |
{ | |
StartClient(); | |
} | |
} | |
// ------------ Server code -------------- | |
static void StartServer() | |
{ | |
var proto = new TcpDuplexServerProtocolSetup(4321); | |
using (var host = new ZyanComponentHost(nameof(GlobalLockSuspicionTest), proto)) | |
{ | |
host.RegisterComponent<IService, Service>(); | |
host.SubscriptionCanceled += (s, e) => Console.WriteLine("Subscription canceled: {0}.{1}", e.ComponentType, e.DelegateMemberName); | |
Console.WriteLine("Server started. Press ENTER to quit."); | |
Console.Title = nameof(GlobalLockSuspicionTest) + " - Server #" + Process.GetCurrentProcess().Id; | |
var ps = new TcpDuplexClientProtocolSetup(); | |
ThreadPool.QueueUserWorkItem(x => TryExternalConnection(ps, "example.com", 4322)); | |
ThreadPool.QueueUserWorkItem(x => TryExternalConnection(ps, "example.com", 4323)); | |
ThreadPool.QueueUserWorkItem(x => TryExternalConnection(ps, "example.com", 4324)); | |
Console.ReadLine(); | |
} | |
} | |
static void TryExternalConnection(TcpDuplexClientProtocolSetup proto, string host, int port) | |
{ | |
var url = proto.FormatUrl(host, port, nameof(GlobalLockSuspicionTest)); | |
try | |
{ | |
new ZyanConnection(url); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("Connection to {0} failed. Exception: {1}, Error message: {2}", url, ex.GetType(), ex.Message); | |
} | |
} | |
public class Service : IService | |
{ | |
private static int Counter { get; set; } | |
public string Hello() | |
{ | |
Counter++; | |
Console.WriteLine("Called: " + Counter); | |
return "Hello: " + Counter; | |
} | |
public void ExternalConnection() | |
{ | |
try | |
{ | |
var proto = new TcpDuplexClientProtocolSetup(); | |
var url = proto.FormatUrl("example.com", 4321, nameof(GlobalLockSuspicionTest)); | |
new ZyanConnection(url); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("Connection failed. Error message: {0}", ex.Message); | |
throw; | |
} | |
} | |
} | |
// ------------ Shared code -------------- | |
public interface IService | |
{ | |
string Hello(); | |
void ExternalConnection(); | |
} | |
// ------------ Client code -------------- | |
static void StartClient() | |
{ | |
Console.Title = nameof(GlobalLockSuspicionTest) + " - Client #" + Process.GetCurrentProcess().Id; | |
var proto = new TcpDuplexClientProtocolSetup(); | |
var url = proto.FormatUrl("localhost", 4321, nameof(GlobalLockSuspicionTest)); | |
Console.WriteLine("Connecting to {0}...", url); | |
var sw = Stopwatch.StartNew(); | |
using (var conn = new ZyanConnection(url)) | |
{ | |
sw.Stop(); | |
Console.WriteLine("Connected. Time elapsed: {0}", sw.Elapsed); | |
var proxy = conn.CreateProxy<IService>(); | |
Console.WriteLine("Client started. Commands: H = hello, P = poll, C = connect to example.com, S = ask server to connect to example.com, ^C to quit."); | |
while (true) | |
{ | |
var command = Console.ReadLine(); | |
switch (command.ToLower().FirstOrDefault()) | |
{ | |
case 'h': | |
var result = proxy.Hello(); | |
Console.WriteLine("Server reply: {0}", result); | |
break; | |
case 'p': | |
Console.WriteLine("Polling..."); | |
ThreadPool.QueueUserWorkItem(x => Poll(proxy)); | |
break; | |
case 'c': | |
Console.WriteLine("Connecting to example.com..."); | |
ThreadPool.QueueUserWorkItem(x => Connect()); | |
break; | |
case 's': | |
Console.WriteLine("Asking server to connect to example.com..."); | |
ThreadPool.QueueUserWorkItem(x => ExternalConnection(proxy)); | |
break; | |
default: | |
Console.WriteLine("Unknown command"); | |
break; | |
} | |
} | |
} | |
} | |
static void ExternalConnection(IService proxy) | |
{ | |
try | |
{ | |
proxy.ExternalConnection(); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("Connection failed. Error message: {0}", ex.Message); | |
} | |
} | |
static void Connect() | |
{ | |
try | |
{ | |
var proto = new TcpDuplexClientProtocolSetup(); | |
var url = proto.FormatUrl("example.com", 4321, nameof(GlobalLockSuspicionTest)); | |
new ZyanConnection(url); | |
} | |
catch (Exception ex) | |
{ | |
Console.WriteLine("Connection failed. Error message: {0}", ex.Message); | |
} | |
} | |
static void Poll(IService proxy) | |
{ | |
for (var i = 0; i < 100; i++) | |
{ | |
try | |
{ | |
Thread.Sleep(TimeSpan.FromSeconds(1)); | |
Console.WriteLine("Iteration #{0}: server reply: {1}", i, proxy.Hello()); | |
} | |
catch (Exception ex) | |
{ | |
while (ex is TargetInvocationException && ex.InnerException != null) | |
{ | |
ex = ex.InnerException; | |
} | |
Console.WriteLine("Polling failure: should never happen. Error message: {0}", ex.Message); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
On Zyan v2.14 and below, the client cannot connect to server until the server fails to connect to example.com.
Related issue: zyanfx/Zyan#87