How to Call an existing Class with Parameters? - c#

I´ve got a Class wich is called Clients on my multi threaded server.
My Question is how do i send data to an specified Client from another Class?
Here is my Listen Function from ServerMain Class.
public static List<Client> clients;
public static List<Thread> threads;
private void Listen()
{
clients = new List<Client>();
threads = new List<Thread>();
int id = 0;
while (true)
{
listenerSocket.Listen(0);
Log.Status(" Waiting for a connection...");
var commands = new ServerCommands();
//commands.Wait();
Client c1 = new Client(id, listenerSocket.Accept());
clients.Add(c1);
Log.Status("New Client Connected!");
Thread t = new Thread(c1.Start);
c1.SetThread = t;
t.Start();
id++;
}
}
And My Client Class with just one send Example
public class Client : IDisposable
{
public int _id;
public string _guid;
public string Name;
public Socket clientSocket;
private Thread thread;
public Client(int id, Socket socket)
{
this._id = id;
this._guid = Guid.NewGuid().ToString();
this.clientSocket = socket;
}
public Thread SetThread
{
set
{
this.thread = value;
}
}
public int Id
{
get
{
return this._id;
}
}
public void Receive()
{
byte[] buffer;
int readBytes;
while (clientSocket != null && clientSocket.Connected)
{
try
{
buffer = new byte[clientSocket.SendBufferSize];
readBytes = clientSocket.Receive(buffer);
if (readBytes > 0)
{
Packet p = new Packet(buffer);
if (p.Type != PacketType.Disconnect)
{
new Task(() => Received(p)).Start();
}
else
{
CloseConnection();
}
}
}
catch (SocketException e)
{
Console.WriteLine(e);
CloseConnection();
}
}
}
////////// Example Send Fuction ////////////
private void Register(User user)
{
var res = Handler.RegisterDo(user);
clientSocket.Send(res.ToBytes());
}
}
I know i can send to all Connected Clients like this
foreach(Client item in ServerMain.clients) //Client clients
{
Console.WriteLine(item._id);
Console.WriteLine(item.Name);
Console.WriteLine(item._guid);
};
Am I missing something to identify?
The id Could do it (i think) but how do I call it then from outside?

In my understand of your code, you just wrapper the 'client' connection socket as the class client. you just need to call the 'this.clientSocket' field of the client class to send() or receive() data.

Related

Create async method for queued timer based HTTP call

I have a class, which holds a queue of requests, which will be collected and send to an Web API via HTTP call after a time interval of max 1 second:
public class AsyncValueTimerIntervalWriter
{
private class ValueRequest
{
public string FullName { get; set; }
public object Value { get; set; }
}
private readonly IValuesClient _valuesClient; // auto generated Swagger HTTP client
private List<ValueRequest> _valueRequests = new List<ValueRequest>();
private object _valuesLock = new object();
private Timer _timer;
public AsyncValueTimerIntervalWriter(IValuesClient valuesClient)
{
_valuesClient = valuesClient;
}
public void Start()
{
_timer = new Timer(o => WriteValuesToServer(), null, 0, 1000);
}
public void Stop()
{
_timer?.Dispose();
_timer = null;
}
public void AddWrite(string fullName, object value)
{
lock (_valuesLock)
{
_valueRequests.Add(new ValueRequest { FullName = fullName, Value = value });
}
}
private async void WriteValuesToServer()
{
IList<ValueRequest> values;
lock (_valuesLock)
{
values = _valueRequests.ToArray();
_valueRequests.Clear();
}
if (values.Any())
{
await _valuesClient.SetValuesAsync(values); // Sends HTTP POST request
}
}
}
Caller example:
var asyncWriter = new AsyncValueTimerIntervalWriter(...);
asyncWriter.AddWrite("My.Var.Tree.VarName", 1234);
asyncWriter.AddWrite("My.Var.Tree.AnotherVar", "Test");
// after max 1 sec the values are written to server
My goal is to write an async method, which also adds a value to write, and returns when the value is written:
await asyncWriter.WriteAsync("My.Var.Tree.VarName", 1234);
// should continue after written to server
Important: I need to handle requests in a queue, because the writer may be stopped at any time and it is not allowed to loose requests. After start the writer again, the added requests needs to be send to server.
I tried to use the ManualResetEvent, but it feels strange:
...
public Task WriteAsync(string fullName, object value)
{
var resetEvent = new ManualResetEvent(false);
lock (_valuesLock)
{
_valueRequests.Add(
new ValueRequest
{
FullName = fullName,
Value = value,
CompletedEvent = resetEvent
});
}
resetEvent.WaitOne();
return Task.CompletedTask;
}
private async void WriteValuesToServer()
{
IList<ValueRequest> values;
lock (_valuesLock)
{
values = _valueRequests.ToArray();
_valueRequests.Clear();
}
if (values.Any())
{
await _valuesClient.SetValuesAsync(values); // Sends HTTP POST request
foreach (var value as values)
value.CompletedEvent?.Set();
}
}
...
Any suggestions?
You can use a TaskCompletionSource within the ValueEntry class to pass a signal from the writer to the caller.
private class ValueEntry
{
public string FullName { get; set; }
public object Value { get; set; }
protected readonly TaskCompletionSource _tcs = new TaskCompleteionSource();
public Task AwaitCompletion()
{
return _tcs.Task;
}
public Task MarkComplete()
{
return _tcs.SetResult();
}
}
Small change to WriteValuesToServer:
public async Task WriteValuesToServer()
{
// snip
if (values.Any())
{
await _emsClient.SetValuesAsync(values); // Sends HTTP POST request
foreach (var value as values)
await value.MarkComplete();
}
}
Now your writer is very simple:
public Task WriteAsync(string fullName, object value)
{
var request = new ValueRequest { FullName = fullName, Value = value };
lock (_valuesLock)
{
_valueRequests.Add(request)
};
await request.AwaitCompletion();
}
Also, I suggest you look into using a BlockingCollection, which is designed to handle a producer/consumer queue, and would allow you to get rid of most of your lock blocks.

Continuous async pinger class: InvalidOperation on Progress (List modified during enumeration)

I'm trying to write a class that continuosly ping "in background" a list of one or more devices, and report the results to a Progress object in the GUI main class. Im very new with async/await and Tasks, but my code seems to work fine on my pc, even if i know its not so good designed. But when i start the application in a different computer it throws an InvalidOperationException from the Progress object because the Dictionary in is changed. I think it happens when i assign a new PingService to the same variable.
The PingService class starts pinging (SendPingAsync) a list of IP's on a function with a inf. loop that updates the PingServiceReply object for each iteration of the list and then "reporting" it to the Progress object.
What is the way for get it done, and what im doing wrong?
Here's the code.
PingSeviceReply class
public class PingServiceReply
{
private Dictionary<string, bool> ipDictionary;
internal PingServiceReply()
{
ipDictionary = new Dictionary<string, bool>();
}
public void SetIpStatus(string ip, bool status)
{
if (ipDictionary.ContainsKey(ip))
{
ipDictionary[ip] = status;
}
else
{
ipDictionary.Add(ip, status);
}
}
public Dictionary<string, bool> GetStatusDictionary()
{
return ipDictionary;
}
public bool AreAllOnline()
{
foreach (bool value in ipDictionary.Values)
{
if (!value)
{
return false;
}
}
return true;
}
}
PingService class
public class PingService
{
private string name;
private List<string> ipList;
private IProgress<PingServiceReply> progress;
private CancellationTokenSource cts;
private int timeout;
private Task tsk;
public PingService(string name, List<string> ipList, int timeoutInMillliseconds, IProgress<PingServiceReply> progress)
{
this.name = name;
this.ipList = ipList;
this.progress = progress;
this.timeout = timeoutInMillliseconds;
}
public PingService(string name, string ip, int timeoutInMillliseconds, IProgress<PingServiceReply> progress)
{
this.name = name;
this.ipList = new List<string>();
ipList.Add(ip);
this.progress = progress;
this.timeout = timeoutInMillliseconds;
}
public PingService()
{
cts = new CancellationTokenSource();
}
private async Task ContinuousPingAsync()
{
var ping = new System.Net.NetworkInformation.Ping();
PingReply singleResponse;
PingServiceReply ruleResponse = new PingServiceReply();
while (!cts.Token.IsCancellationRequested)
{
foreach (string ip in ipList)
{
singleResponse = await ping.SendPingAsync(ip, timeout).ConfigureAwait(false);
ruleResponse.SetIpStatus(ip, singleResponse.Status == IPStatus.Success);
}
progress.Report(ruleResponse);
}
}
public void StartService()
{
cts = new CancellationTokenSource();
tsk = ContinuousPingAsync();
}
public void StopService()
{
cts.Cancel();
}
public string GetName()
{
return name;
}
}
The progress object
IProgress<PingServiceReply> pingProgress = new Progress<PingServiceReply>(HandleSinglePing);
private void HandleSinglePing(PingServiceReply report)
{
if (report.AreAllOnline())
{
//online
}
else
{
//offline
}
}
How i use all in the gui class, on the combobox selectedItemChanged event
comboService.StopService();
comboService = new PingService("Combo", (string) comboBox.SelectedItem, 1000, pingProgress);
comboService.StartService();

Making asynchronous API synchronous

I am connecting to an API to get some data that is defined like this:
A client object ClientConnection, which allows one to send requests.
A IApi interface that needs to be passed to the ClientConnection to receive callbacks.
Schematically it looks like this:
// defined in the API dll
public class ClientConnection {
public ClientConnection(IApi api) { ... }
public void request(int reqid, string reqdetails) { ... }
}
interface IApi
{
void receiveData(int reqid, string ans);
}
Now, obviously this is a fairly standard asynchronous way of doing things: send requests through a global object, with a requestid, and receive answers tagged with that requestid.
I want to create a wrapper that is synchronous. What would be the most natural way of doing this? Is there a smart way of using async await, instead of using thread locking and stuff?
class MyWrapper : IApi
{
private ClientConnection _client;
private int _reqToken = 0;
public MyWrapper()
{
_client = new ClientConnection(this);
}
public string getData(string reqdetails)
{
_client.request(_reqToken++, reqdetails);
// what to do here?
}
public void receiveData(int reqid, string data) {
// what to do here?
}
}
Didn't test the code below, but it should give you the idea. Basically you can use ManualResetEvent to be signalled when you receive your result (and don't ever call this without proper timeout):
class MyWrapper : IApi {
private ClientConnection _client;
// here you store your requests
private Dictionary<int, PendingRequest> _pendingRequests = new Dictionary<int, PendingRequest>();
private int _reqToken = 0;
public MyWrapper() {
_client = new ClientConnection(this);
}
public string getData(string reqdetails, TimeSpan timout) {
// if this is multithreaded - lock over _pendingRequests when you add\remove requests there
// and when you increment your _reqToken, or use concurrent collection
using (var token = new PendingRequest()) {
var id = _reqToken;
// lock here
_pendingRequests.Add(id, token);
_client.request(id, reqdetails);
// and here use Interlocked.Increment
_reqToken++;
if (!token.Signal.WaitOne(timout)) {
// and here
_pendingRequests.Remove(id);
// timeout
throw new Exception("timout");
}
// if we are here - we have the result
return token.Result;
}
}
public void receiveData(int reqid, string data) {
// here you might need to lock too
if (_pendingRequests.ContainsKey(reqid)) {
var token = _pendingRequests[reqid];
_pendingRequests.Remove(reqid);
token.Complete(data);
}
}
private class PendingRequest : IDisposable {
public PendingRequest() {
Signal = new ManualResetEvent(false);
}
public ManualResetEvent Signal { get; private set; }
public string Result { get; private set; }
public void Complete(string result) {
this.Result = result;
Signal.Set();
}
public void Dispose() {
Signal.Dispose();
}
}
}

I get an Exception InvalidOperationException and I don't know why

This is a part of chat with multi users and I want to deserialize in loop so every message I am getting for each user I have a can publish (this is the server side)
public class ServerDLL
{
public TcpClient client { get; set; }
public TcpListener listner { get; set; }
public List<NetworkStream> clientStream = new List<NetworkStream>();
public List<TcpClient> clientsList = new List<TcpClient>();
string clientMsg;
BinaryFormatter formatter = new BinaryFormatter();
private object clientListLock = new object();
public void startConnection()
{
Thread listnerThread = new Thread(ListnerFunc);
listner.Start();
listnerThread.Start();
Thread waitForMeesage = new Thread(WaiterFunc);
waitForMeesage.Start();
}
public void ListnerFunc()
{
while (true)
{
client = listner.AcceptTcpClient();
clientStream.Add(client.GetStream());
if (client.Connected)
{
lock (clientListLock)
{
clientsList.Add(client);
}
}
}
}
public void WaiterFunc()
{
while (true)
{
lock (clientListLock)
{
foreach (NetworkStream stream in clientStream)
{
if (stream != null)
{
clientMsg = formatter.Deserialize(stream).ToString();
}
}
}
}
}
now the exception pops when I send the message from the client..
First, you really should put some sort of wait in your WaiterFunc(). Spinning the CPU like that is not a good idea.
That being said, you have a cross-thread shared resource in the clientStream collection. You can't modify a collection during enumeration (which your while loop does constantly), thus throwing the exception.
You need a lock around access to this list:
private object clientListLock = new object();
public void ListnerFunc()
{
while (true)
{
client = listner.AcceptTcpClient();
lock(clientListLock)
{
clientStream.Add(client.GetStream());
if (client.Connected)
{
clientsList.Add(client);
}
}
}
}
public void WaiterFunc()
{
while (true)
{
lock (clientListLock)
{
foreach (NetworkStream stream in clientStream)
{
clientMsg = formatter.Deserialize(stream).ToString();
}
}
}
}

Sending data over a socket using parallels

I have an application that opens a socket and sends information over it. This functionality is encapsulated in a class.
I thought that it could be easy to work in parallel if I run this feature with Parallel.ForEach. In this way, each task would open/close a socket and send over it (to the same ip/port). This solution doesn't works.
Second way, I am implementing the socket operation in asynchronous way, and the behavior is that the server receives all data from first task and later the rest of data from other task. From the server side, there's no parallel behavior.
I am searching and reading information about this but I can't solve this problem.
Any ideas? Do you have a complete sample of using socket with Parallel library? Or any complete sample of using sockets in multithreading environment?
Complementary information:
I have a LINQ expression that returns a list of files. This list is processed as this:
Parallel.ForEach(AllFiles, new ParallelOptions { MaxDegreeOfParallelism = _maxDegreeOfParallelism }, currentFile =>
{
ProcessFiles(currentFile);
});
...
ProcessFiles sumarized:
void ProcessFile (string currentFile)
{
MyTcpClient client = null;
try
{
var AllLinesInFiles = // LINQ Expression that returns a list of strings
int port = 23000;
client = new MyTcpServer(ip, port);
foreach (string data in AllLinesInFiles)
{
if (data.Length > 0)
{
if (!client.IsOk)
{
client.Connect(false);
if (!client.IsOk)
break;
}
client.SendMessage(tmpLine2);
}
}
}
catch (Exception ex)
{
...
}
finally
{
if ((client != null) && (client.IsOk))
client.Close();
}
}
MyTcpClient, synchronous version is:
public class MyTcpClient : IDisposable
{
private static object objLock = new object();
public int Port = ...
public IPAddress IPAddress = ...
private string _Host;
private TcpClient _client = null;
private Stream _stream = null;
static MyTcpClient()
{
}
public MyTcpClient(string PassedIPAddress, Int32 PassedPort)
{
try
{
this.IPAddress = PassedIPAddress;
this.Port = PassedPort;
}
catch (Exception ex)
{
...
}
}
public TcpClient TcpClient
{
get { return _client; }
set { _client = value; }
}
public X509Certificate Certificate
{
get { return _certificate; }
set { _certificate = value; }
}
public bool IsOk
{
get
{
return ((_client != null) && (_client.Connected));
}
}
public void Connect(bool isSecure)
{
if (IsOk == false)
{
_client = new TcpClient(this.IPAddress.ToString(), this.Port);
_stream = null;
try
{
NetworkStream networkStream = _client.GetStream();
_stream = (NetworkStream)networkStream;
}
catch (AuthenticationException ex)
{
...
}
catch (Exception ex)
{
...
}
finally
{
}
}
}
public void SendMessage(string message)
{
if (_client != null && IsOk)
{
byte[] dgram = EncodingHelper.GetEncoding().GetBytes(message);
lock (MyTcpClient.objLock)
{
_stream.Write(dgram, 0, dgram.Length);
}
}
}
public void SendMessage(byte[] dgram)
{
if (_client != null && IsOk)
{
lock (MyTcpClient.objLock)
{
_stream.Write(dgram, 0, dgram.Length);
}
}
}
public void Close()
{
this.Dispose();
}
public void Dispose()
{
if (_stream != null)
{
_stream.Close();
}
if (_client != null)
{
_client.Close();
}
}
}
And for the Asynchronous version I have used the example here http://msdn.microsoft.com/en-us/library/bew39x2a.aspx
When I use asynchronous socket client, I update ProcessFile method but, the idea is open/close the socket in this method.

Categories