I wrote a client-server app, this is a console chat application for many clients. When only one client is connected, the application works well, but when two or more clients are connected I have a bug, after sending one message to the second client, he lost connection to the server and only first client can send a message to the server...
I used Task for asynchronous operations like listening port and sending messages. When one client sends a message to the server, it adds it to the list messages and resends to all clients to refresh all windows.
Server application:
using System;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace Server
{
class Program
{
private static List<Client> clients = new List<Client>();
private static TcpListener listener = null;
private static StreamReader reader = null;
private static StreamWriter writer = null;
private static List<Task> clientTasks = new List<Task>();
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Server";
try
{
listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 8080);
listener.Start();
Console.WriteLine("Server started...");
var connectTask = Task.Run(() => ConnectClients());
//var listenTask = Task.Run(() => ListenClients());
Task.WaitAll(connectTask);
}
catch (Exception e)
{
Console.WriteLine(e);
}
finally
{
if (listener != null)
{
listener.Stop();
}
}
}
private static void ConnectClients()
{
Console.WriteLine("Waiting for incoming client connections...");
while (true)
{
if (listener.Pending()) //if someone want to connect
{
clients.Add(new Client(listener.AcceptTcpClient(), "Client: " + (clients.Count + 1)));
Console.WriteLine(clients[clients.Count - 1].clientName + " connected to server.");
var newClientTask = Task.Run(() => HandleClient(clients[clients.Count - 1]));
clientTasks.Add(newClientTask); //start new task for new client
}
}
}
private static void HandleClient(Client TCPClient)
{
Console.WriteLine("Starting handle client");
string s = string.Empty;
writer = new StreamWriter(TCPClient.client.GetStream());
reader = new StreamReader(TCPClient.client.GetStream());
try
{
while (!(s = reader.ReadLine()).Equals("Exit") || (s == null))
{
if(!TCPClient.client.Connected)
{
Console.WriteLine("Client disconnected.");
clients.Remove(TCPClient);
}
Console.WriteLine("From client: " + TCPClient.clientName + " -> " + s);
messages.Add(TCPClient.clientName + ": " + s); //save new message
//Console.WriteLine(s);
foreach (Client c in clients) //refresh all connected clients
{
c.writer.WriteLine("%C"); //clear client
foreach (string msg in messages)
{
c.writer.WriteLine(msg);
c.writer.Flush();
}
}
}
//CloseServer();
}
catch (Exception e) { Console.WriteLine(e); }
Console.WriteLine("ending handle client");
}
private static void CloseServer()
{
reader.Close();
writer.Close();
clients.ForEach(tcpClient => tcpClient.client.Close());
}
}
}
Client information class:
using System.Net.Sockets;
using System.IO;
namespace Server
{
class Client
{
public TcpClient client;
public StreamWriter writer;
public string clientName;
public Client(TcpClient client, string clientName)
{
this.client = client;
writer = new StreamWriter(client.GetStream());
this.clientName = clientName;
}
}
}
Client application:
using System.Net.Sockets;
using System.Net;
using System.IO;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Client
{
class Program
{
private static TcpClient client = new TcpClient();
private static StreamReader reader;
private static StreamWriter writer;
private static bool refresh;
private static List<string> messages = new List<string>();
public static void Main()
{
Console.Title = "Client";
ConnectLoop();
//Task.WaitAll(sendTask, recieveTask); //wait for end of all tasks
}
private static void ConnectLoop()
{
bool refreshTask = false;
Task sendTask = null, recieveTask = null, updateConvTask = null;
while (true)
{
if(!client.Connected) //try to connect
{
refreshTask = true;
if(sendTask != null || recieveTask != null || updateConvTask != null)
{
sendTask.Dispose();
recieveTask.Dispose();
updateConvTask.Dispose();
sendTask = recieveTask = updateConvTask = null;
}
Console.WriteLine("Connecting to server...");
try
{
client.Connect(IPAddress.Parse("127.0.0.1"), 8080);
}
catch (SocketException) { }
Thread.Sleep(10);
}
else if(refreshTask) // \/ CONNECTED \/
{
Console.WriteLine("Connected.");
reader = new StreamReader(client.GetStream());
writer = new StreamWriter(client.GetStream());
sendTask = Task.Run(() => SendMessage()); //task for sending messages
recieveTask = Task.Run(() => RecieveMessage()); //task for recieving messages
updateConvTask = Task.Run(() => UpdateConversation()); //task for update console window
refreshTask = false;
}
}
}
private static void SendMessage()
{
string msgToSend = string.Empty;
do
{
Console.WriteLine("Enter a message to send to the server");
msgToSend = Console.ReadLine();
writer.WriteLine(msgToSend);
writer.Flush();
} while (!msgToSend.Equals("Exit"));
EndConnection();
}
private static void RecieveMessage()
{
try
{
while (client.Connected)
{
//Console.Clear();
string msg = reader.ReadLine();
if(msg != string.Empty)
{
if (msg == "%C") //special message from server, clear messages if recieve it
{
messages.Clear();
}
else
{
messages.Add(msg);
refresh = true; //refresh console window
}
}
//Console.Clear();
//Console.WriteLine(msgFromServer);
}
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private static void UpdateConversation()
{
//string conversationTmp = string.Empty;
try
{
while (true)
{
if (refresh) //only if refresh
{
refresh = false;
Console.Clear();
messages.ForEach(msg => Console.WriteLine(msg)); //write all messages
Console.WriteLine();
}
}
}
catch (Exception) { }
}
private static void EndConnection()
{
reader.Close();
writer.Close();
client.Close();
}
}
}
I know that my bug will be something stupid. I'm new to TCP/IP applications, could you give me links to some tutorials that use it and Tasks?
Thanks for any help.
Related
I was following a tutorial to connect my bluetooth module to pc and read data from it, but in the tutorial he designed the program to run as a GUI, now I'm trying to edit it to run in console, which I will merge the new code in unity engine to move my game by the input data.
The GUI
used and the code,
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Threading;
using InTheHand;
using InTheHand.Net.Bluetooth;
using InTheHand.Net.Sockets;
using System.IO;
namespace Bluetooth
{
public partial class Form1 : Form
{
List<string> items;
public Form1()
{
items = new List<string>();
InitializeComponent();
}
private void bGo_Click(object sender, EventArgs e)
{
if(serverStarted)
{
updateUI("Server already started!");
return;
}
if(rbClient.Checked)
{
connectAsClient();
}
else
{
connectAsServer();
}
}
private void connectAsServer()
{
Thread bluetoothServerThread = new Thread(new ThreadStart(serverConnectThread));
bluetoothServerThread.Start();
}
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
bool serverStarted = false;
public void serverConnectThread()
{
serverStarted = true;
updateUI("Server started, waiting for clients");
BluetoothListener blueListener = new BluetoothListener(mUUID);
blueListener.Start();
BluetoothClient conn = blueListener.AcceptBluetoothClient();
updateUI("Client has connected");
Stream mstream = conn.GetStream();
while (true)
{
try
{
//handle server connection
byte[] received = new byte[1024];
mstream.Read(received, 0, received.Length);
updateUI("Received: " + Encoding.ASCII.GetString(received));
byte[] sent = Encoding.ASCII.GetBytes("Hello world\n");
mstream.Write(sent, 0, sent.Length);
}
catch (IOException exception)
{
updateUI("Client has disconnected!!");
break;
}
}
}
private void connectAsClient()
{
startScan();
}
private void startScan()
{
listBox1.DataSource = null;
listBox1.Items.Clear();
items.Clear();
Thread bluetoothScanThread = new Thread(new ThreadStart(scan));
bluetoothScanThread.Start();
}
BluetoothDeviceInfo[] devices;
private void scan()
{
updateUI("Start scanning...");
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
updateUI(devices.Length.ToString() + " devices discovered");
updateUI("Scan complete");
foreach(BluetoothDeviceInfo d in devices)
{
items.Add(d.DeviceName);
}
updateDeviceList();
}
private void updateUI(string message)
{
Func<int> del = delegate ()
{
tbOutput.AppendText(message + System.Environment.NewLine);
return 0;
};
Invoke(del);
}
private void updateDeviceList()
{
Func<int> del = delegate ()
{
listBox1.DataSource = items;
return 0;
};
Invoke(del);
}
BluetoothDeviceInfo DeviceInfo;
private void listBox1_DoubleClick(object sender, EventArgs e)
{
DeviceInfo = devices.ElementAt(listBox1.SelectedIndex);
updateUI(DeviceInfo.DeviceName + " was Selected, attempting connect");
if(PairDevice())
{
updateUI("Device paired");
updateUI("starting connect thread");
Thread bluetoothClientThread = new Thread(new ThreadStart(ClientConnectThread));
bluetoothClientThread.Start();
}
else
{
updateUI("pair failed");
}
}
private void ClientConnectThread()
{
BluetoothClient client = new BluetoothClient();
updateUI("Attempting connect");
client.BeginConnect(DeviceInfo.DeviceAddress, mUUID, this.BluetoothClientConnectCallback, client);
}
void BluetoothClientConnectCallback(IAsyncResult result)
{
BluetoothClient client = (BluetoothClient)result.AsyncState;
client.EndConnect(result);
Stream stream = client.GetStream();
stream.ReadTimeout = 10000;
while(true)
{
try
{
byte[] received = new byte[1024];
stream.Read(received, 0, received.Length);
updateUI(Encoding.ASCII.GetString(received));
}
catch (IOException exception)
{
updateUI("Client has disconnected!!");
break;
}
}
}
string mypin = "1234";
private bool PairDevice()
{
if(!DeviceInfo.Authenticated)
{
if (!BluetoothSecurity.PairRequest(DeviceInfo.DeviceAddress, mypin)) ;
{
return false;
}
}
return true;
}
bool ready = false;
byte[] message;
private void tbText_KeyPress(object sender, KeyPressEventArgs e)
{
if(e.KeyChar == 13)
{
byte[] b = Encoding.ASCII.GetBytes(tbText.Text);
ready = true;
tbText.Clear();
}
}
}
}
I tried to edit my code but I don't know why scan method can't be called.
class Program
{
Guid mUUID = new Guid("00001101-0000-1000-8000-00805F9B34FB");
List<string> items = new List<string>();
BluetoothDeviceInfo[] devices;
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
Thread bluetoothScanThread = new Thread(new ThreadStart(scan));
bluetoothScanThread.Start();
}
public void scan()
{
Console.WriteLine("Start scanning...");
BluetoothClient client = new BluetoothClient();
devices = client.DiscoverDevicesInRange();
Console.WriteLine(devices.Length.ToString() + " devices discovered");
Console.WriteLine("Scan complete");
foreach (BluetoothDeviceInfo d in devices)
{
items.Add(d.DeviceName);
}
}
}
I have been given the task to create a interface where I receive data through socket from the sender, for this purpose I am using NetMQ PushSocket for the sender side and then I receive the data at client side sung PullSocket and I have to update the UI (WPF app) when data is received so I receive data using poller in ReceiveReady event of the PullSocket when I do this in a seperate service class and call that class in UI ViewModel the UI thread hangs, so I use Poller.Run in a task, now the problem is that when I stop the poller and then restart it again it doesn't call the ReceiveReady event
Here is the ReceiverService for receiving the data.
public class ReceiverService
{
string msg;
string _address;
int _port;
PullSocket receiver;
NetMQPoller poller;
private MapViewModel ViewModel { get; set; }
public ReceiverService(MapViewModel mapViewModel, int port = 5555)
{
_address = GetComputerLanIP();
_port = port;
receiver = new PullSocket($"tcp://{_address}:{_port}");
receiver.Options.Linger = TimeSpan.Zero;
this.ViewModel = mapViewModel;
poller = new NetMQPoller { receiver };
receiver.ReceiveReady += receiver_ReceiveReady;
}
public void Start()
{
receiver.Connect($"tcp://{_address}:{_port}");
poller.Run();
}
public void Stop()
{
receiver.Disconnect($"tcp://{_address}:{_port}");
poller.Stop();
}
private void receiver_ReceiveReady(object sender, NetMQSocketEventArgs e)
{
// receive won't block as a message is ready
msg = e.Socket.ReceiveFrameString();
// send a response
if (!string.IsNullOrEmpty(msg))
{
try
{
//Updaing the ViewModel here
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
}
private string GetComputerLanIP()
{
string strHostName = Dns.GetHostName();
IPHostEntry ipEntry = Dns.GetHostEntry(strHostName);
foreach (var ipAddress in ipEntry.AddressList)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
{
return ipAddress.ToString();
}
}
return "";
}
private string GetValueFromMessage(string identifier)
{
msg.Replace("{", "");
msg.Replace("}", "");
identifier = /*" " + */identifier + " = ";
try
{
int index = msg.IndexOf(identifier) + identifier.Length;
if (index != -1)
{
int index2 = msg.IndexOf(";", index);
if (index2 == -1)
{
index2 = msg.Length;
}
return msg.Substring(index, index2 - index);
}
}
catch (IndexOutOfRangeException ex)
{
return null;
}
return null;
}
}
and in my ViewModel I have set commands for these
private void StartReceiver()
{
Task.Run(() => ReceiverService.Start());
}
private void StopReceiver()
{
Task.Run(() => ReceiverService.Stop());
}
What am I doing wrong? I am new to NetMQ and WPF. TIA
at first it would be good to make a task inside ReceiverService, kind of an ActorModel, because in the end if You would like to reuse it anywhere You need to remember that You should creat a Task first.
always it would be good to have socket in using statement, because You should always close socket if You are not using it
public async Task StartAsync() {
await Task.Run(() => ThreadBody())
}
public void Stop()
{
_poller.Stop();
}
private void ThreadBody()
{
using (PullSocket receiverSocket = new PullSocket())
using (_poller = new NetMQPoller())
{
receiverSocket.Connect($"tcp://{_address}:{_port}");
receiverSocket.ReceiveReady += receiver_ReceiveReady;
_poller.Add(receiverSocket);
_poller.Run();
}
}
I have a problem: the server doesn't receive any data from the client.
Here is server initialization:
public void Start()
{
var listener = new TcpListener(IPAddress.Any, Port);
listener.Start();
Task.Run(
async () =>
{
while (!this.cancellationToken.IsCancellationRequested)
{
var client = await listener.AcceptTcpClientAsync();
var stream = client.GetStream();
string request = await ReceiveRequestAsync(stream);
await RequestHandlerAsync(request, stream);
}
listener.Stop();
}, this.cancellationToken);
}
Here is requesting client code (it is from unit test so server is initialized right here):
var server = new SimpleFtpServer();
server.Start();
using (TcpClient client = new TcpClient(RequestUri, Port))
{
NetworkStream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream)
{
AutoFlush = true,
};
writer.Write("zapros");
using (StreamReader reader = new StreamReader(stream))
{
Console.Writeline(reader.ReadToEnd());
}
}
server.Stop();
It worth saying that I have started learning async/await in C# really recently so probably the problem is in usage of them.
Thank you in advance!
its probably not perfect however I am in the same situation as you and created a Async TCP Client/Server for practice and experimentation.
The below is an excerpt of my implementation, it works s
Server:
public class AsyncServerDemo
{
private CancellationTokenSource cancel;
private readonly TcpListenerEx listener;
private Task WaitingForConnections;
private Timer timerCallAcceptClients;
public bool IsRunning { get; private set; }
public AsyncServerDemo(int port)
{
cancel = new CancellationTokenSource();
listener = new TcpListenerEx(IPAddress.Any, port);
}
private Task<string> WaitForMessageAsync(TcpClient client, CancellationToken token)
{
return Task.Run(() =>
{
StringBuilder sb = new StringBuilder();
bool dataAvailable = false;
while (!token.IsCancellationRequested)
{
while (client.Client.Available > 0)
{
dataAvailable = true;
int buffered = client.Client.Available;
byte[] buffer = new byte[buffered];
client.Client.Receive(buffer);
sb.Append(Encoding.ASCII.GetString(buffer));
}
if (dataAvailable)
{
dataAvailable = false;
return sb.ToString();
}
};
return string.Empty; //timeout
});
}
private Task AcceptClientAsync()
{
return Task.Factory.StartNew(async () =>
{
IsRunning = true && !cancel.IsCancellationRequested;
while (!cancel.IsCancellationRequested)
{
if (!listener.Pending())
{
continue;
}
TcpClient newClient = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
Stopwatch timeout = new Stopwatch();
timeout.Restart();
string message = await WaitForMessageAsync(newClient, new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
if (message != null)
{
//TODO: Message recieved
}
timeout.Stop();
}
});
}
public void Start()
{
listener.Start();
timerCallAcceptClients = new Timer(new TimerCallback((state) =>
{
AcceptClientAsync();
}), null, 0, (int)TimeSpan.FromSeconds(1).TotalMilliseconds);
}
public async void Stop()
{
if (!IsRunning) return;
using (cancel)
cancel.Cancel();
timerCallAcceptClients.Dispose();
if (WaitingForConnections != null)
await WaitingForConnections;
cancel = null;
listener.Stop();
IsRunning = false;
cancel = new CancellationTokenSource();
}
}
Client:
public class ClientExDemo
{
private Task<string> WaitForMessage;
private NetworkStream currentStream;
private CancellationTokenSource messageToken;
public EventHandler<ClientEx> OnServerFound;
public TcpClient Connection;
public EventHandler<string> OnMessage;
public async Task StartListenAsync(CancellationTokenSource token = null)
{
if (token == null)
messageToken = new CancellationTokenSource();
else
messageToken = token;
currentStream = Connection.GetStream();
string message = "";
if (message.Length > 0)
OnMessage?.Invoke(this, message);
if (!messageToken.IsCancellationRequested)
{
await StartListenAsync(token);
}
Timeout();
}
protected virtual void Timeout()
{
}
public async Task WaitForServerAsync(string ip, int port)
{
do
{
try
{
await Connection.ConnectAsync(ip, port);
}
catch (SocketException x)
{
}
await Task.Delay(50);
} while (!Connection.Connected);
}
public void StopListen()
{
using (messageToken)
{
messageToken.Cancel();
}
try
{
WaitForMessage.GetAwaiter().GetResult();
}
catch (AggregateException)
{
}
currentStream.Close();
messageToken = null;
currentStream = null;
WaitForMessage = null;
}
public ClientExDemo()
{
Connection = new TcpClient();
OnServerFound += ServerFound;
}
private void ServerFound(object sender, ClientEx args)
{
}
public void Send(string message)
{
Connection.Client.Send(Encoding.ASCII.GetBytes(message));
}
}
You can send messages from the client in a simple console application:
ClientEx client= new ClientEx();
await client.WaitForServerAsync(ip, port);
string msg = string.Empty;
do
{
Console.Write("Send Message: ");
msg = Console.ReadLine();
shell.Send(msg);
} while (msg != "q");
Console.WriteLine();
Console.WriteLine("BYE");
Console.ReadKey();
I am trying to write a program to control home automation devices. This involves a WebSocket server that runs infinitely in a background thread listening for clients. The client sends JSON packets that contain settings. When the server gets a JSON packet, I want it to read and change any settings as needed in the Main()
I have a working WebSocket server and I have tried to use the PropertyChangedEvent but it never seems to see the handler. I suspect this occurs because they exist in different threads.
I have attached my code below as well as the example I have been working off of. There is a chance I am way off the mark here but this is the best I could find with the reading I have been doing.
Any help would be appreciated!
This is the Main():
using System;
using System.Threading;
using System.ComponentModel;
namespace HomeAutomation
{
class Controller
{
static void Main(string[] args)
{
bool passGo = false;
Thread SocketThread = new Thread(Socket.WebSocketServer);
SocketThread.IsBackground = true;
SocketThread.Start();
//This line lets the user know the Socket Thread is running in the background
Console.WriteLine("Socket Thread is running in the background: {0}", SocketThread.IsBackground);
do {
char input = Console.ReadKey().KeyChar;
if (input == 'x')
{
passGo = true;
}
} while (passGo == false);
Console.ReadLine();
/*
Settings s = new Settings();
s.PropertyChanged += new PropertyChangedEventHandler(S_PropertyChanged);
while (true)
{
string str = Console.ReadLine();
s.State = str;
}*/
}
public static void S_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
Settings RecSettings = (Settings)sender;
Console.WriteLine("The {0} has changed to {1}", e.PropertyName, RecSettings.State);
}
}
public class Settings : INotifyPropertyChanged
//The Class Object 'Settings' is used to recieve the variable(s) from the client software
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
string state = string.Empty;
public string State
{
get { return state; }
set
{
state = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("State"));
Console.WriteLine("Event has been called");
}
}
}
}
}
This is my webSocket:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using Newtonsoft.Json;
namespace HomeAutomation
{
class Socket
{
public static void WebSocketServer()
{
//Declaring variables used in the program
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
TcpListener server = new TcpListener(ipAddress, 8080);
try
{
//Starts the server
server.Start();
Console.WriteLine("Starting Server...");
}
catch (Exception ex)
{
//If the server cannot start the error will be caught and printed to console
Console.WriteLine(ex.ToString());
Console.ReadLine();
}
while (true)
{
TcpClient client = server.AcceptTcpClient();
MakeNewConnection(client);
}
}
public static void MakeNewConnection(TcpClient client)
{
var thread = new Thread(NewClient);
thread.Start(client);
}
public static void NewClient(object data)
{
var client = (TcpClient)data;
Settings RecSettings = new Settings();
//Lets you know the address of the connected client
string address = client.Client.AddressFamily.ToString();
Console.WriteLine("{0} has connected!", address);
//creates a network stream for information to flow through
NetworkStream stream = client.GetStream();
byte[] receivedBuffer = new byte[100];
stream.Read(receivedBuffer, 0, receivedBuffer.Length);
StringBuilder msg = new StringBuilder();
foreach (byte b in receivedBuffer)
{
if (b.Equals(00))
{
break;
}
else
{
msg.Append(Convert.ToChar(b).ToString());
}
}
Console.WriteLine("Client Says: {0}", msg.ToString());
RecSettings = JsonConvert.DeserializeObject<Settings>(msg.ToString());
Console.WriteLine(RecSettings.State.ToString());
RecSettings.State = "Off";
int byteCount = Encoding.ASCII.GetByteCount("Thank you");
byte[] sendData = new byte[byteCount];
sendData = Encoding.ASCII.GetBytes("Thank you");
stream.Write(sendData, 0, sendData.Length);
}
}
}
This is the event handler example I am using:
using System;
using System.ComponentModel;
namespace HomeAutomation
{
class Program
{
static void Main(string[] args)
{
TestClass sample = new TestClass();
sample.PropertyChanged += new PropertyChangedEventHandler(sample_PropertyChanged);
while (true)
{
string str = Console.ReadLine();
int val;
if (int.TryParse(str, out val))
sample.TestValue = val;
}
}
static void sample_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
TestClass sample = (TestClass)sender;
/*
* Use expression behind if you have more the one property instead sample.TestValue
* typeof(TestClass).GetProperty(e.PropertyName).GetValue(sample, null)*/
Console.WriteLine("Value of property {0} was changed! New value is {1}", e.PropertyName, sample.TestValue);
}
}
public class TestClass : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
int testValue = 0;
public int TestValue
{
get { return testValue; }
set
{
testValue = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("TestValue"));
}
}
}
}
You may want to wrap the contents of your WebSocket response in code that invokes it in the Dispatcher thread.
System.Windows.Application.Current.Dispatcher.Invoke(new Action(() =>
{
... response handler code
}
Does starting many asynchronous operations could be a problem?
I'am writing TCP server where number of concurrent clients is upper bounded. I've came up with idea where server contains certain number of slots. Each slot starts asynchronous BeginAcceptTcpClient call on shared TcpListener instance. When client connects, first available asynchronous operation will return by callback. Then I can handle TcpClient instance and reanable slot by calling BeginAcceptTcpClient once again. With such architecture I don't have to manually care about synchronising counter to limit client connections. Incomming connection waits for reeanbling slots. But I'm not sure is it a good idea at all.
Sample console program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace SlotTcpServerSample
{
internal class Program
{
private class Slot : IDisposable
{
private TcpListener _listener;
private EventWaitHandle _closed;
public Slot(TcpListener listener)
{
_listener = listener;
_closed = new ManualResetEvent(false);
}
public void Open(AsyncCallback callback)
{
_listener.BeginAcceptTcpClient(callback, this);
}
public void Close()
{
_closed.Set();
}
public void WaitForClose()
{
_closed.WaitOne();
}
public void Dispose()
{
_closed.Close();
}
}
private class TcpServer
{
private const int MAX = 10;
private object _sync;
private Slot[] _slots;
private IPEndPoint _endpoint;
private TcpListener _listener;
public TcpServer(IPEndPoint endpoint)
{
_sync = new object();
_endpoint = endpoint;
}
public void Start()
{
lock (_sync)
{
if (_listener != null)
return;
_listener = new TcpListener(_endpoint);
_slots = new Slot[MAX];
for (int i = 0; i < MAX; i++)
_slots[i] = new Slot(_listener);
_listener.Start();
foreach (Slot slot in _slots)
slot.Open(HandleConnection);
}
}
public void Stop()
{
lock (_sync)
{
if (_listener == null)
return;
_listener.Stop();
foreach (Slot slot in _slots)
{
slot.WaitForClose();
slot.Dispose();
}
_listener = null;
}
}
private void HandleConnection(IAsyncResult asyncResult)
{
Slot slot = (Slot)asyncResult.AsyncState;
TcpClient client = null;
try
{
client = _listener.EndAcceptTcpClient(asyncResult);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
HandleClient(client);
try
{
slot.Open(HandleConnection);
}
catch (ObjectDisposedException ex)
{
slot.Close();
return;
}
}
private void HandleClient(TcpClient client)
{
Console.WriteLine("Connected: {0}", client.Client.RemoteEndPoint.ToString());
client.Close();
}
}
private static void Main(string[] args)
{
IPEndPoint endpoint = new IPEndPoint(IPAddress.Any, 8080);
TcpServer server = new TcpServer(endpoint);
try
{
Console.WriteLine("Starting...");
server.Start();
Console.WriteLine("Started");
Console.ReadLine();
Console.WriteLine("Stopping...");
server.Stop();
Console.WriteLine("Stopped");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}