Weird behavior with socketIO and .NET clients - c#

I'm using socketIO on node and hook it up with the front-end, they work fine
Now I want to push things further
I want my .net clients (UWP) communicate with the socketIO
But there is something really weird happening
At first I tested and it run just fine, the second time I run the client
It started to send twice or more messages when I only send one. And I realize that if I open the .net client first and the server later this won't happen, but when I shut my clients down (while the server still running) this bug started to happen.
public sealed partial class StuffDetail : Page
{
Socket socket = IO.Socket("ws://localhost:8888");
ObservableCollection<SocketMessage> InCommingData { get; set; } = new ObservableCollection<SocketMessage>();
public StuffDetail()
{
this.InitializeComponent();
DisconnectState();
SetSocket();
ChatWindow.ItemsSource = InCommingData;
}
private void DisconnectState()
{
ReceivedText.Text = "Not Connect";
}
private void SetSocket()
{
socket.Connect();
ReceivedText.Text = "Connect Completed";
socket.On("chat", async (data) =>
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var IncomeMess = JsonConvert.DeserializeObject<SocketMessage>(data.ToString());
InCommingData.Add(IncomeMess);
});
});
}
private void Send(object sender, RoutedEventArgs e)
{
var message = new SocketMessage()
{
message = MessTextBox.Text,
handle = "From Beta User"
};
socket.Emit("chat", JsonConvert.SerializeObject(message));
}
}

Related

How do I correctly shutdown all gRPC channels and connections?

I have a Unity game, implementing a gRPC client that is generated from the protobuf compiler. While the game is running, I can receive all the data I need from the streaming call, and interact with that data perfectly. The issue I have is in the shutdown of the game and cleanup of the gRPC client/channel (I believe).
When I attempt to exit play mode, it retains a connection to the server, and the Unity editor hangs (presumably waiting for the PlotManager.OnDisable code ShutdownAsync.Wait() call).
The only way to remedy this at the moment is to shutdown my server process, which causes the connection to be lost, and Unity editor returns to normal functionality.
How can I best manage the lifecycle of the Client / Channel to ensure the Unity game cleans up correctly?
public class PlotRenderer : MonoBehaviour
{
private bool _subscribed = false;
private CancellationTokenSource _cancellationToken;
public async void Subscribe()
{
this._subscribed = true;
this._cancellationToken = new CancellationTokenSource();
using (var call = PlotManager.s.Client.SubscribePlotCellUpdates(
new PrimaryKey { Id = this._plot.Id },
cancellationToken: this._cancellationToken.Token))
{
var responseReader = Task.Run(async () =>
{
while (this._subscribed
&& await call.ResponseStream.MoveNext(this._cancellationToken.Token))
{
var cell = call.ResponseStream.Current;
// Add cell to a list.
}
this.Unsubscribe();
});
await responseReader;
}
}
public void Unsubscribe()
{
if (this._cancellationToken != null)
this._cancellationToken.Cancel();
this._subscribed = false;
}
// Called when the object is being destroyed (game stopping)
private void OnDestroy()
{
this.Unsubscribe();
}
}
Relevant code from my PlotManager class is:
public class PlotManager
{
public static PlotManager s;
public Plotty.PlottyClient Client;
public Channel Channel;
public string Address = "127.0.0.1:8075"
// Called when object is created and enabled in game
private void OnEnable()
{
this.Channel = new Channel(this.Address, ChannelCredentials.Insecure);
return new Plotty.PlottyClient(this.Channel);
}
// Called when the object is being destroyed (game stopping)
private void OnDisable()
{
this.Channel.ShutdownAsync().Wait();
this.Channel = null;
this.Client = null;
}
}

Sending information from windows phone 8 to Pc Window 7 windows forms

I am trying to send information from my windows phone to the computer. I read some where that the usb cable is treated like a Ethernet cable. I created a server and a client(Phone is client) to try to send information. The program sends a message every time it presses enter.
Client Side
public sealed partial class MainPage : Page
{
private bool Connected;
public MainPage()
{
this.InitializeComponent();
this.NavigationCacheMode = NavigationCacheMode.Required;
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.
/// This parameter is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
// TODO: Prepare page for display here.
// TODO: If your application contains multiple pages, ensure that you are
// handling the hardware Back button by registering for the
// Windows.Phone.UI.Input.HardwareButtons.BackPressed event.
// If you are using the NavigationHelper provided by some templates,
// this event is handled for you.
}
private DatagramSocket dataGramSocket = new DatagramSocket();
private DataWriter socketWriter;
private bool messageSent;
private static string port = "138";
private void Grid_Loaded(object sender, RoutedEventArgs e)
{
dataGramSocket.MessageReceived += dataGramSocket_MessageReceived;
StartListener();
}
void dataGramSocket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
}
private async void StartListener()
{
string IpHostname = "127.0.0.1";
var IpAdresses = NetworkInformation.GetHostNames();
for (int i = 0; i < IpAdresses.Count; i++)
{
if (IpAdresses[i].IPInformation != null)
{
if (IpAdresses[i].IPInformation.NetworkAdapter.IanaInterfaceType == 6 && IpAdresses[i].DisplayName != null)
{
IpHostname = IpAdresses[i].DisplayName;
break;
}
else if (IpAdresses[i].IPInformation.NetworkAdapter.IanaInterfaceType == 71 && IpAdresses[i].DisplayName != null)
{
IpHostname = IpAdresses[i].DisplayName;
break;
}
}
}
HostName host = new HostName(IpHostname);
//EndpointPair endpoint = new EndpointPair(localHostName,)
await dataGramSocket.BindServiceNameAsync(port);
await dataGramSocket.ConnectAsync(host, port);
socketWriter = new DataWriter(dataGramSocket.OutputStream);
Connected = true;
}
private async void SendPacket()
{
await socketWriter.StoreAsync();
messageSent = true;
}
private void TextBox1_KeyDown(object sender, KeyRoutedEventArgs e)
{
if(e.Key == Windows.System.VirtualKey.Enter)
{
SendMessage(textBox1.Text);
}
}
private void SendMessage(string message)
{
socketWriter.WriteString(message);
SendPacket();
textBox1.Text = "";
}
}
}
Server Side
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static int port = 138;
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
Task.Factory.StartNew(() =>
{
var dataStream = new MemoryStream(1024);
var udpClient = new UdpClient(port);
while (true)
{
if (udpClient.Available > 0)
{
udpClient.BeginReceive(ar =>
{
var clientEndPoint = new IPEndPoint(IPAddress.Any, port);
var bytesReceived = udpClient.EndReceive(ar, ref clientEndPoint);
dataStream.Write(bytesReceived, 0, bytesReceived.Length);
if (bytesReceived.Length > 0)
{
UpdateUI(Encoding.UTF8.GetString(bytesReceived));
UpdateUI(Encoding.ASCII.GetString(bytesReceived));
}
}, null);
}
Thread.Sleep(1);
}
}, _cancellationTokenSource.Token);
}
private void UpdateUI(string message)
{
this.Invoke(new MethodInvoker(delegate
{
this.textBox1.Text += message + Environment.NewLine;
}));
}
private void button1_Click_1(object sender, EventArgs e)
{
byte[] message = Encoding.UTF8.GetBytes(textBox2.Text);
using (var udpClient = new UdpClient())
{
udpClient.Send(message, message.Length, new IPEndPoint(IPAddress.Loopback, port));
}
textBox2.Clear();
}
}
}
The information isn't connecting somewhere in the middle. On both sides nothing breaks. When I test the form by sending information to the loopback it works. I don't know why the information is not reaching the other side. Can you please tell me if I am doing this write and it is suppose to be done this way or can you tell me if this is not possible so I can stop working on it.
I saw a similar question and I answered there, Communicate to PC over USB.
It requires editing the registry, the server code running on the device and I am not sure if the code will run outside of a development environment (I only need this to speed up my workflow and debugging - so its not an issue).
Not possible.
TCP/IP over USB worked OK in Windows Phone 7. In Windows Phone 8 however they removed the functionality.
Seek for other alternatives.
You could use TCP/IP over WiFi, or use BT, or write data to "Documents" and read with MTP COM API, or write data to isolated storage and read it using isetool.exe (this one only works for dev.unlocked devices).

Problems with receiving UDP messages in Metro-Apps

I'm currently working on a project and one of the featured devices is a Windows Tablet. To "connect" it to other devices (like some Raspberry Pi) in the project environment UDP is used to send messages. The Windows Tablet is intended to be some controlling device with soem touch functionality. Therefore I'm writing an App (and the intention of the App is not to put it into the Windows Store). The UDP part in this work is quite painful because I had to do much research since I started with no experience in App programming. More painful than the programming is, that I practically finished the work only to start over again because the App didn't receive UDP anymore.
Here's my code (I removed elements not relevant to the actual problem). I apologize for the bad coding....
App.xaml.cs:
sealed partial class App : Application
{
NetworkInterface ni = new NetworkInterface();
public App()
{
this.InitializeComponent();
this.Suspending += OnSuspending;
ni.MessageReceived += OnMessageReceived;
ni.Connect(new HostName("127.0.0.1"), "5556");
}
private void OnMessageReceived(object sender, MessageReceivedEventArgs e)
{
Debug.WriteLine("Processing");
Debug.WriteLine(e.Message.Data);
}
public static new App Current
{
get { return Application.Current as App; }
}
private DatagramSocket _socket;
protected override void OnLaunched(LaunchActivatedEventArgs e)
{
Update_Timer();
}
DispatcherTimer timer = new DispatcherTimer();
private void Update_Timer()
{
timer.Start();
timer.Interval = new TimeSpan(0,0,0,0,500);
timer.Tick += alive;
}
private void alive(object sender, object e)
{
if (start == 0) {
Debug.WriteLine("App-Startup");
ni.SendMessage("Startup...");
start++;
}
else
{
Debug.WriteLine("App-Alive");
ni.SendMessage("alive");
start++;
}
}
}
This part of code is to send and receive Messages in the backgrond in the whole App.
And a NetworkInterface class:
class NetworkInterface
{
private DatagramSocket _socket;
public bool IsConnected { get; set; }
public NetworkInterface()
{
IsConnected = false;
_socket = new DatagramSocket();
_socket.MessageReceived += OnSocketMessageReceived;
}
public async void Connect(HostName remoteHostName, string remoteServiceNameOrPort)
{
if (IsConnected != true)
{
await _socket.BindServiceNameAsync("5321");
await _socket.ConnectAsync(remoteHostName, remoteServiceNameOrPort);
}
IsConnected = true;
}
public void alive(object sender, object e)
{
Debug.WriteLine("alive");
}
public event EventHandler<MessageReceivedEventArgs> MessageReceived;
private void OnSocketMessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
var reader = args.GetDataReader();
var count = reader.UnconsumedBufferLength;
var data = reader.ReadString(count);
Debug.WriteLine(args);
if (MessageReceived != null)
{
var ea = new MessageReceivedEventArgs();
ea.Message = new Message() { Data = data };
ea.RemoteHostName = args.RemoteAddress;
ea.RemotePort = args.RemotePort;
MessageReceived(this, ea);
}
}
DataWriter _writer = null;
public async void SendMessage(string message)
{
if (_writer == null)
{
var stream = _socket.OutputStream;
_writer = new DataWriter(stream);
}
_writer.WriteString(message);
await _writer.StoreAsync();
}
}
The main problems are:
If I dont send something before receiving, I won't be able top get an message.
If I send before I have random Faults at this line:
var reader = args.GetDataReader();
If nothing fails, I'm not able to receive messages from a local Python script (which works) but I can send messages from a local program which the App receives.
Does anyone know how I can fix these problems?
Thanks in advance!

TCP listener not working when it is behind a load balancer

I have a TCP listener in a windows service that listens for any incoming TCP requests on a specific port and processes the message. It works fine when it is accessed directly. But once this is running behind a load balancer (in intranet), then it is not accepting any requests. I get errors like "unable to connect to remote server" OR "operation timed out". After a while the service terminates with "out of memory" exception. Please let me know what could be the reason for this. Pasting the code below. I even tried async mode as well (to avoid explicit thread launching). but that didn't help.
public class SampleListener: IDisposable
{
public delegate void JobRecieved(HttpMessage msg);
public event JobRecieved OnJobRecieved;
#region Property
private TcpListener _tcpListener;
private Thread _listenerThread;
public int Port { get; private set; }
public string Url
{
get
{
return new UriBuilder { Scheme = "http", Port = Port, Host = Dns.GetHostName() }.ToString();
}
}
#endregion
public SampleListener(int port)
{
Port = port;
}
~SampleListener()
{
DisposeImpl(false);
}
public void Start()
{
_tcpListener = new TcpListener(IPAddress.Any, Port);
_tcpListener.Start();
_listenerThread = new Thread(ListenCallback);
_listenerThread.Start();
}
public void ListenCallback()
{
try
{
while (true)
{
using (TcpClient client = _tcpListener.AcceptTcpClient())
using (var clientStream = client.GetStream())
{
var msg = new HttpMessage();
msg.Receive(clientStream);
SendOKResponse(client, "");
OnJobRecieved(msg);
client.Close();
}
}
}
catch (System.Net.Sockets.SocketException e)
{
// Expected, TcpClient.Stop called
}
catch (System.Threading.ThreadAbortException)
{
// Expected, thread going away
}
catch (System.IO.IOException)
{
// Expected, shutdown while reading
}
}
private void SendOKResponse(TcpClient tcpClient, String responseBody)
{
var response = new HttpMessage
{
Status = "200",
Reason = "OK",
Version = "HTTP/1.1"
};
response.Send(tcpClient.GetStream(), responseBody);
}
public void Shutdown()
{
lock (this)
{
if (_listenerThread != null)
{
_listenerThread.Abort();
_listenerThread = null;
}
if (_tcpListener != null)
{
_tcpListener.Stop();
_tcpListener.Server.Close();
_tcpListener = null;
}
}
}
#region IDisposable Members
private void DisposeImpl(Boolean bDisposing)
{
lock (this)
{
Shutdown();
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
DisposeImpl(true);
}
#endregion
}
That's because NLB on Windows needs your application be a clustered one by default. And if it is not (which it is your case) you must use Sticky Sessions. Apparently your NLB is not using Sticky Sessions so requests may travel to different servers on each pass. That's why you get those exceptions (Take a look at this).
That happened to me on one of my own projects (a high performance TCP Server - the opposite of what you are doing).

Connecting Anonymous Pipe across processes gives Invalid Handle Error, I'm using System.Io.Pipes

I'm trying to put together a class to handle Ipc between processes using anonymous pipes provided by System.Io.Pipes.
The problem I'm having is that when I test the class using a single process the pipes set up correctly and I can send data between client and server without a problem. However, when I split the client and server into separate processes ( on the same machine ), the client is unable to connect to the end of the server pipe.
The error System.Io.Exception Invalid pipe handle is raised when call
_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
The full code of the class is pasted below.
Essentially its work like this;
Server Process. Create anonymous pipe set for inbound data - call this Pipe A
Server Process. Starts Client process and passes PipeHandle via command argument
Client Process. Connects to end of Pipe A
Client Process. Create anonymous pipe set for inbound data (Pipe B)
5 Client process. Passes pipe handle back to Server using Pipe A
Server Process. Connects to end of Pipe B
So now we have two anonymous pipes, pointing in opposite directions between Server and Client.
Here is the full code of my IPC class
public class MessageReceivedEventArgs : EventArgs
{
public string Message { get; set; }
}
public class IpcChannel : IDisposable
{
private AnonymousPipeServerStream _inboundPipeServerStream;
private StreamReader _inboundMessageReader;
private string _inboundPipeHandle;
private AnonymousPipeClientStream _outboundPipeServerStream;
private StreamWriter _outboundMessageWriter;
public delegate void MessageReceivedHandler(object sender, MessageReceivedEventArgs e);
public event MessageReceivedHandler MessageReceived;
private Thread _clientListenerThread;
private bool _disposing = false;
public IpcChannel()
{
SetupServerChannel();
}
public IpcChannel(string serverHandle)
{
SetupServerChannel();
// this is the client end of the connection
// create an outbound connection to the server
System.Diagnostics.Trace.TraceInformation("Connecting client stream to server : {0}", serverHandle);
SetupClientChannel(serverHandle);
IntroduceToServer();
}
private void SetupClientChannel(string serverHandle)
{
_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, serverHandle);
_outboundMessageWriter = new StreamWriter(_outboundPipeServerStream)
{
AutoFlush = true
};
}
private void SetupServerChannel()
{
_inboundPipeServerStream = new AnonymousPipeServerStream(PipeDirection.In);
_inboundMessageReader = new StreamReader(_inboundPipeServerStream);
_inboundPipeHandle = _inboundPipeServerStream.GetClientHandleAsString();
_inboundPipeServerStream.DisposeLocalCopyOfClientHandle();
System.Diagnostics.Trace.TraceInformation("Created server stream " + _inboundPipeServerStream.GetClientHandleAsString());
_clientListenerThread = new Thread(ClientListener)
{
IsBackground = true
};
_clientListenerThread.Start();
}
public void SendMessage(string message)
{
System.Diagnostics.Trace.TraceInformation("Sending message {0} chars", message.Length);
_outboundMessageWriter.WriteLine("M" + message);
}
private void IntroduceToServer()
{
System.Diagnostics.Trace.TraceInformation("Telling server callback channel is : " + _inboundPipeServerStream.GetClientHandleAsString());
_outboundMessageWriter.WriteLine("CI" + _inboundPipeServerStream.GetClientHandleAsString());
}
public string ServerHandle
{
get
{
return _inboundPipeHandle;
}
}
private void ProcessControlMessage(string message)
{
if (message.StartsWith("CI"))
{
ConnectResponseChannel(message.Substring(2));
}
}
private void ConnectResponseChannel(string channelHandle)
{
System.Diagnostics.Trace.TraceInformation("Connecting response (OUT) channel to : {0}", channelHandle);
_outboundPipeServerStream = new AnonymousPipeClientStream(PipeDirection.Out, channelHandle);
_outboundMessageWriter = new StreamWriter(_outboundPipeServerStream);
_outboundMessageWriter.AutoFlush = true;
}
private void ClientListener()
{
System.Diagnostics.Trace.TraceInformation("ClientListener started on thread {0}", Thread.CurrentThread.ManagedThreadId);
try
{
while (!_disposing)
{
var message = _inboundMessageReader.ReadLine();
if (message != null)
{
if (message.StartsWith("C"))
{
ProcessControlMessage(message);
}
else if (MessageReceived != null)
MessageReceived(this, new MessageReceivedEventArgs()
{
Message = message.Substring(1)
});
}
}
}
catch (ThreadAbortException)
{
}
finally
{
}
}
public void Dispose()
{
_disposing = true;
_clientListenerThread.Abort();
_outboundMessageWriter.Flush();
_outboundMessageWriter.Close();
_outboundPipeServerStream.Close();
_outboundPipeServerStream.Dispose();
_inboundMessageReader.Close();
_inboundMessageReader.Dispose();
_inboundPipeServerStream.DisposeLocalCopyOfClientHandle();
_inboundPipeServerStream.Close();
_inboundPipeServerStream.Dispose();
}
}
In a single process, it can be used like this;
class Program
{
private static IpcChannel _server;
private static IpcChannel _client;
static void Main(string[] args)
{
_server = new IpcChannel();
_server.MessageReceived += (s, e) => Console.WriteLine("Server Received : " + e.Message);
_client = new IpcChannel(_server.ServerHandle);
_client.MessageReceived += (s, e) => Console.WriteLine("Client Received : " + e.Message);
Console.ReadLine();
_server.SendMessage("This is the server sending to the client");
Console.ReadLine();
_client.SendMessage("This is the client sending to the server");
Console.ReadLine();
_client.Dispose();
_server.Dispose();
}
Thanks in advance for any suggestions.
You didn't post the server code, but anyway. In the server:
You need to specify that the client's pipe handle is inheritable when you create it.
When you launch the client you need to specify that inheritable handles will be inherited.
If you miss either of these steps then the pipe handle will be invalid in the client process.
Also, your step 4 won't work. If you create a pipe handle in the client it won't mean anything to the server when you pass it back. You can make this work using the DuplicateHandle function, but it's much easier to create all the handles in the server and inherit them in the client.
The key point is that handles are per-process, not system-wide.
Starting child process do not forget to set UseShellExecute = false or the handle will not be inherited.

Categories