C#, .Net 4.5. I have a queue that contains objects which are to be processed. Processing includes obtaining data with the URL which specified in one of the fields of the object. In the course of operation the new objects can be added to the queue. When I tried to do the work with the network asynchronous, I faced with a problem.
Here is a minimum code.
public partial class Form1 : Form
{
private void button1_Click(object sender, EventArgs e)
{
string[] urls = { "http://www.stackoverflow.com/",
"http://www.google.com/",
"http://www.microsoft.com/" };
int i = 0;
Queue<MyClass1> queue = new Queue<MyClass1>();
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(urls[i]);
webRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
queue.Enqueue(new MyClass1(urls[i], webRequest.GetResponseAsync()));
while (queue.Count > 0)
{
MyClass1 o = queue.Dequeue();
o.RespTask.Wait();
Debug.Print("Url: {0}, bytes: {1}", o.Url,
o.RespTask.Result.ContentLength);
i++;
if (i < urls.Length)
{
webRequest = (HttpWebRequest)WebRequest.Create(urls[i]);
webRequest.Proxy.Credentials = CredentialCache.DefaultCredentials;
queue.Enqueue(new MyClass1(urls[i], webRequest.GetResponseAsync()));
}
}
}
}
public class MyClass1
{
public MyClass1() { }
public MyClass1(string url, Task<WebResponse> respTask)
{
Url = url;
RespTask = respTask;
}
public string Url;
public Task<WebResponse> RespTask;
}
That code hangs on o.RespTask.Wait(); on third iteration of cycle. Before this call o.RespTask.Status has value WaitingForActivation and waiting lasts forever. What am I doing wrong?
UPDATE. I checked the code on 3 boxes. On two of them (Win7 32-bit and Win7 64-bit) the program hangs. On the third (Win7 64-bit) everything is working fine. It seems to me very strange.
This code has ceased to hang after such a modification:
...
Debug.Print("Url: {0}, bytes: {1}", o.Url,
o.RespTask.Result.ContentLength);
o.RespTask.Result.Close();
i++;
...
My mistake was that I did not pay attention to the fact that the call to the Close method of the HttpWebResponse class is a must.
Related
I'm creating a UWP program for Raspberry Pi. One of the functions of the program is to send and receive some data from an Arduino.
The problem is when I try sending data to the Arduino rapidly and many times, I end up with System.Runtime.InteropServices.COMException The operation identifier is not valid. originating from DataWriter.DetachStream().
Sending the data rapidly works just fine, up until a certain amount it seems, where I get the exception thrown.
With "rapid", I mean using an auto clicker to click a button to send data each millisecond.
I've not tried sending data slowly many times in a row to reproduce the issue, as this would probably take a long time (seeing it takes about 10-20 seconds with 1ms delay between transmissions.
I've been searching for a solution to this problem for way too many hours, but I can't seem to find any related questions/solutions.
public sealed partial class LightControl : Page
{
int Alpha;
int Red;
int Green;
int Blue;
// This is the handler for the button to send data
private void LightButton_Click(object sender, RoutedEventArgs e)
{
if (!(sender is Button button) || button.Tag == null) return;
string tag = button.Tag.ToString();
Alpha = int.Parse(tag.Substring(0, 2), System.Globalization.NumberStyles.HexNumber);
Red = int.Parse(tag.Substring(2, 2), System.Globalization.NumberStyles.HexNumber);
Green = int.Parse(tag.Substring(4, 2), System.Globalization.NumberStyles.HexNumber);
Blue = int.Parse(tag.Substring(6, 2), System.Globalization.NumberStyles.HexNumber);
SendLightData();
}
public async void SendLightData()
{
await ArduinoHandler.Current.WriteAsync(ArduinoHandler.DataEnum.LightArduino,
ArduinoHandler.DataEnum.Light, Convert.ToByte(LightConstants.LightCommand.LightCommand),
Convert.ToByte(Red), Convert.ToByte(Green), Convert.ToByte(Blue), Convert.ToByte(Alpha),
WriteCancellationTokenSource.Token);
}
}
public class ArduinoHandler
{
// Code for singleton behaviour. Included for completeness
#region Singleton behaviour
private static ArduinoHandler arduinoHandler;
private static Object singletonCreationLock = new Object();
public static ArduinoHandler Current
{
get
{
if (arduinoHandler == null)
{
lock (singletonCreationLock)
{
if (arduinoHandler == null)
{
CreateNewArduinoHandler();
}
}
}
return arduinoHandler;
}
}
public static void CreateNewArduinoHandler()
{
arduinoHandler = new ArduinoHandler();
}
#endregion
private DataWriter dataWriter;
private Object WriteCancelLock = new Object();
public async Task WriteAsync(DataEnum receiver, DataEnum sender,
byte commandByte1, byte dataByte1, byte dataByte2, byte dataByte3,
byte dataByte4, CancellationToken cancellationToken)
{
try
{
dataWriter = new DataWriter(arduinos[receiver].OutputStream);
byte[] buffer;
Task<uint> storeAsyncTask;
lock (WriteCancelLock)
{
buffer = new byte[8];
buffer[0] = Convert.ToByte(receiver);
buffer[1] = Convert.ToByte(sender);
buffer[2] = commandByte1;
buffer[3] = dataByte1;
buffer[4] = dataByte2;
buffer[5] = dataByte3;
buffer[6] = dataByte4;
buffer[7] = Convert.ToByte('\n');
cancellationToken.ThrowIfCancellationRequested();
dataWriter.WriteBytes(buffer);
storeAsyncTask = dataWriter.StoreAsync().AsTask(cancellationToken);
}
uint bytesWritten = await storeAsyncTask;
Debug.Write("\nSent: " + BitConverter.ToString(buffer) + "\n");
}
catch (Exception e)
{
Debug.Write(e.Message);
}
finally
{
dataWriter.DetachStream(); // <--- I've located the exception to originate from here, using the debugger in Visual Studio
dataWriter.Dispose();
}
}
public enum DataEnum
{
Light = 0x01,
Piston = 0x02,
PC = 0x03,
LightArduino = 0x04
}
}
I would expect the Raspberry Pi to send the data to the Arduino, but after a while with rapid data transmission, the exception is thrown.
Update
I tried using a local variable for the dataWriter as suggested below, but this causes strange behavior after a while with rapid data transmission. Just as if it slows down. It is worth noting that I don't get an exception anymore.
Quite hard trying to explain how it behaves, but the Debug.Write logs the message I'm sending (which works fine). However, after a while, it seems to "slow down", and even after I stop clicking, the data is being sent once every second or so. It works completely fine up until this point. So I'm wondering if there is a limit of some sort I'm hitting?
Update 2
I seem to have found a rather "hacky" and weird solution to the problem.
If I use Serial.write() on the Arduino to send the data back to the Raspberry Pi, it seems to have fixed the issue somehow.
If anyone knows how this worked, I'd be very interested to know :)
const int payloadSize = 8;
byte payload[payloadSize]
int numBytes;
// Called each time serial data is available
void serialEvent()
{
numBytes = Serial.available();
if (numBytes == payloadSize)
{
for (int i = 0; i < payloadSize; i++)
{
payload[i] = Serial.read();
Serial.write(payload[i]); // <--- This line fixed the issue for whatever reason
}
}
checkData(); // Function to do something with the data
for (int i = 0; i < payloadSize; i++)
{
payload[i] = None;
}
numBytes = 0;
}
Your problem originates from the fact that you are using a fire-and-forget approach of working with async method. When you call SendLightData() in quick succession, it doesn't wait for the previous WriteAsync operation to complete.
Once the execution reaches the first actual await expression - which is the await storeAsyncTask line, the UI thread is freed up to handle another button click.
This new button click can start executing and overwrite the dataWriter field in the same instance of ArduinoHandler. When the first storeAsyncTask finishes executing, it will actually datach the dataWriter of the second call, not its own. This can lead to multiple different sorts of issues and race conditions.
So you must make sure that it is not possible to click the button before the previous operation actually executes. You could use a boolean flag for that as a simple solution.
private bool _isWorking = false;
public async void SendLightData()
{
if (!_isWorking)
{
try
{
_isWorking = true;
await ArduinoHandler.Current.WriteAsync(ArduinoHandler.DataEnum.LightArduino,
ArduinoHandler.DataEnum.Light, Convert.ToByte(LightConstants.LightCommand.LightCommand),
Convert.ToByte(Red), Convert.ToByte(Green), Convert.ToByte(Blue), Convert.ToByte(Alpha),
WriteCancellationTokenSource.Token);
}
finally
{
_isWorking = false;
}
}
This will ensure that two operations never execute simultaneously.
Other solution could be to not store the data writer as a field and just have it as a local variable. When you avoid all shared state between the calls, you can safely know that there will be no race condition stemming from overwriting.
I want to make a chat. The server is made in console app and the client is made in winforms.
In client I write a nickname and connect to server. The server receives name from client. I add all clients that connect to server in a Dictionary list with the (string)name and (TcpClient)Socket. After, I want to send to every client the client list.
When I debug on server, the Sockets appear with DualMode,EnableBroadcast error. In client when I have to receive the list it stops and doesn't do anything.
Server
namespace MyServer
{
class MyServer
{
public Dictionary<string, TcpClient> clientList = new Dictionary<string, TcpClient>();
TcpListener server = null;
NetworkStream stream = null;
StreamReader streamReader = null;
StreamWriter streamWriter = null;
TcpClient clientSocket;
String messageReceived;
int number_clients = 0;
public MyServer(TcpClient clientSocket_connect)
{
stream = clientSocket_connect.GetStream();
streamReader = new StreamReader(stream);
streamWriter = new StreamWriter(stream);
receiveMessage(clientSocket_connect); // receive messages
}
public MyServer()
{
Thread thread = new Thread(new ThreadStart(run));
thread.Start();
}
public void receiveMessage(TcpClient client_Socket)
{
messageReceived = streamReader.ReadLine();
if (messageReceived.Substring(messageReceived.Length - 4) == "user")
{
String name = messageReceived.Substring(0, messageReceived.Length - 4);
bool found = false;
foreach (var namefound in clientList.Keys)
{
if (namefound == name)
{
found = true;
streamWriter.WriteLine("The user already exists");
streamWriter.Flush();
}
}
if (!found)
{
//show who's connected
Console.WriteLine(name + " is online");
number_clients++;
clientList.Add(name, client_Socket);
//send to client clientlist
String send = null;
foreach (var key in clientList.Keys)
{
send += key + ".";
}
foreach (var value in clientList.Values)
{
TcpClient trimitereclientSocket = value;
if (trimitereclientSocket != null)
{
NetworkStream networkStream = trimitereclientSocket.GetStream();
StreamWriter networkWriter = new StreamWriter(networkStream);
networkWriter.WriteLine(send + "connected");
networkWriter.Flush();
}
}
}
}
}
void run()
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
server = new TcpListener(ipAddress, 8000);
server.Start();
Console.WriteLine("Server started!");
while (true)
{
clientSocket = server.AcceptTcpClient();
new MyServer(clientSocket);
}
}
}
static void Main(string[] args)
{
MyServer server = new MyServer();
}
}
Client
namespace MyClient
{
class MyClient
{
List<string> clientList = new List<string>();
TcpClient client = null;
NetworkStream stream = nul
l;
StreamReader streamReader = null;
StreamWriter streamWriter = null;
bool connected;
String received_message;
public MyClient()
{
client = new TcpClient("127.0.0.1", 8000);
stream = client.GetStream();
streamReader = new StreamReader(stream);
streamWriter = new StreamWriter(stream);
}
public void sendClientName(String name)
{
streamWriter.WriteLine(Convert.ToString(name));
streamWriter.Flush();
}
public List<ClientName> receiveClientList()
{
List<ClientName> val = new List<ClientName>();
string name = Convert.ToString(streamReader.ReadLine());
if (name.Substring(0, name.Length - 9) == "connected")
{
ClientName client = new ClientName();
client.Nume = name;
val.Add(client);
}
return val;
}
}
}
Client Form
public partial class Form1 : Form
{
MyClient client = new MyClient();
public Form1()
{
InitializeComponent();
Thread receiveClients = new Thread(new ThreadStart(getMessages));
}
private void btnConnect_Click(object sender, EventArgs e)
{
client.sendClientName(txtNickname.Text + "user");
}
public void getMessages()
{
while (true)
{
lbClientsConnected.Items.Add(client.receiveClientList());
}
}
}
I was unable to reproduce any error when running your code. I don't know what you mean by "the Sockets appear with DualMode,EnableBroadcast error". That said, there are a number of fixable problems with the code, including some that pertain directly to your concern that "when I have to receive the list it stops and doesn't do anything."
Probably the biggest issue with the code is that you simply never start the client's receiving thread. You need to call the Start() method on the Thread object after it's been created:
public Form1()
{
InitializeComponent();
Thread receiveClients = new Thread(new ThreadStart(getMessages));
// The receiving thread needs to be started
receiveClients.Start();
}
Now, even with that fixed, you have a few other problems. The next big issue is that you are parsing the received text incorrectly. In your code, where you should be looking for the text "connected" at the end of the string, you instead extract the other part of the text (with the list of client names).
Your receiveClientList() method should instead look like this:
private const string _kconnected = "connected";
public List<string> receiveClientList()
{
List<string> val = new List<string>();
string name = Convert.ToString(streamReader.ReadLine());
// Need to check the *end* of the string for "connected" text,
// not the beginning.
if (name.EndsWith(_kconnected))
{
name = name.Substring(0, name.Length - _kconnected.Length);
val.Add(name);
}
return val;
}
(You didn't share the ClientName class in your question, and really the example doesn't need it; a simple string value suffices for the purpose of this exercise. ALso, I've introduced the const string named _kconnected, to ensure that the string literal is used correctly in each place it's needed, as well as to simplify usage.)
But even with those two issues fixed, you've still got a couple in the Form code where you actually handle the return value of the receive method. First, you are passing the List<T> object that is returned from the receive method to the ListBox.Items.Add() method, which would just result in the ListBox displaying the type name for the object, rather than its elements.
Second, because the code is executing in a thread other than the UI thread that owns the ListBox object, you must wrap the call in a call to Control.Invoke(). Otherwise, you'll get a cross-thread operation exception.
Fixing those two issues, you get this:
public void getMessages()
{
while (true)
{
// Need to receive the data, and the call Invoke() to add the
// data to the ListBox. Also, if adding a List<T>, need to call
// AddRange(), not Add().
string[] receivedClientList = client.receiveClientList().ToArray();
Invoke((MethodInvoker)(() => listBox1.Items.AddRange(receivedClientList)));
}
With those changes, the code will process the message sent by the client, and return the list of clients. That should get you further along. That said, you still have a number of other problems, including some fairly fundamental ones:
The biggest issue is that when you accept a connection in the server, you create a whole new server object to handle that connection. There are a number of reasons this isn't a good idea, but the main one is that the rest of the code seems to conceptually assume that a single server object is tracking all of the clients, but each connection will result in its own collection of client objects, each collection having just one member (i.e. that client).
Note that once you've fixed this issue, you will have multiple threads all accessing a single dictionary data structure. You will need to learn how to use the lock statement to ensure safe shared use of the dictionary across multiple threads.
Another significant problem is that instead of using the streamWriter you created when you first accepted the connection, you create a whole new StreamWriter object (referenced in a local variable named networkWriter) to write to the socket. In this very simple example, it works fine, but between buffering and the lack of thread safety, this incorrectly-designed code could have serious data corruption problems.
Less problematic, but worth fixing, is that your server code completely fails to take advantage of the fact that you're storing the clients in a dictionary, as well as that .NET has useful helper functions for doing things like joining a bunch of strings together. I would write your server's receiveMessage() method something more like this:
private const string _kuser = "user";
public void receiveMessage(TcpClient client_Socket)
{
messageReceived = streamReader.ReadLine();
if (messageReceived.EndsWith(_kuser))
{
String name = messageReceived.Substring(0, messageReceived.Length - _kuser.Length);
if (clientList.ContainsKey(name))
{
streamWriter.WriteLine("The user already exists");
streamWriter.Flush();
return;
}
//show who's connected
Console.WriteLine(name + " is online");
number_clients++;
clientList.Add(name, client_Socket);
string send = string.Join(".", clientList.Keys);
foreach (var value in clientList.Values.Where(v => v != null))
{
// NOTE: I didn't change the problem noted in #2 above, instead just
// left the code the way you had it, mostly. Of course, in a fully
// corrected version of the code, your dictionary would contain not
// just `TcpClient` objects, but some client-specific object specific
// to your server implementation, in which the `TcpClient` object
// is found, along with the `StreamReader` and `StreamWriter` objects
// you've already created for that connection (and any other per-client
// data that you need to track). Then you would write to that already-
// existing `StreamWriter` object instead of creating a new one each
// time here.
NetworkStream networkStream = value.GetStream();
StreamWriter networkWriter = new StreamWriter(networkStream);
networkWriter.WriteLine(send + "connected");
networkWriter.Flush();
}
}
}
The above is not exhaustive by any means. Frankly, you probably should spend more time looking at existing examples of network-aware code, e.g. on MSDN and Stack Overflow, as well as on tutorials on web sites, blogs, or in books. Even when you write the server in a one-thread-per-connection way as you seem to be trying to do here, there are lots of little details you really need to get correct, and which you haven't so far.
But I do hope the above is enough to get you past your current hurdle, and on to the next big problem(s). :)
I need to send HTTP requests with all the standard RESTful methods and access to the body of the request in order to send/receive JSON with it. I've looked into,
WebRequest.HttpWebRequest
This works almost perfectly, but there are cases where, for example, if the server is down the function GetResponse can take several seconds to return- since it is a synchronous method- freezing the application for that period. The asynchronous version of this method, BeginGetResponse, does not seem to work asynchronously (in Unity anyway) as it still freezes the application for that period.
UnityEngine.WWW#
Only supports POST and GET requests for some reason- but I also need PUT and DELETE (standard RESTful methods) so I didn't bother looking into it any further.
System.Threading
In order to run WebRequest.HttpWebRequest.GetResponse without freezing the application I looked into using threads. Threads seem to work in the editor (but seem extremely volatile- if you don't stop a thread when the application exits it keeps running in the editor forever even when you stop it), and when built to an iOS device crash it as soon as I try to start a thread (I forgot to write down the error and I don't have access to it right now).
Run threads in a native iOS app with a bridge to the Unity app
Ridiculous, not even going to attempt this.
UniWeb
This. I would like to know how they managed it.
Here is an example of the WebRequest.BeginGetResponse method I am trying,
// The RequestState class passes data across async calls.
public class RequestState
{
const int BufferSize = 1024;
public StringBuilder RequestData;
public byte[] BufferRead;
public WebRequest Request;
public Stream ResponseStream;
// Create Decoder for appropriate enconding type.
public Decoder StreamDecode = Encoding.UTF8.GetDecoder();
public RequestState()
{
BufferRead = new byte[BufferSize];
RequestData = new StringBuilder(String.Empty);
Request = null;
ResponseStream = null;
}
}
public class WebRequester
{
private void ExecuteRequest()
{
RequestState requestState = new RequestState();
WebRequest request = WebRequest.Create("mysite");
request.BeginGetResponse(new AsyncCallback(Callback), requestState);
}
private void Callback(IAsyncResult ar)
{
// Get the RequestState object from the async result.
RequestState rs = (RequestState) ar.AsyncState;
// Get the WebRequest from RequestState.
WebRequest req = rs.Request;
// Call EndGetResponse, which produces the WebResponse object
// that came from the request issued above.
WebResponse resp = req.EndGetResponse(ar);
}
}
... based on this: http://msdn.microsoft.com/en-us/library/86wf6409(v=vs.71).aspx
Ok, I finally managed to write my own solution. We basically need a RequestState, a Callback Method and a TimeOut Thread. Here I'll just copy what was done in UnifyCommunity (now called unity3d wiki). This is outdated code, but smaller than what's there, so more convenient to show something here. Now I've removed (in the unit3d wiki) System.Action and static for performance and simplicity:
Usage
static public ThisClass Instance;
void Awake () {
Instance = GetComponent<ThisClass>();
}
static private IEnumerator CheckAvailabilityNow () {
bool foundURL;
string checkThisURL = "http://www.example.com/index.html";
yield return Instance.StartCoroutine(
WebAsync.CheckForMissingURL(checkThisURL, value => foundURL = !value)
);
Debug.Log("Does "+ checkThisURL +" exist? "+ foundURL);
}
WebAsync.cs
using System;
using System.IO;
using System.Net;
using System.Threading;
using System.Collections;
using UnityEngine;
/// <summary>
/// The RequestState class passes data across async calls.
/// </summary>
public class RequestState
{
public WebRequest webRequest;
public string errorMessage;
public RequestState ()
{
webRequest = null;
errorMessage = null;
}
}
public class WebAsync {
const int TIMEOUT = 10; // seconds
/// <summary>
/// If the URLs returns 404 or connection is broken, it's missing. Else, we suppose it's fine.
/// </summary>
/// <param name='url'>
/// A fully formated URL.
/// </param>
/// <param name='result'>
/// This will bring 'true' if 404 or connection broken and 'false' for everything else.
/// Use it as this, where "value" is a System sintaxe:
/// value => your-bool-var = value
/// </param>
static public IEnumerator CheckForMissingURL (string url, System.Action<bool> result) {
result(false);
Uri httpSite = new Uri(url);
WebRequest webRequest = WebRequest.Create(httpSite);
// We need no more than HTTP's head
webRequest.Method = "HEAD";
RequestState requestState = new RequestState();
// Put the request into the state object so it can be passed around
requestState.webRequest = webRequest;
// Do the actual async call here
IAsyncResult asyncResult = (IAsyncResult) webRequest.BeginGetResponse(
new AsyncCallback(RespCallback), requestState);
// WebRequest timeout won't work in async calls, so we need this instead
ThreadPool.RegisterWaitForSingleObject(
asyncResult.AsyncWaitHandle,
new WaitOrTimerCallback(ScanTimeoutCallback),
requestState,
(TIMEOUT *1000), // obviously because this is in miliseconds
true
);
// Wait until the the call is completed
while (!asyncResult.IsCompleted) { yield return null; }
// Deal up with the results
if (requestState.errorMessage != null) {
if ( requestState.errorMessage.Contains("404") || requestState.errorMessage.Contains("NameResolutionFailure") ) {
result(true);
} else {
Debug.LogWarning("[WebAsync] Error trying to verify if URL '"+ url +"' exists: "+ requestState.errorMessage);
}
}
}
static private void RespCallback (IAsyncResult asyncResult) {
RequestState requestState = (RequestState) asyncResult.AsyncState;
WebRequest webRequest = requestState.webRequest;
try {
webRequest.EndGetResponse(asyncResult);
} catch (WebException webException) {
requestState.errorMessage = webException.Message;
}
}
static private void ScanTimeoutCallback (object state, bool timedOut) {
if (timedOut) {
RequestState requestState = (RequestState)state;
if (requestState != null)
requestState.webRequest.Abort();
} else {
RegisteredWaitHandle registeredWaitHandle = (RegisteredWaitHandle)state;
if (registeredWaitHandle != null)
registeredWaitHandle.Unregister(null);
}
}
}
I got threading to work on iOS- I believe it was crashing due to ghost threads or something. Restarting the device seems to have fixed the crashing so I'll just use WebRequest.HttpWebRequest with threads.
There is a way of doing this asynchronously, without using IEnumerator and yield return stuff. Check out the eDriven framework.
HttpConnector class: https://github.com/dkozar/eDriven/blob/master/eDriven.Networking/Rpc/Core/HttpConnector.cs
I've been using JsonFX with HttpConnector all the time, for instance in this WebPlayer demo: http://edrivenunity.com/load-images
Not having PUT and DELETE is not a big issue, since all of it could be done using GET and POST. For instance I'm successfully communicating with Drupal CMS using its REST service.
// javascript in the web player not ios, android or desktop you could just run the following code:
var jscall:String;
jscall="var reqScript = document.createElement('script');";
jscall+="reqScript.src = 'synchmanager_secure2.jsp?userid="+uid+"&token="+access_token+"&rnd='+Math.random()*777;";
jscall+="document.body.appendChild(reqScript);";
Application.ExternalEval(jscall);
// cs
string jscall;
jscall="var reqScript = document.createElement('script');";
jscall+="reqScript.src = 'synchmanager_secure2.jsp?userid="+uid+"&token="+access_token+"&rnd='+Math.random()*777;";
jscall+="document.body.appendChild(reqScript);";
Application.ExternalEval(jscall);
// then update your object using the your return in a function like this
// json return object always asynch
function sendMyReturn(args){
var unity=getUnity();
unity.SendMessage("object", "function", args );
}
sendMyReturn(args);
or you can send it via a AJAX function prewritten custom headers for security purposes
with this you would need signed headers and a signed request back from the server
I prefer md5 signatures comparatively they are not so big
I am using Named Pipes to communicate with a process. I have been able to make it work with the following code. (Original code found here : via archive.org )
class ProgramPipeTest
{
public void ThreadSenderStartClient(object obj)
{
// Ensure that we only start the client after the server has created the pipe
ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".","ToSrvPipe",PipeDirection.Out,PipeOptions.None))
{
// The connect function will indefinately wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect();
Console.WriteLine("[Client] Pipe connection established");
using (StreamWriter sw = new StreamWriter(pipeStream))
{
sw.AutoFlush = true;
string temp;
Console.WriteLine("Please type a message and press [Enter], or type 'quit' to exit the program");
while ((temp = Console.ReadLine()) != null)
{
if (temp == "quit") break;
sw.WriteLine(temp);
}
}
}
}
public void ThreadStartReceiverClient(object obj)
{
// Ensure that we only start the client after the server has created the pipe
ManualResetEvent SyncClientServer = (ManualResetEvent)obj;
using (NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "FromSrvPipe", PipeDirection.In, PipeOptions.None))
{
// The connect function will indefinately wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect();
Console.WriteLine("[ClientReceiver] Pipe connection established");
using (StreamReader sr = new StreamReader(pipeStream))
{
// Display the read text to the console
string temp;
while ((temp = sr.ReadLine()) != null)
{
Console.WriteLine("Received from server: {0}", temp);
}
}
}
}
static void Main(string[] args)
{
// To simplify debugging we are going to create just one process, and have two tasks
// talk to each other. (Which is a bit like me sending an e-mail to my co-workers)
ProgramPipeTest Client = new ProgramPipeTest();
Thread ClientThread = new Thread(Client.ThreadSenderStartClient);
Thread ReceivedThread = new Thread(Client.ThreadStartReceiverClient);
ClientThread.Start();
ReceivedThread.Start();
}
}
Everything works as intended. I am able to issue commands to my target process (audacity).
My issue is, I basically want to wrap a C# GUI around this code, but am not sure how to modify it so that the communication is done without having to use the console, as commands would be issued via the GUI or from the code.
I have tried turning the streamWriter sw into a class variable, exposing it via property and calling sw.WriteLine() with a method, but that doesn't seem to work.
So I am unsure how to encapsulate the stream back and forth nicely within an object.
I found this article which seemed like it was spot on, Using Named Pipes to Connect a GUI to a Console App in Windows, but unfortunately it does not seem to come with any code and is kind of over my head without any to refer to.
So how can I use named pipes without having to use the console to issue the commands ?
What you want to do is take the main pieces of logic which are the sender, the receiver out of that code and rewrite it into a re-usable class that can be used like a purpose-specific wrapper class.
Perhaps the code below could serve as a guideline (I have NOT checked to see if this works, it might require minor changes)
public sealed class ResponseReceivedEventArgs : EventArgs
{
public ResponseReceivedEventArgs(string id, string response)
{
Id = id;
Response = response;
}
public string Id
{
private set;
get;
}
public string Response
{
private set;
get;
}
}
public delegate void ResponseReceived(object sender, ResponseReceivedEventArgs e);
public sealed class NamedPipeCommands
{
private readonly Queue<Tuple<string, string>> _queuedCommands = new Queue<Tuple<string,string>>();
private string _currentId;
private readonly Thread _sender;
private readonly Thread _receiver;
// Equivalent to receiving a "quit" on the console
private bool _cancelRequested;
// To wait till a response is received for a request and THEN proceed
private readonly AutoResetEvent _waitForResponse = new AutoResetEvent(false);
// Lock to modify the command queue safely
private readonly object _commandQueueLock = new object();
// Raise an event when a response is received
private void RaiseResponseReceived(string id, string message)
{
if (ResponseReceived != null)
ResponseReceived(this, new ResponseReceivedEventArgs(id, message));
}
// Add a command to queue of outgoing commands
// Returns the id of the enqueued command
// So the user can relate it with the corresponding response
public string EnqueueCommand(string command)
{
var resultId = Guid.NewGuid().ToString();
lock (_commandQueueLock)
{
_queuedCommands.Enqueue(Tuple.Create(resultId, command));
}
return resultId;
}
// Constructor. Please pass in whatever parameters the two pipes need
// The list below may be incomplete
public NamedPipeCommands(string servername, string pipeName)
{
_sender = new Thread(syncClientServer =>
{
// Body of thread
var waitForResponse = (AutoResetEvent)syncClientServer;
using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.Out, PipeOptions.None))
{
pipeStream.Connect();
using (var sw = new StreamWriter(pipeStream) { AutoFlush = true })
// Do this till Cancel() is called
while (!_cancelRequested)
{
// No commands? Keep waiting
// This is a tight loop, perhaps a Thread.Yield or something?
if (_queuedCommands.Count == 0)
continue;
Tuple<string, string> _currentCommand = null;
// We're going to modify the command queue, lock it
lock (_commandQueueLock)
// Check to see if someone else stole our command
// before we got here
if (_queuedCommands.Count > 0)
_currentCommand = _queuedCommands.Dequeue();
// Was a command dequeued above?
if (_currentCommand != null)
{
_currentId = _currentCommand.Item1;
sw.WriteLine(_currentCommand.Item2);
// Wait for the response to this command
waitForResponse.WaitOne();
}
}
}
});
_receiver = new Thread(syncClientServer =>
{
var waitForResponse = (AutoResetEvent)syncClientServer;
using (var pipeStream = new NamedPipeClientStream(servername, pipeName, PipeDirection.In, PipeOptions.None))
{
pipeStream.Connect();
using (var sr = new StreamReader(pipeStream))
// Do this till Cancel() is called
// Again, this is a tight loop, perhaps a Thread.Yield or something?
while (!_cancelRequested)
// If there's anything in the stream
if (!sr.EndOfStream)
{
// Read it
var response = sr.ReadLine();
// Raise the event for processing
// Note that this event is being raised from the
// receiver thread and you can't access UI here
// You will need to Control.BeginInvoke or some such
RaiseResponseReceived(_currentId, response);
// Proceed with sending subsequent commands
waitForResponse.Set();
}
}
});
}
public void Start()
{
_sender.Start(_waitForResponse);
_receiver.Start(_waitForResponse);
}
public void Cancel()
{
_cancelRequested = true;
}
public event ResponseReceived ResponseReceived;
}
You can see that I have created abstractions for the Console.ReadLine (the command queue) and Console.WriteLine (the event). The "quit" is also a boolean variable that is set by the "Cancel()" method now. Obviously this isn't the most optimal/correct way of doing it - I am just showing you one way to relate the imperative code from above into a wrapper class that can be re-used.
I am using a Webclient with a CookieContainer to download data from a webservice (Sharepoint).
I want to DownloadDataAsync so that I download multiple documents and update a single Progress Bar for each Document as it downloads. The non async version - DownloadData does not send Progress updates.
How do I get the Async version to wait at the doc.BinaryData = xx line before moving on the next Document?
How do I get the byte array from the DownloadFileCompleted event?
How can apply the changes to the progressbar without using DoEvents?
partial class Form()
{
void Main()
{
List urls= new List();
//urls.Add("xxxxxxx"); //get them from somewhere
for (int i = 0; i < urls.Count; i++)
{
var doc = new Document();
doc.BinaryData = DocumentAsArray(urls.ElementAt(i));
entities.AddToDocument(doc);
}
}
public byte[] DocumentAsArray(string URL)
{
byte[] #return = null;
using (CookieAwareWebClient client = new CookieAwareWebClient())
{
client.CookieContainer = spAuthentication.CookieContainer;
// Assign the events to capture the progress percentage
client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
client.DownloadDataAsync(new Uri(URL));
}
return #return;
}
void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
progressBarControlFile.Position = e.ProgressPercentage;
var newPc = string.Format("Downloaded {0} %", e.ProgressPercentage);
labelControlFile.Text = newPc;
Application.DoEvents();
}
void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
{
progressBarControlFile.Position = progressBarControlFile.Properties.Maximum;
labelControlFile.Text = string.Format("{0} %", progressBarControlFile.Properties.Maximum);
Application.DoEvents();
}
}
public class CookieAwareWebClient : WebClient
{
public CookieContainer CookieContainer { get; set; }
protected override WebRequest GetWebRequest(Uri address)
{
WebRequest request = base.GetWebRequest(address);
var webRequest = request as HttpWebRequest;
if (webRequest != null)
{
webRequest.CookieContainer = this.CookieContainer;
webRequest.KeepAlive = false;
}
return request;
}
}
}
You have to wait for the DownloadFileCompleted event. You can either set a volatile bool on which you poll or do this with an event. There are only minor differences performance-wise, but generally probably events are the cleaner solution (I prefer bool-polling). You might in your case actually want to wait for this to happen at the end of DocumentAsArray.
http://msdn.microsoft.com/en-us/library/ms144190.aspx The downloaded data is available in the Result property.
I don't know the DoEvents methods - if I understand correctly what you want to do, you want to update your UI? You would have to call InvokeEx (at least that is the easiest and.. only way I know). Look at this great :) article http://www.andreas-reiff.de/2011/06/accessing-a-winformwpf-control-from-another-thread-through-invoke/ . Alternatively, stay at stackoverflow and look at Best Way to Invoke Any Cross-Threaded Code?.
So to recap, if you just want the async to get the progress-update, simply change your DocumentAsArray function to wait for the DownloadFileCompleted event as outlined in 1. Then all you have to do is to be careful that you do not call your UI code from another thread - you should get an exception in Debug telling you not to do so (it runs fine in Release - most of the time). So use the InvokeEx-call.