Windows Named pipes not working over network? - c#

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.

Related

Get the client IP used to connect to some target IP?

First of all I have to mention that I don't have any dedicated server in this case. But I know about the server's IP. So the problem is if the client connects to that IP, how could I know which client IP it uses? Because a client can have more than 1 network adapter, each one is connected to a different network. Also the server does not need to be in the same LAN with the client, it may require several hops before the client's packets reaching the server. We know the server's IP, how could we know the client's IP in this case?
Because we don't have dedicated server so we cannot detect the client's IP via some server app (some kind of clients manager). Also the Ping class seems not helpful in this case, also in general the server does not have to have pinging enabled. Currently the server is just a SQL Server to which the client executes some query directly. I know we can obtain the client's IP when it executes a query to my SQL Server (using sys.dm_exec_connections) but it's just the last resort for me. I would like to find another way directly from the client (and without involving the SQL Server).
Here is the closest approach I can follow but I don't really know why it chooses the last address?
var hn = System.Net.Dns.GetHostName();
var ipEntry = System.Net.Dns.GetHostEntry(hn);
IPAddress[] addr = ipEntry.AddressList;
var ip = addr[addr.Length - 1].ToString();//why the last?
Any way there are many IP addresses (not in the same LAN directly) which are not contained in the AddressList.
My problem is some kind of finding all possible network paths between the client (starting at some available network adapter on the client) and the server (with IP known beforehand). In almost cases there should be just 1 path available (so we should just find 1 client's IP). Trying sending some request from the client may be required to find the path but I currently don't have any clue on how it can be done.
You can easily do this from the client side using any available listening port on the server side (HTTP port, SSH port, or SQL Server port). Here's a small python program:
import sys
import socket
if len(sys.argv) != 3:
print("Usage: {} ip-or-hostname port-number".format(sys.argv[0]))
sys.exit(1)
hostname = sys.argv[1]
port = int(sys.argv[2])
s = socket.socket()
s.connect((hostname, port))
print(s.getsockname()[0])
What it does is to create a connection to the destination system, then uses the getsockname system call to provide the local address used in the connection. This local address will always correspond to one of your client side interfaces.
So for example, if I run it with arguments www.google.com 80, I get:
python /tmp/disc.py www.google.com 80
192.168.0.110
If I instead give it an address and port of a machine on a different local subnet, I get:
python /tmp/disc.py 192.168.40.128 22
192.168.40.131
The two addresses returned correspond to two different interfaces on my local system:
ip -4 addr
[snipped]
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.0.110/24 brd 192.168.0.255 scope global dynamic ens33
valid_lft 166968sec preferred_lft 166968sec
3: ens34: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
inet 192.168.40.131/24 brd 192.168.40.255 scope global ens34
valid_lft forever preferred_lft forever
I'm sure you could easily implement the same program in C# -- just not a language I'm intimately familiar with.
Looks like I missed one important already built-in class to act as a client (we have HttpClient, WebClient ... but in this case I need a TcpClient). This can try connecting to some IP (with some port provided) and if it succeeds I can obtain the resolved LocalEndPoint of the underlying webSocket. It can just be converted to string but I can parse for the client IP it used (the string format is like IP:port). Here is just a few lines of code to achieve what I want:
public string GetIPConnectingTo(string targetIP, int port = 80){
try {
using(var tc = new TcpClient(targetIP, port)){
return tc.Client.LocalEndPoint.ToString().Split(':')[0];
}
}
catch {
return null;
}
}

Listen for certain IP address and port with tcplistener

I'm creating a screen sharing application. To allow for nat traversal I'm having to do this through a server, I'm just wondering how I can check that the client trying to connect to the server is the one I want to connect and not someone else, whilst not actually blocking other people from being able to connect to that port.
I'm thinking of using BeginAcceptTcpClient() instead of AcceptTcpClient() is there a way to check who is trying to connect before it accepts the connection this way so it can be picked up by the TcpListener later?
The only other thing I can of is to send the ID of the person I want to send the image to in the connection and let the server handle who to send it to but would that be too slow or resource intensive?
Maybe you should take a look on how join.me makes it:
On first machine start the Observable.
This connects to the central server and receives a unique id (ticket) that will be shown to the user.
On the second machine start the Observer.
This connects also to the central server and awaits an entering of the desired id to connect to.
Now the user on the observable machine has to communicate the id to the observer guy through a different channel (e.g. phone).
On the observer the ticket number is entered and the server can send both machines the ip address and port of each other where their did the hole punching. If a direct connect is possible, the central server has finished its work, otherwise both sides will send their data to the server and from their to the other client.
So to ensure that the correct clients are connected simply create a unique id which both sides have to share through a different communication channel.
I think the following should be enough to see if the correct client has connected to your server:
Create a TCPListener and start accepting connections either synchronously or async. I'm using the synchronous example from MSDN: http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient(v=vs.110).aspx
When a client connects, create a stream to read data sent by the client like this:
NetworkStream stream = client.GetStream();
i = stream.Read(bytes, 0, bytes.Length);
Deserialize the message from bytes to string and check if it, for example, matches a unique ID that you are expecting:
`
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
//There are, of course, better ways of doing this.
if(data.Equals("HandshakeId")
{
//start receiving/sending data in a loop
}
else
{
// Shutdown and end connection
client.Close();
}
`
A more interesting question is how to capture the actual screen you'll be sharing. I personally have done this in VS C++, and the performance was okay. There are several ways to do it, i.e. using GDI+, using DirectX or OpenGL, the list goes on..
I'm curious as to what are you planing to use :)

is it wise to use 3 ports for a server application?

I have a server-client application [TCP sockets, .NET 4.0]..
the application about :do the commands that received from the clientreceives filessend a screenshot image
the application should do the 3 tasks in the same time
After i done that and it worked .. i realized that these kind of application should use one port for all tasks .. like Radmin and netsupport .. etc
but i used 3 ports .. one to keep receiving commands any time the client sends. and one for receiving files .. and one if the client asked for a screenshot
so is it fine to use 3 ports for a network application? ..
I've tried to create 3 sockets on the client side to connect to server on the same port (ex:9090)
but when i tried to send a file from the client .. the server received the bytes in Job function that's should receives the commands only... so it looks like i can't use one port for those tasks so is it possible use one port for all of the three tasks that they may work at the same time?
private void ClientAccept()
{
while (true)
{
Socket client = server.Accept();
Console.WriteLine(client.RemoteEndPoint + " has connected");
NetworkStream stream = new NetworkStream(client);
StreamReader reader = new StreamReader(stream);
string line = reader.ReadLine();
if (line == "1") //it means its a command socket
{
thJob = new Thread(Job);
thJob.Start(cmdClient);
}
else if(line=="2") //its a data socket
{
FileTransfer ft = new FileTransfer(client);
}
}
}
private void Job(object o)
{
Socket s = (Socket)o;
StreamReader sr = new StreamReader(new NetworkStream(s));
string cmd = null;
while ((cmd = sr.ReadLine()) != null)
{
//bla bla
}
}
Added question:
lets say the server has one port.
the client connect to server for commands .. let's call it cmdClient which its port is 11589then a Job Thread started for this client like the code up.
then the client connect with another socket to the server .. dataClient which its port is 1800 then when i use the dataClient to send a file .. the server receives the bytes at the job Method .. !! why does that happene?
Yes, it is wise to use multiple ports when doing file transfers. It would require a quite advanced protocol to use the same port and still keep the application response (as you still have to be able to send commands during file transfers).
But I do not recommend you to use three fixed ports. Use one port for all commands and an arbitrary number of ports for the file transfers.
A file transfer would look like this:
(CmdPort) Client -> Server Hey I want to transfer file XXX with size YYYY
(CmdPort) Server -> Client Roger, connect to port 8217 and transfer the file
(8217) Client -> Server Connects, transfer the entire file, disconnect
(8217) Server Checks that the transferred size matches the one specified in step #1
That allows you to transfer several files at the same time. Let the server create a new listening socket using port 0. It tells the OS to select a free port. Then use Socket.LocalEndpoint to find out the port before sending it back in step #2.
The specified approach also lets you take advantage of Socket.SendFile which is probably the most effective and fastest way to send files using .NET.
(FTP uses the same approach, as do bittorrent. You might have used a file manager when downloading files from the web. They takes a more extreme approach and splits up the file download over multiple sockets to get around web server bandwidth throttling.)
update in response to a comment:
my application also send folders , a folder may has 2000 files , many files size may equals to less than a kilo byte, it would be a huge mistake to connect for each file .. or maybe i should connect once for each task (a folder/ a file)
You did not specify that information in the original question, which made me assume that you only transfer one file at a time.
Batch transfers would work in the same way, just change so that step #1 sends a list of filename+size and then send all files after each other in step #3.
It would not be best practice to use 3 ports unless each operation was it's own application, i.e. a file server, an image server etc. You should create one application listening on 1 port and then use Threading to accept multiple connections to the server (each with it's own instance of a StreamReader). You could then write a parser method for the users input. For example, if the user sends the command "RECIEVE FILE", the server would expect a File, if the user sent the command "IMAGE" the server would expect an image.
An example of multi threaded servers can be found here:
http://csharp.net-informations.com/communications/csharp-multi-threaded-server-socket.htm

How can I send data over the internet using a socket?

I would like to send data over internet through a desktop application. I know a little bit about sockets. I have transferred the data within the LAN, but now I want to transfer the data over the internet. What is the best way to transfer both large and small quantities of data?
My system is connected to the server which has the access to the internet. My system's IP address is dynamic. I don't know how to send the data to another system which is connected to the internet. Do I need to find the router address? (My IP address is generated as 192.168.1.15).
Is using a socket enough, or is HTTP required?
Socket is enough if no firewalls/proxies are involved.
But, as Internet is involved (not the fastest connection), I suggest for the sake of convenience you should better opt for remoting over http. That way, even if in the future the setup changes, and firewalls/proxies get involved in the equation, you should not worry.
If all you want to do is transfer raw data from one machine to another it's very easy to do using a TCP socket.
Here's a quick example.
Server:
ThreadPool.QueueUserWorkItem(StartTCPServer);
private static void StartTCPServer(object state) {
TcpListener tcpServer = new TcpListener(IPAddress.Parse("192.168.1.15"), 5442);
tcpServer.Start();
TcpClient client = tcpServer.AcceptTcpClient();
Console.WriteLine("Client connection accepted from " + client.Client.RemoteEndPoint + ".");
StreamWriter sw = new StreamWriter("destination.txt");
byte[] buffer = new byte[1500];
int bytesRead = 1;
while (bytesRead > 0) {
bytesRead = client.GetStream().Read(buffer, 0, 1500);
if (bytesRead == 0) {
break;
}
sw.BaseStream.Write(buffer, 0, bytesRead);
Console.WriteLine(bytesRead + " written.");
}
sw.Close();
}
Client:
StreamReader sr = new StreamReader("source.txt");
TcpClient tcpClient = new TcpClient();
tcpClient.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.15"), 5442));
byte[] buffer = new byte[1500];
long bytesSent = 0;
while (bytesSent < sr.BaseStream.Length) {
int bytesRead = sr.BaseStream.Read(buffer, 0, 1500);
tcpClient.GetStream().Write(buffer, 0, bytesRead);
Console.WriteLine(bytesRead + " bytes sent.");
bytesSent += bytesRead;
}
tcpClient.Close();
Console.WriteLine("finished");
Console.ReadLine();
More information about your connection needs is required in order to give you an appropriate solution. There are many protocols at your disposal and there are trade-offs for all of them. You will probably choose one of these two transport layers:
UDP - This is a send-and-forget method of sending packets. Good for streaming media that doesn't necessarily have to be 100% correct.
The good:
No connection required.
Very lightweight.
The bad:
No guarantee of your packet reaching the destination (although most of the time they make it).
Packets can arrive out of the order in which you sent them.
No guarantee that their contents are the same as when you sent the packet.
TCP - This is a connection-based protocol that guarantees predictable behavior.
The good:
You will know for sure whether the packet has reached the destination or not.
Packets will arrive in the order you sent them.
You are guaranteed that 99.999999999% of the time your packets will arrive with their contents unaltered.
Flow control - if the machine sending packets is sending too quickly, the receiving machine is able to throttle the sender's packet-sending rate.
The bad:
Requires a connection to be established.
Considerable more overhead than UDP.
The list of pros and cons is by no means complete but it should be enough information to give you the ability to make an informed decision. If possible, you should take advantage of application layer-based protocols that already exist, such as HTTP if you are transferring ASCII text, FTP if you are transferring files, and so on.
You can do it with .Net's Socket class or you can work with the more convenient TcpClient class.
Firstly though you need to figure out what server you intend to communicate with. Is it an HTTP server or an FTP server? Both HTTP and FTP are application-level protocols which are implemented on top of (using) sockets, which is really a transport layer interface.
Your local IP address or the address of the router really doesn't matter. You however need to know the IP address of the remote host you intend to connect to. You can obtain this by calling:
IPHostEntry host;
host = Dns.GetHostEntry(hostname);
You might also want to think about other issues when working with sockets, such as using timeouts to mask failure, the possibility of resuming upload/downloads when transferring large files, etc. If you spend sometime looking on the net, you should be able to find higher level HTTP/FTP apis that will let you work with file transfers much more easily.
Judging by your question, you seem pretty new to sockets, so reading this might also help
In your question you mix different things. Sockets are an abstraction for network communication. You will certainly need a socket to communicate over the network. However, possibly you will not see that a socket is used (like in a web-browser). Http is a communication protocol. This is what goes through a communication channel.
Visual Studio has a lot of well made facilities for creating and consuming SOAP XML Web Services. I'd look into it if I were you. Sure, there is some overhead, but coding against it is extremely easy.
Of course, I'm not sure how well that would scale if you had to transfer, say, tens or hundreads of megabytes of data across slow internet connections. It does offer asynchronous I/O, but I don't think you can get a progress indicator, and there most definately isn't a resume functionality.
Added: You can also continue using your socket. There is no extra work invloved for connecting to a server across the internet. Just specify the server's IP address, and away you go. Your OS will take care of all the gory details like routers, missing packets, etc.
First you should make a decision what protocol you want to use TCP or UDP. Then you have two options: 1. use Socket (lower level) or 2. Use class like TCPClient or UDPClient (which represents a little higher abstraction.
I'd suggest (for the begging the second option).
What you want to know depends heavily on many parts of your infrastructure.
If you want to send data to a server that is transparently connected
to the internet, it is as easy as connecting to it's IP adress.
If you want to connect to some friend with a broadband connection, things
get tricky. You usually have to configure both of your routers (or at least the
target one) for NAT.
Familiarize yourself with NAT, and the basics of IP routing.
The details you provided are not sufficient to describe exactly what
you want to do.

C# 3.5 - Connecting named pipe across network

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

Categories