I recently asked a question on IPC between C# and PHP and followed an answer up suggesting named pipes. For this, I searched the Internet for an appropriate example of named pipes using solely C# as client and server simultaneously and modified it so it'd run asynchronously:
static void Main(string[] args)
{
Start();
new AutoResetEvent(false).WaitOne();
}
private static async void Start()
{
StartServer();
Thread.Sleep(1500);
StartClient();
}
private static async void StartClient()
{
var client = new NamedPipeClientStream("TestPipe");
await client.ConnectAsync();
var reader = new StreamReader(client);
var writer = new StreamWriter(client);
while (true)
{
var input = Console.ReadLine();
if (string.IsNullOrEmpty(input)) break;
await writer.WriteLineAsync(input);
await writer.FlushAsync();
Console.WriteLine(await reader.ReadLineAsync());
}
}
private static async void StartServer()
{
await Task.Run(async() =>
{
var server = new NamedPipeServerStream("TestPipe");
await server.WaitForConnectionAsync();
var reader = new StreamReader(server);
var writer = new StreamWriter(server);
while(true) // should be !reader.EndOfStream(), doesn't work tho
{
var line = await reader.ReadLineAsync();
await writer.WriteLineAsync("RECEIVED > " + line);
await writer.FlushAsync();
}
});
}
So if I now type Hello into the console, it is going to return RECEIVED > Hello, which is fine and looks like it's brilliantly working. I entirely understand this in C#. However, this changes when PHP comes into play: I found less good examples (or even tutorials) for named pipes in PHP and the usage. Now what I found here brought me one step further, but only one.
In PHP, I seem to lack the understanding of the whole complex. My target is to 'feed' my C# server with tasks in the form of commands (e.g. create document id=12). The server (which is also running largely asynchronous) then shall give something back stating whether it has worked out or not (also using the id). So for example, my server's reply could be:
document id=12 created successfully
or
document id=12 error
Of course, I'll need my both applications to parse this and process these replies further, however, this is not the nub of the matter at this point. I need my PHP application to schedule tasks to C# and get the 'ping-back' ('error or not', you could say). I don't even need multiple ping backs, so for example a status update of the C# application frequently sending this, I only need one final statement whether it has worked or not.
Taking a look at the example I found on php.net, this does not tell me too much about it:
<?php
$pipe="/tmp/pipe";
$mode=0600;
if(!file_exists($pipe)) {
// create the pipe
umask(0);
posix_mkfifo($pipe,$mode);
}
$f = fopen($pipe,"w");
fwrite($f,"hello"); //block until there is a reader
unlink($pipe); //delete pipe
?>
And this is the non-blocking reader:
<?php
$pipe="/tmp/pipe";
if(!file_exists($pipe)) {
echo "I am not blocked!";
}
else {
//block and read from the pipe
$f = fopen($pipe,"r");
echo fread($f,10);
}
?>
The first, blocking variant, does not qualify for Windows since posix is not available on Windows and my C# application requires this. The example shows a blocked pipe (what exactly is this even? I could think of an existent pipe considered blocked, since if(!file_exists($pipe)) suggests this). However, this would mean that I could only handle one task at the same time with my C# server, which is not the requirement.
This is the procedure it is supposed to be:
User presses 'download'
PHP Action is fired (inside my Laravel Controller)
PHP schedules a task to the C# server via pipe
C# server receives it and processes it
C# server finishes it and tells PHP that it is finished (or error thrown, respectively) via pipe
The PHP (Laravel Controller) already awaits this answer and renders it to the user
Where I'm stuck is the point where pipes can be blocked, since this (according to the reference on the PHP docs page comments section) would mean if a certain pipe is blocked and I want multiple tasks to be ran at the same time, I need to create a new one, which my C# server must be aware of, too, which in conclusion means I can only set a very limited number of pipes, so to speak 'possible' slots for 'work' or 'tasks' of the server which a user of the web application can join into [the slot] and afterwards the slot's cleared. Howsoever, this'd destroy the concept of my C# asynchronous server and the principal idea behind it, and I can't think of this as the only solution.
I'm looking forward to seeing some suggestions. Cheers!
Related
Could someone explain why i am getting Timeouts are not supported on this stream. error.
If i use my code like this everythings fine. My sockets connects to server adn retreives info. (This method was like dummy cause the connection was happening for one server and at the start of everything)
private async Task Update()
{
while (true)
{
server = Ips.First();
if (server.Map != sq.map || server.Name != sq.name || server.Players != sq.players)
{
return;
}
}
}
While in real app i need to query a lot of servers. So i try something like this ( cause i'm noob and cant figure out a better way )
foreach (var server in Ips)
{
sq.Connect(new Windows.Networking.HostName(server.Ip), server.Port);
if (server.Map != sq.map || server.Name != sq.name || server.Players != sq.players)
{
return;
}
}
And that's where i get Timeouts are not supported on this stream error. Can someone explain why and maybe tell me where should i look in too?
My error comes in first line of this method:
(Stream streamIn = args.GetDataStream().AsStreamForRead();)
private async void Socket_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
Stream streamIn = args.GetDataStream().AsStreamForRead();
StreamReader reader = new StreamReader(streamIn);
string message = await reader.ReadToEndAsync();
byte[] packet = System.Text.Encoding.ASCII.GetBytes(message);
Parser parser = new Parser(packet);
But why does the first method work?
The main difference between your first code block and the second one is sq.Connect(new Windows.Networking.HostName(server.Ip), server.Port);, base on your code, it is possible that
you only connect to Ips.First(), and the code run to "return" to jump out of the "foreach".
you establish two(or more) connections until the code run to "return".
I don't know what is your sq, and there is no Connect(hostname, serverport) method in DatagramSocket class, there is only a similar method but an aysnc one: DatagramSocket.ConnectAsync(HostName, String) | connectAsync(HostName, String) method.
Mapping to the two possibilities I listed up:
if the code in "foreach" only run one time (means Ips.First() connected), then the difference between two code block is you established a connection in the second code, this could be a reason.
for the second possibility, I assume that you are using ConnectAsync method actually, then sq is c sq = new DatagramSocket();, and it is connected to several servers using one DatagramSocket. But ConnectAsync method is for communicate with a single remote endpoint, so I think it could also be the reason here.
While in real app i need to query a lot of servers.
I think for your scenario, it's better not using connections, you can bind your DatagramSocket to a local port, and join a DatagramSocket object to a multicast group. You can refer to the official DatagramSocket sample, the scenario 5 is for multicast and broadcast, you can take a look.
If you have any problems here, please leave a comment.
I am trying to get some basic multi-threading working in C#. There's no clear tutorial that I've found so bear with my sub-par code:
class Program
{
private static TcpListener listener;
private static List<TcpClient> clients;
static void Main(string[] args)
{
listener = new TcpListener(IPAddress.Any, 1337);
clients = new List<TcpClient>();
StartListening();
Console.WriteLine("Accepting clients..");
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
static async void StartListening()
{
listener.Start();
while (true)
{
clients.Add(await listener.AcceptTcpClientAsync().ConfigureAwait(false));
Console.WriteLine("Client connected!");
HandleClient(clients[clients.Count - 1], clients.Count);
}
}
static async void HandleClient(TcpClient c, int number)
{
Console.WriteLine($"Getting client #{number}'s handshake..");
var ns = c.GetStream();
var sr = new StreamReader(ns);
var handshake = sr.ReadLine();
Console.WriteLine("Client {0}'s handshake: {1}", number, handshake);
}
}
Right, so what I'm trying to achieve in the server program is:
1. Accepting client
2. Receiving handshake, print it to console
3. Add to the clients list
The accepting client part works, however the program just stops just after the first line of HandleClient(). I've tried waiting for absurd amounts of time (1000ms) and even then it just doesn't receive anything, nor does it throw an exception (i.e. it stays connected). What am I doing wrong here?
Client code is here if you need it!
Your client code is broken here - you're never flushing it:
var sw = new StreamWriter(ns);
Thread.Sleep(1000);
sw.WriteLine(handshake);
There's no need for the Thread.Sleep call, but you should flush the StreamWriter if you want the data to actually be sent to the network layer immediately:
sw.Flush();
While (as Stephen Cleary notes) this wouldn't mean it necessarily got sent immediately, it's reasonable to expect it to be sent "reasonably soon" after flushing.
I am trying to get some basic multi-threading working in C#.
I'm always amazed at devs who try to learn concurrency by writing a bare-metal TCP/IP server (when they've never programmed TCP/IP previously). Concurrency and TCP/IP are two extremely difficult topics; trying to learn them at the same time is almost certainly going to end in disaster. It's just really odd that this is such a common approach.
If you want to learn asynchrony, I recommend my async intro and article on best practices (where, among other things, you'll learn the principle "avoid async void").
If you want to learn TCP/IP, I recommend my TCP/IP .NET FAQ blog series. However, writing TCP/IP code is almost never necessary, and since you can change both the client and server, I strongly recommend using SignalR instead.
I suspect that you actually want to learn async, and the TCP/IP is just getting in the way. So, drop the harder topic (TCP/IP) and use async with simpler communications such as WebAPI or SignalR.
(As far as the actual problem you saw, it is indeed caused by buffering, but it's important to note that flushing the buffer does not cause the data to be send over the network immediately; it is only sent to the networking layer immediately. A proper solution would need message framing.)
As Jon Skeet mentioned, to make sure the content is not just sitting in a buffer, you should Flush it.
Your client should look like so:
var sw = new StreamWriter(ns);
Thread.Sleep(1000); // let the server catch up
sw.WriteLine(handshake);
sw.Flush();
Console.WriteLine("Staying connected.. Press ESCAPE to exit.");
EDIT: Forgot to mention... That Thread.Sleep(1000); there... you can safely remove it.
I am working with this code in order to comunicate with another program through TCP which acts as a server. My app is also a Windows Store App and I just added the 3 methods to my code. The server is not made by me, I can't modify it in any way. Connection and sending messages works fine. After I give a specific command to the server, it sends back a continuous stream composed of strings that end in "\r\n" in order to see when a message ends, something like this: "string1\r\nstring2\r\n" and so on, as long as there is a connection with it. Note that sending the command works because I get a visual response from the server.
I can not find a way to display the individual strings in my app's UI, I think my problem lies in the read() method, because the stream never "consumes":
public async Task<String> read()
{
DataReader reader;
StringBuilder strBuilder;
using (reader = new DataReader(socket.InputStream))
{
strBuilder = new StringBuilder();
// Set the DataReader to only wait for available data (so that we don't have to know the data size)
reader.InputStreamOptions = Windows.Storage.Streams.InputStreamOptions.Partial;
// The encoding and byte order need to match the settings of the writer we previously used.
reader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
reader.ByteOrder = Windows.Storage.Streams.ByteOrder.LittleEndian;
// Send the contents of the writer to the backing stream.
// Get the size of the buffer that has not been read.
await reader.LoadAsync(256);
// Keep reading until we consume the complete stream.
while (reader.UnconsumedBufferLength > 0)
{
strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength));
await reader.LoadAsync(256);
}
reader.DetachStream();
return strBuilder.ToString();
}
}
I have an event on a button that calls send() having a parameter the string command I wish to send. At first, I simply tried textBox.Text = await read(); after calling the send() method, nothing appeared in the textBox. Next, I tried making the read() method to not return anything and putting textBox.Text = strBuilder.ToString(); in different places inside read(). Finally, I discovered if I put it inside while (reader.UnconsumedBufferLength > 0) after strBuilder.Append(reader.ReadString(reader.UnconsumedBufferLength)); the textBox gets updated, although I'm not sure if the strings really appear correctly, but my UI becomes unresponsive, probably because it gets stuck in the while loop. I searched the internet for multiple examples, including how to do it in a separate thread, unfortunately my experience is entry-level and this is the best I could do, I don't know how to adapt the code any further. I hope I have been explicit enough. Also, I don't mind if you show me a different, better way of updating the UI
I have a C# application which in turn loads a C or C++ dll (which in turn loads other C/C++ dlls). Within the C# application I use a log4net logger to capture all the output into a series of log files. My application runs as a windows service so there is no console/output window for normal printfs or output written into stdout/stderr to go to.
Is there a way to setup the C# application to direct stdout/stderr (from the DLLs) and turn each line into a log4net output. Or is there some way within the C/C++ DLL to connect the stdout/stderr streams to the log4net output?
I found some solution (here : http://bytes.com/topic/c-sharp/answers/822341-dllimport-stdout-gets-eaten) that indicated I needed to put a call into my C DLL like this : setvbuf(stdout, NULL, _IONBF, 0); Though, I don't know what that does, it doesn't do what I want. I assume I'd also need a similar line for stderr. In either case, google seemed to think those lines simply take care of buffering and not redirection into log4net.
I assume I need some sort of function override which snags the console writes (from a loaded DLL in another language) and converts them into mLog.InfoFormat("{0}", consoleString); sorts of calls. I'm new to c# and not even sure what terms to google in order to find such an override (if its even possible).
Not sure if this complicates the problem, but my C# application is multithreaded and some of the DLLs have multiple threads as well. I assume that just means I need a lock of some sort inside the method that handles the console output and writes it into the log4net framework(maybe) or maybe the normal serialization of log4net will handle it for me.
Turns out those did the trick once I figured out how to use them. I setup two named pipes(or two ends of the same pipe?). One I connected to stdout and had it do a log message in log4net of whatever came through the pipe.
internal static void InfoLogWriter(Object threadContext)
{
mLog.Info("InfoLogWriterthread started");
int id = Process.GetCurrentProcess().Id; // make this instance unique
var serverPipe = new NamedPipeServerStream("consoleRedirect" + id, PipeDirection.In, 1);
NamedPipeClientStream clientPipe = new NamedPipeClientStream(".", "consoleRedirect" + id, PipeDirection.Out, PipeOptions.WriteThrough);
mLog.Info("Connecting Client Pipe.");
clientPipe.Connect();
mLog.Info("Connected Client Pipe, redirecting stdout");
HandleRef hr11 = new HandleRef(clientPipe, clientPipe.SafePipeHandle.DangerousGetHandle());
SetStdHandle(-11, hr11.Handle); // redirect stdout to my pipe
mLog.Info("Redirection of stdout complete.");
mLog.Info("Waiting for console connection");
serverPipe.WaitForConnection(); //blocking
mLog.Info("Console connection made.");
using (var stm = new StreamReader(serverPipe))
{
while (serverPipe.IsConnected)
{
try
{
string txt = stm.ReadLine();
if (!string.IsNullOrEmpty(txt))
mLog.InfoFormat("DLL MESSAGE : {0}", txt);
}
catch (IOException)
{
break; // normal disconnect
}
}
}
mLog.Info("Console connection broken. Thread Stopping.");
}
Also have a function to push all that to another thread so it doesn't block my main thread when it hits the various blocking calls.
internal static void RedirectConsole()
{
mLog.Info("RedirectConsole called.");
ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(InfoLogWriter));
// TODO enqueue and item for error messages too.
}
I'm having trouble with it disconnecting and have to reconnect the pipes, but I'll figure out a reconnect solution. I'm guessing that happens when DLLs get swapped back out of memory or perhaps when I need to read but there isn't anything currently ready to be read? I've also got to setup another pair to snag stderr and redirect it as well, using Error logs for that one. Probably want to get rid of the magic number (-11) and use the normal enums as well (STD_ERROR_HANDLE, etc)
I'm trying to create a chat with file transfer application using TCPSocket and here is my code..
SENDER:
public void sendData(string message)
{
StreamWriter streamWriter = new StreamWriter(netStream); // netStream is
// connected
streamWriter.WriteLine(message);
streamWriter.WriteLine(message);
logs.Add(string.Format("Message Sent! :{0}", message));
//netStream.Flush();
streamWriter.Flush();
}
RECEIVER:
private void ReceiveData()
{
StreamReader streamReader = new StreamReader(ChatNetStream);
StringBuilder dataAppends = new StringBuilder();
bool doneTransfer = false;
string data;
while (!doneTransfer)
{
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
doneTransfer = true;
//ChatNetStream.Close();
//streamReader
}
//do whatever i want with dataAppends.ToString() here..
ReceiveData()
}
the problem is i always turn into infinite loop inside this statement
while ((data = streamReader.ReadLine()) != null)
{
dataAppends.Append(data);
}
even if i put streamWriter.Flush() on my sender..
do i need to close/dispose the netStream/NetworkStream?
anyway, can i use only 1 socket or connection to send a File and send a chat at the same time..? or do i need to use a new socket connection everytime i send a file..
You get an infinite loop because StreamReader.ReadLine will only return null when the end of the stream is reached. For a network stream, "end of stream" means "the other side has closed its half of the connection". Since the other side is your client, and it keeps the connection open while waiting for the user to type in more data, you will end up with an infinite loop.
What you want to do instead is fire off an operation that only completes if there is more data to read. There are two ways to go about this: either use a blocking read operation (on a dedicated thread, so that you don't block your application's other processing while waiting for messages), or use an async (event- or callback-based) approach.
For the synchronous (blocking) approach, see the documentation on NetworkStream.Read which includes example code that shows how to check if there is incoming data and how you can read it. The one point you absolutely need to know here is that when Read returns zero, it means that all data has been read and the connection has been closed from the other side (so you should close your end as well and not loop; the client has disconnected).
For low-level async network reads, the relevant operation is NetworkStream.BeginRead, which comes with its own example.
Both approaches are lower-level than what you currently have and will require you to manually assemble data inside a buffer and decide when "enough data" (i.e. a full line) has accumulated for you to process. You will then have to carefully pull that data out of the buffer and continue.
For a higher-level approach that still allows you some degree of orchestrating things, look into using client sockets (and in particular the two sync and async options there). This functionality is introduced by the TcpClient (and server-side the corresponding TcpListener) classes.
Finally, as jValdron's comment says, you will either need a separate connection for transferring file data or engineer some custom protocol that allows you to interleave multiple kinds of data over the same network stream. The second solution is has generally more technical merit, but it will also be harder for you to implement correctly.
Checkout the BasicSend example in networkComms.net which demonstrates a simple chat application using an open source library.