Below this post, is my ChatApp's client disconnect handler, where it removed the disconnected client from the ListView, it perfectly but the CPU usage suddenly goes up to 50% when the client disconnects. How can I fix it?
Task.Factory.StartNew(() =>
{
while (true)
{
try
{
if (!client.Client.Connected)
{
session.Stop();
session.tcpclient = null;
Clients.Remove(session);
listView1.Invoke((MethodInvoker)(() =>
{
ListViewItem data = new ListViewItem(session.listItems);
listView1.Items.RemoveAt((session.index));
listView1.Refresh();
}));
}
Thread.Sleep(500);
}
catch (Exception)
{
}
}
});
I tried putting it in a Thread but didn't work.
We have a siglnalR hub hosted in IIS, and a WPF .net core application that connects. Everything is working perfectly on first run. However, when IIS recycles the application pool, the WPF client re-reconnects successfully, but, (so it seems) on another thread, as when the user attempts to perform an action (open a new WPF window) - the following error is thrown when creating a new instance of the window to open :-
"The calling thread must be STA, because many UI components require this"
This is how we connect to the hub :-
private async void Connect()
{
try
{
_signalRConnection.On<Notification>(NotificationMessageStr, (message) =>
{
if (message != null && _signalRConnection != null)
{
OnProcessMessage(message);
}
}
);
_signalRConnection.Reconnecting += error =>
{
OnReconnecting("Connection lost - Attempting to reconnect.");
return Task.CompletedTask;
};
_signalRConnection.Reconnected += connectionId =>
{
OnReconnected("Reconnected");
return Task.CompletedTask;
};
_signalRConnection.Closed += error =>
{
OnLostConnection("Failed to connect");
// Notify users the connection has been closed or manually try to restart the connection.
return Task.CompletedTask;
};
try
{
//Connect to the server
await _signalRConnection.StartAsync();
}
catch (Exception ex)
{
}
}
catch (Exception ex)
{
}
}
When a message is received from the hub, we call :-
private void SubscriveToNewNotification()
{
vm.NewNotification += (sender, e) => {
ShowNotificationAlert(e.NotificationMessage); };
}
private void ShowNotificationAlert(Notification notification) {
NotificationAlert notificationAlert = new NotificationAlert();
notificationAlert.notification = notification;
notificationAlert.Show();
}
And it is this:-
NotificationAlert notificationAlert = new NotificationAlert();
That is failing.
This is how the connection is built up :-
private void InitializeViewModel()
{
try
{
string serviceAddress = "xxxx/notificationHub";
connectHub = NotificationHubManager.CreateNotificationHub(serviceAddress, userInfo);
}
catch (System.Exception ex)
{
System.Windows.MessageBox.Show(ex.Message + "--");
}
connectHub.ProcessMessage += (sender, e) =>
{
// THIS IS WHERE IT FALLS OVER
NotificationAlert n = new NotificationAlert();
OnNotificationReceived(e.NotificationMessage);
};
-- This is the notification hub
public static NotificationHubConnect CreateNotificationHub(string address, ISwiftUser userInfo = null)
{
HubConnection hubConnection = new HubConnectionBuilder()
.WithUrl(address)
.WithAutomaticReconnect()
.Build();
try
{
var result = new NotificationHubConnect(hubConnection, userInfo);
return result;
}
catch (Exception ex)
{
throw ex;
}
}
Is there a way to have the reconnect run on the same thread?
So I have a really really weird issue. This is going to take a tiny bit of a wall to explain fully..
I'm running some game servers for a Unity game called SCP: Secret Laboratory, and have a custom-made C# Discord Bot that helps my staff moderate both in-game and on Discord, by controlling bans, logging player warnings, etc, etc.
I'm trying to make the two platforms communicate with each other over a TCP port over the local machine address (127.0.0.1).
I've setup the listener on the bot, to whom the individual servers (there are 7) will connect to when they are ready.
I've also set it up so that if the connection is broken from either side, the servers will close the TcpClient, start a new one, and attempt to connect, while the listener just resumes listening on that port for a connection again, after closing the client on it's side.
I've tested it several times by closing the client, the socket, or just rebooting the program on either end, and they seem to without fail reconnect flawlessly.
Here's my issue..
While the game servers remain empty, everything is fine. After players start to connect, anywhere from 5mins to an hour will go by, then suddenly, seemingly at random, the server no longer 'hears' the bot when it talks across the connection, however, the bot itself does not hit an error when trying to send data, the server just never receives any. What's stranger, is the server will continue to send it's own data over the connection, and the bot does receive that data.
To attempt to 'reset' the connection with a new client when this happens, I make the servers send an initial heartbeat to the bot when they first connect. This tells the bot that the connection is established on the server's end, and begins a looping thread that will send an AYT message to the server every 10s, to which the server must reply.
If the bot sends 3 AYT messages without getting a response back, it will close the TcpClient, and start listening for a new one.
At this time, the server detects the connection was closed, disposes of it's client, instantiates a new one, and tries to connect successfully. The bot then receives it's initial heartbeat, and starts the AYT timer for that client again, but the server continues to not receive them. Or any data whatsoever sent from the bot, even though the bot still receives data from the server during this time.
The only solution to fix the problem at that point, is to fully restart the game server, after which it will connect to the bot and work perfectly fine, until it.. just doesn't anymore.
For reference, pastebins of the code used are below.
The bot "listener" side
public class ProcessSTT
{
private static ConcurrentDictionary<int, TcpClient> bag = new ConcurrentDictionary<int, TcpClient>();
private static ConcurrentDictionary<int, int> heartbeats = new ConcurrentDictionary<int, int>();
public static void SendData(string data, int port, ulong channel = 0)
{
try
{
BinaryFormatter formatter = new BinaryFormatter();
SerializedData.SerializedData serializedData =
new SerializedData.SerializedData { Data = data, Port = port, Channel = channel };
//Console.WriteLine($"Sending {serializedData.Data}");
if (!bag.ContainsKey(port))
{
Console.WriteLine($"STT: Bag does not contain {port}");
return;
}
if (bag[port] != null && bag[port].Connected)
formatter.Serialize(bag[port].GetStream(), serializedData);
else
{
Console.WriteLine($"Error - Bag {port} is null or not connected.");
if (bag.TryRemove(port, out TcpClient client))
client.Dispose();
}
}
catch (IOException s)
{
Console.WriteLine($"STT: Socket exception, removing..");
KeyValuePair<int, TcpClient> thingything = default;
foreach (var thing in bag)
if (thing.Key == port)
thingything = thing;
if (bag.TryRemove(thingything.Key, out TcpClient _client))
{
_client.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static List<TcpListener> listener = new List<TcpListener>();
public static void Init()
{
for (int i = 1; i < 8; i++)
{
TcpListener list = new TcpListener(IPAddress.Loopback, 11900 + i);
Console.WriteLine($"STT: Listener started for port {11900 + i}");
listener.Add(list);
list.Start();
ThreadPool.QueueUserWorkItem(ListenForConn, list);
}
}
public static async Task Heartbeat(int port)
{
await Task.Delay(10000);
for (;;)
{
Console.WriteLine("STT: Starting Heartbeat");
if (heartbeats[port] > 3)
{
Console.WriteLine($"STT: Removing {port} due to heartbeat timeout.");
if (bag.TryRemove(port, out TcpClient client))
client.Close();
heartbeats.TryRemove(port, out int _);
return;
}
heartbeats[port]++;
Console.WriteLine($"STT: Sending heartbeat to: {port}");
if (!bag[port].Connected)
{
Console.WriteLine($"STT: {port} is null, removing.");
if (bag.TryRemove(port, out TcpClient client))
client.Close();
return;
}
SendData("ping", port, 653737934150959115);
await Task.Delay(10000);
}
}
public static void ListenForConn(object token)
{
Console.WriteLine("STT: Listener started.");
TcpListener listen = token as TcpListener;
for (;;)
{
try
{
TcpClient thing = listen.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(ListenOn, thing);
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
public static async Task ReceiveData(SerializedData.SerializedData data, TcpClient client)
{
try
{
if (data == null)
{
Console.WriteLine("STT: Received data null");
return;
}
if (data.Data == "ping")
{
if (!bag.ContainsKey(data.Port))
{
Console.WriteLine($"STT: Adding {data.Port}");
bag.TryAdd(data.Port, client);
}
if (!bag[data.Port].Connected || bag[data.Port] == null)
{
Console.WriteLine($"STT: Bag {data.Port} not connected or null, removing.");
if (bag.TryRemove(data.Port, out TcpClient cli))
{
cli?.Close();
}
}
Console.WriteLine($"STT: Received heartbeat for: {data.Port}");
if (!heartbeats.ContainsKey(data.Port))
{
Heartbeat(data.Port);
heartbeats.TryAdd(data.Port, 0);
}
else
heartbeats[data.Port]--;
return;
}
Console.WriteLine(data.Data);
data.Data = data.Data.Substring(data.Data.IndexOf('#') + 1);
//Console.WriteLine("Getting guild.");
SocketGuild guild = Bot.Discord.GetGuild(478381106798788639);
//Console.WriteLine("Getting channel");
SocketTextChannel chan = guild.GetTextChannel(data.Channel);
//Console.WriteLine("Sending message.");
await chan.SendMessageAsync($"Server {data.Port -= 7770}: {data.Data}");
if (data.Port == 7771)
{
DiscordWebhookClient webhook = new DiscordWebhookClient(
"");
await webhook.SendMessageAsync($"{data.Data}");
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
public static void ListenOn(object token)
{
TcpClient client = token as TcpClient;
try
{
BinaryFormatter formatter = new BinaryFormatter();
for (;;)
{
SerializedData.SerializedData serializedData;
if (!client.Connected)
{
Console.WriteLine($"Client not connected..");
client.Close();
continue;
}
serializedData = formatter.Deserialize(client.GetStream()) as SerializedData.SerializedData;
new Thread(() => ReceiveData(serializedData, client)).Start()
}
}
catch (SerializationException s)
{
Console.WriteLine($"STT: Serialization exception, removing..");
KeyValuePair<int, TcpClient> thingything = default;
foreach (var thing in bag)
if (thing.Value == client)
thingything = thing;
if (bag.TryRemove(thingything.Key, out TcpClient _client))
{
_client.Close();
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
}
The server "speaker" side
public class ProcessSTT
{
private static TcpClient tcpClient;
public static readonly ConcurrentQueue<SerializedData.SerializedData> dataQueue = new ConcurrentQueue<SerializedData.SerializedData>();
private static Thread _init;
private static bool _locked;
public static void Init()
{
if (_locked)
return;
_locked = true;
Thread.Sleep(1000);
try
{
Plugin.Log($"STT: Starting INIT.");
tcpClient?.Close();
tcpClient = new TcpClient();
while (!tcpClient.Connected)
{
Plugin.Log($"STT: While loop start");
Thread.Sleep(2000);
try
{
tcpClient.Connect("127.0.0.1", ServerConsole.Port + 4130);
}
catch (SocketException)
{
tcpClient.Client.Disconnect(false);
}
catch (Exception e)
{
Plugin.Log($"STT: {e}");
}
}
Thread thread = new Thread(ReceiveData);
thread.Start();
SendData("ping", 0);
_locked = false;
}
catch (IOException i)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
public static void SendData(string data, ulong channel)
{
try
{
if (!tcpClient.Connected)
throw new InvalidOperationException("Tcp Client not connected!");
SerializedData.SerializedData serializedData = new SerializedData.SerializedData
{
Data = data, Port = ServerConsole.Port, Channel = channel
};
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(tcpClient.GetStream(), serializedData);
ServerConsole.AddLog($"Sent {data}");
}
catch (IOException i)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
public static void ReceiveData()
{
try
{
if (!tcpClient.Connected)
throw new InvalidOperationException("Tcp Client not connected!");
BinaryFormatter formatter = new BinaryFormatter();
for (;;)
{
SerializedData.SerializedData deserialize =
formatter.Deserialize(tcpClient.GetStream()) as SerializedData.SerializedData;
if (deserialize == null)
continue;
dataQueue.Enqueue(deserialize);
}
}
catch (SerializationException s)
{
_init = new Thread(Init);
_init.Start();
}
catch (IOException e)
{
_init = new Thread(Init);
_init.Start();
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
}
public class HandleQueue
{
public static ulong channelid;
public static void HandleQueuedItems()
{
while (ProcessSTT.dataQueue.TryDequeue(out SerializedData.SerializedData result))
{
string command = result.Data;
Plugin.Log($"STT: Received {result.Data} for {result.Port}");
if (result.Port != ServerConsole.Port)
return;
if (result.Data == "ping")
{
Plugin.Log("STT: BLART Heartbeat received.");
ProcessSTT.SendData("ping", 0);
return;
}
channelid = result.Channel;
try
{
GameCore.Console.singleton.TypeCommand($"/{command}", new BlartSender());
}
catch (Exception e)
{
ServerConsole.AddLog(e.ToString());
}
}
}
public static IEnumerator<float> Handle()
{
for (;;)
{
HandleQueuedItems();
yield return Timing.WaitForSeconds(1f);
}
}
}
public class BlartSender : CommandSender
{
public override void RaReply(string text, bool success, bool logToConsole, string overrideDisplay)
{
ProcessSTT.SendData($"{text}", HandleQueue.channelid);
}
public override void Print(string text)
{
ProcessSTT.SendData($"{text}", HandleQueue.channelid);
}
public override string SenderId => "BLART";
public override string Nickname => "BLART";
public override ulong Permissions => ServerStatic.GetPermissionsHandler().FullPerm;
public override byte KickPower => Byte.MaxValue;
public override bool FullPermissions => true;
}`
I am currently trying to feed my socket.io server with data from my C# client. But I am not sure how to receive the message on the server.
My server code:
const io = require('socket.io')(9000);
io.on('connection', (socket) => {
console.log('Connected');
}
First of all I don't know which event I have to listen to, but nevertheless I am unable to send data to my server using the following client (which uses Websocket-sharp) code:
private void init()
{
// start socket connection
using (var ws = new WebSocket("ws://localhost:9000/socket.io/?EIO=2&transport=websocket"))
{
ws.OnMessage += (sender, e) =>
API.consoleOutput("Message: " + e.Data);
ws.OnError += (sender, e) =>
API.consoleOutput("Error: " + e.Message);
ws.Connect();
ws.Send("server");
}
}
The connection works, but how do I receive the message of the server? The sending does not fire an error, therefore I think it does work.
I've gotten this working for a UWP app that connects to a node.js server. Basically what I do is connect to a URL that looks like ws://localhost:4200/socket.io/?EIO=3&transport=websocket
the port number being something we chose.
once that is set I connect to the node.js socket io library via the following lines of code.
private async Task ConnectWebsocket() {
websocket = new MessageWebSocket();
Uri server = new Uri(WebSocketURI); //like ws://localhost:4300/socket.io/?EIO=3&transport=websocket
websocket.Control.MessageType = SocketMessageType.Utf8;
websocket.MessageReceived += Websocket_MessageReceived;
websocket.Closed += Websocket_Closed;
try {
await websocket.ConnectAsync(server);
isConnected = true;
writer = new DataWriter(websocket.OutputStream);
}
catch ( Exception ex ) // For debugging
{
// Error happened during connect operation.
websocket.Dispose();
websocket = null;
Debug.Log("[SocketIOComponent] " + ex.Message);
if ( ex is COMException ) {
Debug.Log("Send Event to User To tell them we are unable to connect to Pi");
}
return;
}
}
`
at this point your socket io on "connection" should fire on your server
then you can emit events to it like normal. except the C# socket code does not discriminate various channels so you must do so on your own. below is how we do it (aka SocketData and SocketIOEvent are classes we have defined)
private void Websocket_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args) {
try {
using ( DataReader reader = args.GetDataReader() ) {
reader.UnicodeEncoding = UnicodeEncoding.Utf8;
try {
string read = reader.ReadString(reader.UnconsumedBufferLength);
//read = Regex.Unescape(read);
SocketData socc = SocketData.ParseFromString(read);
if (socc != null ) {
Debug.Log(socc.ToString());
SocketIOEvent e = new SocketIOEvent(socc.channel, new JSONObject( socc.jsonPayload));
lock ( eventQueueLock ) { eventQueue.Enqueue(e); }
}
}
catch ( Exception ex ) {
Debug.Log(ex.Message);
}
}
} catch (Exception ex ) {
Debug.Log(ex.Message);
}
}
in our specific application we did not need to send messages to our server, so for that I do not have a good answer.
I have been working on this for days, but can't fix the problem.
This is what I've got right now ->
Bluetooth handler
protected BluetoothAdapter bluetoothAdapter;
protected BluetoothServer btServer;
protected BluetoothSocket btSocket;
protected BluetoothDevice pairedBTDevice;
protected BluetoothListener btListener;
protected ParcelUuid uuid;
public BluetoothHandler()
{
BluetoothAdapter = null;
}
public void Initialize()
{
BluetoothAdapter = BluetoothAdapter.DefaultAdapter;
// Check if it has a bluetooth interface
if (BluetoothAdapter == null)
{
Console.WriteLine("Bluetooth is not available!");
return;
}
// Check if bluetooth interface is enabled
if (!BluetoothAdapter.IsEnabled)
{
BluetoothAdapter.Enable();
}
int count = 0;
// Get all the devices in the bluetooth list
var listDevices = BluetoothAdapter.BondedDevices;
if (listDevices.Count > 0)
{
foreach (var btDevice in listDevices)
{
// Get the specific controller
if (btDevice.Name == "MOCUTE-032_B52-CA7E")
{
UUID = btDevice.GetUuids().ElementAt(count);
pairedBTDevice = btDevice;
}
count++;
}
}
// Check if bluetooth is enabled
// Check if there is a device
if (BluetoothAdapter.IsEnabled && pairedBTDevice != null)
{
// Check if it's paired
if (pairedBTDevice.BondState == Bond.Bonded)
{
// First start the server
btServer = new BluetoothServer(this);
Thread.Sleep(1000);
// Start a new thread
Thread thread = new Thread(new ThreadStart(Connect));
thread.Start();
}
}
}
protected void Connect()
{
// Check if there is no socket already
if (btSocket == null)
{
try
{
btSocket = pairedBTDevice.CreateRfcommSocketToServiceRecord(UUID.Uuid);
}
catch (IOException ex)
{
throw ex;
}
}
try
{
Console.WriteLine("Attempting to connect...");
// Create a socket connection
btSocket.Connect();
}
catch
{
Console.WriteLine("Connection failed...");
Console.WriteLine("Attempting to connect...");
try
{
btSocket = pairedBTDevice.CreateInsecureRfcommSocketToServiceRecord(UUID.Uuid);
btSocket.Connect();
}
catch
{
Console.WriteLine("Connection failed...");
return;
}
}
Console.WriteLine("Client socket is connected!");
Read();
}
protected void Read()
{
btListener = new BluetoothListener();
btListener.Read(btSocket);
}
Bluetooth server
private BluetoothHandler bluetoothHandler;
private BluetoothServerSocket serverSocket;
private Thread thread;
public BluetoothServer(BluetoothHandler bluetoothHandler)
{
this.bluetoothHandler = bluetoothHandler;
BluetoothServerSocket tmp = null;
try
{
tmp = bluetoothHandler.BluetoothAdapter.ListenUsingRfcommWithServiceRecord("MOCUTE-032_B52-CA7E", bluetoothHandler.UUID.Uuid);
}
catch (IOException ex)
{
throw ex;
}
serverSocket = tmp;
thread = new Thread(new ThreadStart(Run));
thread.Start();
}
protected void Run()
{
System.Console.WriteLine("Server is running...");
while (true)
{
try
{
serverSocket.Accept();
}
catch (IOException ex)
{
System.Console.WriteLine("FAILED! === > " + ex);
}
}
}
Bluetooth listener
protected Stream mmInStream;
public void Read(BluetoothSocket socket)
{
Stream tmpIn = null;
try
{
tmpIn = socket.InputStream;
}
catch (IOException ex)
{
throw ex;
}
mmInStream = tmpIn;
Thread thread = new Thread(new ThreadStart(Run));
thread.Start();
}
protected void Run()
{
byte[] buffer = new byte[1024];
int bytes;
Console.WriteLine("Waiting for events...");
while (true)
{
try
{
if (mmInStream.IsDataAvailable())
{
bytes = mmInStream.Read(buffer, 0, buffer.Length);
}
}
catch (Exception ex)
{
throw ex;
}
}
}
I would like to connect with the following controller ->
So, I would like to catch the buttons events from the controller, but I have no idea anymore..
I've got also the known error: Java.IO.IOException: "read failed, socket might closed or timeout, read ret: -1
The UUID of the controller is: 00001124-0000-1000-8000-00805f9b34fb
I have one example to connect to a Bluetooth(2.0) device on my Github you can check the code and see if you setup is correct here is the link https://github.com/AlejandroRuiz/Mono/blob/master/Arduino/Bluetooth/MainActivity.cs if you have any specific question about the code please let me know also you need to be sure what kind of bluetooth is using because the way to connect to a 4.0 BLE is very different that the old 2.0
The problem is solved. I didn't need a Bluetooth socket. I just used the override methods "KeyDown" and "KeyUp". It works great now :)
If you need a socket and you've got an exception like IOException: read failed, socket might closed then you should read my fix here:
IOException: read failed, socket might closed - Bluetooth on Android 4.3