What is the correct way to setup a named pipe in C# across a network?
Currently I have two machines, 'client' and 'server'.
Server sets up its pipe in the following manner:
NamedPipeServerStream pipeServer = new NamedPipeServerStream(
"pipe",
PipeDirection.InOut,
10,
PipeTransmissionMode.Byte,
PipeOptions.None)
pipeServer.WaitForConnection();
//... Read some data from the pipe
The client sets up its connection in the following manner:
NamedPipeClientStream pipeClient = new NamedPipeClientStream(
"server",
"pipe",
PipeDirection.InOut);
pipeClient.Connect(); //This line throws an exception
//... Write some data to the pipe
The 'server' machine can be accessed on the network by going to "\\server".
Whenever I run the program, I get a System.UnauthorizedAccessException that says "Access to the path is denied." The code works fine when I run the server and client on my local machine and attempt to connect to "." with the client.
You need to set permissions on the NamedPipeServerStream so that the client will have permissions to access the pipe.
I would look at the SetAccessControl method of your NamedPipeServerStream.
Look in the System.Runtime.Remoting namespace. IIRC, named pipes are one option for the protocol used by remoting channels.
It is not possible to used named pipes between machines.
"The WCF-NetNamedPipe adapter provides cross-process communication on the same computer"
http://msdn.microsoft.com/en-us/library/bb226493.aspx
Related
In my C# application, I have this code:
var factory = new ConnectionFactory
{
Port = 5671,
UserName = "userxxxx",
Password = "passwordxxx",
HostName = "amqps://xxxx.mq.us-east-1.amazonaws.com"
};
using var connection = factory.CreateConnection();
But during the CreateConnection I receive:
RabbitMQ.Client.Exceptions.BrokerUnreachableException
HResult=0x80131620
Message=None of the specified endpoints were reachable
Source=RabbitMQ.Client
The AWS Console shows me:
Endpoint: amqps://xxxx.mq.us-east-1.amazonaws.com:5671
What am I doing wrong?
Use a tool like "netcat" to verify you can connect to port 5671 on the AWS MQ. Netcat should be used from the same host you are trying to connect from. Alternatively, consider using a cloud-based portscanner like https://www.whatismyip.com/port-scanner/ to take your local network out of the equation.
Successful example with netcat:
$ nc -vz myownawsmq.mq.us-east-1.amazonaws.com 5671
Connection to myownawsmq.mq.us-east-1.amazonaws.com 5671 port [tcp/amqps] succeeded!
If you get an error or timeout, then your URL is incorrect or port 5671 is blocked.
When I created my AWS RabbitMQ instance, port 5671 was open to the internet because publicly accessible is the default. You cannot use a security group with RabbitMQ instance that is publicly accessible. If you set Private Access for the RabbitMQ instance, you won't be able to reach it externally.
It's also possible 5671 is blocked by local firewall rules. Check the firewall configuration in your local network to make sure 5671 is allowed. If a cloud-based port scanner can connect to the port, but a local scan can't, it's probably your local network configuration.
Using the example Chat Server/Client project available as part of the Akka.NET source code I have attempted to modify it such that it would successfully work over two computers on my network.
I have two systems that are connected via a router like this
192.168.0.29 (Server) <---------------| Router |---------------> 192.168.0.52 (Client)
I then have two actor systems that are configured like this:
Server:
akka {
actor {
provider = remote #Specify remote provider
}
remote {
dot-netty.tcp {
port = 666 #Akka server port number
hostname = 0.0.0.0 #Bind to all local network interfaces
public-hostname = 192.168.0.29 #Expose public IP to enable correct routing of public messages.
}
}
}
Client:
akka {
actor {
provider = remote
}
remote {
dot-netty.tcp {
port = 0 #Tell Akka that this is a client connection/use random port.
hostname = 192.168.0.29 #Tell Akka.NET which remote instance to connect to
}
}
}
Unfortunately, while I am able to successfully connect to the chat server locally, no matter how I configure my Hocon I cannot seem to get the remote instance to bind to my server actor located on the machine 192.168.0.29.
The specific error message that I receive
[ERROR][27/11/2019 4:58:36 PM][Thread 0004][Akka.Remote.Transport.DotNetty.TcpTransport] Failed to bind to 192.168.0.29:0; shutting down DotNetty transport.
Cause: System.Net.Sockets.SocketException (10049): The requested address is not valid in its context
at System.Net.Sockets.Socket.UpdateStatusAfterSocketErrorAndThrowException(SocketError error, String callerName)
This error message suggests to me that there is no available socket that Akka.NET can access.
Ironically enough, some time ago I asked a very similar question which at the time helped me resolve my connectivity issues but I never used Akka.NET till recently again.
I note that both machines have their firewalls turned off and can successfully ping each other, I have also played around with all various combinations of settings.
The original source code to the Akka.NET server/client application is located here, my current version of it is here.
Could anyone provide any insight into what I might be doing wrong and how I can improve my debugging of Akka.NET remote connections? For example is there a way that I can verify that the Actor system on server 192.168.0.29 is accessible from 192.168.0.52 externally?
Haha, and literally 5 minutes after posting my question I was finally able to determine the solution (although its not ideal).
The solution was the realisation that when you instantiate the ActorSystem on the client application you are NOT actually connecting the local actor system to the remote system BUT rather creating a local instance of an actor system which itself is listening on a random port.
The remote connection itself occurs when you create an ActorSelection() reference.
So all I needed to do was change my client hocon from
hostname = 192.168.0.29
TO
hostname = 192.168.0.52
However this creates one final (albeit rather small) problem. I now need a different hocon file for an instance running locally vs an instance running remotely. Admittedly this could probably be addressed through code....
I'd be happy to mark as the solution someone who might be able to propose something that addresses this issue.
I am using named pipes to communicate between multiple different apps. I have two named pipe hosts which I am trying to get to listen on different addresses.
If I start either app on its own it will run. When i run the second app it will throw and exception telling me that the address is already in use.
System.ServiceModel.AddressAlreadyInUseException: 'Cannot listen on pipe name
'net.pipe://dfb679124c82453888842928c37c6dae/' because another pipe endpoint is
already listening on that name.'
The two services are not using the same address.
I have even setup one of the services with the following code:
Host = new ServiceHost(
this,
new Uri[]
{
new Uri("net.pipe://"+Guid.NewGuid().ToString("N"))
});
var binding = new NetNamedPipeBinding();
Host.AddServiceEndpoint(typeof(IService),
binding, Guid.NewGuid().ToString());
In this code I am generating a random address when the service is created and it still throws the AddressAlreadyInUseException.
I am not using any config configuration to setup the named pipes, everything is code based.
What am I doing wrong?
I have few questions (and problems) about the tcp client class.
1. What IP should I give to it constructor, mine or the remote host that I want to connect to? because in MSDN I see that the constructor takes a local ip endpoint and I can't understand it.
2. What may be the reason for such statement:
TcpClient client = new TcpClient(ip.Text, port: portNum);
to stop the code from running without throwing an exception?
1. The IP you should give to the constructor
You should give the IP you want to connect, look about the IPAddress class.
2. The reason of the statement
Why did you type port: portNum ?
Just write like what is writed in the official documentation :
//Creates a TCPClient using host name and port.
TcpClient tcpClientB = new TcpClient ("www.contoso.com", 11000);
System.Net.Sockets.TcpClient has four constructors. The two constructors that seem to be the source of confusion are:
TcpClient(IPEndPoint) - binds it to the specified local endpoint.
TcpClient(String, Int32) - connects to the specified port on the specified host.
Constructor #1 is useful if your computer has more than one NIC (e.g. Ethernet and WiFi) and you want to pick which one to use. If you construct your TcpClient instance this way, then you would explicitly call TcpClient.Connect to connect the remote host and port number.
Constructor #2 creates the TcpClient instance (picking a local endpoint automatically) and immediately connects using the supplied remote host and port.
I'm encountering a strange problems with Named pipes on Windows in C#.
Client:
NamedPipeClientStream pipeStream = new NamedPipeClientStream("default-PC","mypipe");
pipeStream.Connect();
BinaryWriter sw = new BinaryWriter(pipeStream);
sw.Write((byte[]) data);
Server:
NamedPipeServerStream pipeStream = new NamedPipeServerStream("mypipe");
byte[] dataAll = null;
pipeStream.WaitForConnection();
dataAll = new BinaryReader(pipeStream).ReadBytes(1024 * 1000 * 512);
--
If I use "." as a server name in the constructor for the NamedPipeClientStream everything works correctly, i.e. the server fills the dataAll object.
Now the strange thing is that if I on the other hand put the network name of the computer("default-PC") in the NamedPipeClientStream like shown in the code above then no data is read on the server as ReadBytes in the server code returns an empty array.
This could understandable I was running the server and client on two different computers but they are both running on the same machine. The only difference being whether the "server name" parameter in NamedPipeClientStream is "." or the actual network name (or even localhost).
Any ideas?
I believe that both "." and "localhost" are considered special names and don't use the normal network connections, but a loopback of some sort.
When you specify a computer name, even your own computer's name, it uses the standard network protocols/stack/etc.
You probably need to open a firewall port. TCP 445. Also, by default, Windows allows all outgoing communications. You should only need to add an inbound port exception. Your configuration may vary of course.
.NET 3.5 (C#) Named pipes over network
So the conclusion is this:
If the Server name parameter in NamedPipeClientStream is something else than "." then the underlying implementation is through a transport layer that supports a maximum of 64k in a single Write operation. The problem is that if you Write more than 64k then the data just disappears instead of throwing an exception.
The solution is to use the NamedPipeClientStream directly and Write the data in less than 64kb chunks.