I have a IIS hosted WCF service that is configured with a WebHttpBinding. It is the same default WCF service VS2008 creates when you create a new one. The only changes I have made is to allow it to be called from javascript.
In the test method GetData(int value), i return a string that displays the remote clients IP address, port, and useragent. Everything works fine, except I am not expecting the port number it is returning. I am expecting port 80, but instead get something like 49353. Below is the method I am calling.
public string GetData(int value)
{
OperationContext context = OperationContext.Current;
MessageProperties messageProperties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpointProperty = messageProperties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
return string.Format("Hello {0}! \r\naddress: {1}\r\nport: {2}\r\nuseragent: {3}",
value, endpointProperty.Address, endpointProperty.Port, WebOperationContext.Current.IncomingRequest.UserAgent);
}
Like I said, i am invoking this method from javascript. IIS is configured for port 80, so I am not sure why the port is being reported wrong.
I think you might have this a bit backwards. Port 80 is where you are listening, but once that happens, it passes that off to a new ephemeral port to handle that connection.
Also, the client is also probably using an ephemeral port to open the connection to port 80. So the client's port is likely some "random" port number outside the typical "fixed" port range (0-1024).
Related
I am trying to use the TCP protocol with the System.Net.Sockets library to have one computer send a string to the other. Here is part of my host code. Is the listener object supposed to be declared with the client IP address or the host IP address (like it is in the code below)?
IPAddress ipAddr = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0]; //Automatically retrieves IPAddress.
int port = 135; //specify port number.
TcpListener listener = new TcpListener(ipAddr, port);
Also, here is a piece of my client code. Which constructor do I use?
TcpClient client = new TcpClient();
The listener object listens on the host's IP. The constructor takes it as an argument because you could have several IP's on the computer and it doesn't know which one you want to listen on.
As far as the client goes, you can pick whichever constructor you want. By using the parameterized constructors, you can connect right away, whereas the default requires a call to one of the overloads of Connect. It mostly depends on if you actually want to connect at instantiation time.
See MSDN for the overloads you can use.
Here is a TCP server sample code:
int port = 135; //specify port number.
TcpListener listener = new TcpListener(IPAddress.Any, port);
// Start listening for client requests
listen.Start();
And then you can select to use polling method to create a simple sync TCP server.
The client (PowerShell):
$Address = [System.Net.Dns]::GetHostAddresses("<hostName>")
$Port = 135
$client = New-Object System.Net.Sorckets.TcpClient
$Client.Connect($Address, $Port)
I successfully made a client server program in C# working perfectly under a LAN, we used the TcpListener and TcpSocket class.
We could not get it to work over the internet though, I understand that it has to do with firewalls, router port blocking etc.
We forwarded the port we used and turned off our firewalls and still no luck.
What do I have to do differently in order to make this work? Like a certain port to use that will work without issues? How does say "Msn Messenger" do it?
Server Code:
private static TcpListener serverTcpListener;
public static bool Run()
{
// Initialize new thread for client communications
Thread listenThread = new Thread(new ThreadStart(ListenForClients));
// Initialize TCP listener and attempt to start
ServerTcpListener = new TcpListener(IPAddress.Any, 3000);
try
{
ServerTcpListener.Start();
}
catch (SocketException)
{
return false;
}
// Start client communications thread
listenThread.Start();
return true;
}
public static void ListenForClients()
{
while (true)
{
TcpClient client = ServerTcpListener.AcceptTcpClient();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
Client Code:
private TcpClient myClient;
private NetworkStream clientStream;
public InitializeResult Initialize()
{
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
try
{
MyClient.Connect(serverEndPoint);
}
catch (SocketException)
{
return InitializeResult.AccessError;
}
catch (ArgumentNullException)
{
return InitializeResult.NullRemote;
}
try
{
ClientStream = MyClient.GetStream();
}
catch (Exception)
{
return InitializeResult.StreamFail;
}
if (!Authenticate())
{
return InitializeResult.AuthenticateFail;
}
return InitializeResult.Success;
}
Here are some common problems you might run in to:
Server
Windows Firewall.
Here is a tutorial on how to allow your program through the firewall: http://windows.microsoft.com/en-US/windows7/Allow-a-program-to-communicate-through-Windows-Firewall
Port forwarding on the router.
http://portforward.com/ is a good resource, I believe you can select your router and it will give you steps for that. You will need to select the LAN IP address of the machine hosting the server, and the port you are attempting to connect on (in your case, 3000) .
Client
For the client, it should be able to connect fine, but you will have to specify the external IP address, and not the LAN IP address of the server. You can find it by going to http://whatismyip.com on the computer hosting the server.
--
Msn and similar chat programs use a straightforward client/server approach like this - very easy to accomplish. A very interesting chat program to look into though, is Skype. It uses a P2P system, not a Client-Server. It accomplishes it using Nat Hole Punching, if you're interested (as a student) I'd suggest looking into it to expand your knowledge of networking.
If this:
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
is exactly what's in your client code, that's probably where the issue lies, even if firewalls are set up right. You'll have to modify the client program to take an IP as a configuration setting, command line parameter, text box, etc. and then use that instead.
I would first test this with two computers on the same LAN, if possible, using the address of the box running the server. If you can't connect, ensure the IP is right (by running ipconfig on the machine running the server), and seeing if Windows Firewall is on on the server. If it is, you'll either have to allow your program, or just open port 3000.
Once that's confirmed working, from another network entirely, with the external IP of the network the server is on. You can get this by going to http://icanhazip.com/ or similar (I prefer this over whatismyip, no ads, it only serves back the IP address), and ensuring port 3000 on the firewall/router is set to be forwarded to the internal IP of the server box.
You need to bind to the external NIC. Chances are you bind to the Loopback adaptor
If you provide some code, we could, maybe, diagnose (or even fix) things
You need to replace 127.0.0.1 with your actual IP address in:
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
To get your IP you can Google "what is my ip" or go to www.whatismyip.com/ from the server.
I also recommend installing Wireshark on both your client and server. I use this tool often when debugging sockets and other network issues.
The problem is, the following code works well if IPAddress.Any was given as a parameter, but throws an error if `IPAddress.IPv6Any is used.
I receive error #10057
Socket is not connected.
A request to send or receive data was disallowed because the socket is
not connected and (when sending on a datagram socket using
sendto) no address was supplied. Any other type of operation might
also return this error—for example, setsockopt setting SO_KEEPALIVE if
the connection has been reset.
Why does it fails to work as IPv6Any? I'm pretty sure it's not the firewall, since the port remains the same and it works with IPv4 (and my firewall should pass any requests made by my application).
To short up the code, it's something like this:
The Listener:
listener = new TcpListener(IPAddress.IPv6Any, portNr);
listener.AllowNatTraversal(true);
listener.Start();
listener.BeginAcceptTcpClient(this.AcceptClient, null);
The Client:
client = new TcpClient();
client.NoDelay = true;
try
{
this.client.Connect(ip, port); //ip = "localhost" when connecting as server
}
catch (Exception ex)
{
FileLogger.LogMessage(ex);
Disconnect();
}
I'm trying to set up the "server-side" of the TCP-connection.
What I do is that I start a listener at localhost, and then connect to it as a client (and allow others to join as clients as well).
What I'm trying to achieve with this is direct addressability of this TCP server, following this article: http://blogs.msdn.com/b/ncl/archive/2009/07/27/end-to-end-connectivity-with-nat-traversal-.aspx
The reason I'm doing this is that I want person A to be able to connect to a person B when they both are behind NAT routers.
I know this answer comes a bit late, but I also had this issue and it was client related. The problem is, that your provided code...
client = new TcpClient();
... creates an IPv4-Instance of the TcpClient that is not capable of interpreting IPv6-Addresses. So if you already have the IP address at the moment of initialization, try to initialize your TcpClient like this:
TcpClient client = new TcpClient(ip.AddressFamily);
If the variable ip is a string, you need to convert it to type IPAddress first:
IPAddress iAddr = IPAddress.Parse(ip);
Actually a IPv6-TcpClient seems to be compatible to IPv4-Addresses as well, so you can also initialize your client as follows:
TcpClient client = new TcpClient(AddressFamily.InterNetworkV6)
Whilst the upper suggestions seem to be the cleanest ones, the bottom suggestion seems to be the more universal one. At the end it's up to your preferences.
I solved a similar issue where the following line would only block connections coming from IPv4 addresses:
listener = new TcpListener(IPAddress.IPv6Any, portNr);
It seems the socket when configured to accept IPv6 connections, by default, accepts ONLY IPv6 connections. To fix this problem i had to update my code to this:
listener.Server.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, false);
listener.Start();
When you use TcpClient.Connect(string, int) you make it possible to break because of DNS resolution.
Though Microsoft documents that IPv6 address will be tried first, the resolution may only return IPv4 addresses.
http://msdn.microsoft.com/en-us/library/8s2yca91.aspx
Therefore, can you try to call TcpClient.Connect(IPAddress.IPv6Loopback, port) on client side to test if it works?
IPAddress.Loopback == FAIL
IPAddress.IPv6Loopback == SUCCESS
Perhaps localhost is mapping to the IPv4 Loopback Address in your case?
I have a server application. I also have a client application. I am able to establish a tcp connection between the applications when both applications happen to be on the same network. so let's say that the computer running the server application is listening from new connections on port 2121 and it has the LAN ip address 192.168.0.120. On a different computer running the client application I will be able to establish a connection by providing port number 2121 and ip address 192.168.0.120.
Is there a way to find all computers on a network that are listening on port 2121?
One algorithm that I am thinking now is like:
get ip address of current computer and lets say it comes out as 192.168.0.145.
now most likely the server will be listening on ip addresss 192.168.0.?
then ping 192.168.0.1 on port 2121 then 192.168.0.2 on port 2121 ... and then keep going.
I don't know if that method is efficient. moreover there might be a possibility that the server happens to be listening on ip address 192.168.1.x
So what changes will I have to make to my server and client application so that the client is able to find all the servers listening on port 2121?
The algorithm you proposed is the one you need. One problem is in the dynamic generation of the candidate IP addresses.
Normally, the possible IP address range is the one given by the subnet mask ( http://en.wikipedia.org/wiki/Subnetwork ). More exactly, the part of the IP that change is that part when in the subnet mask you have 0bits (always at the end of mask).
In your example:
if the mask is 255.255.255.0, then your possible ip address range is
192.168.0.*.
if the IP can also be 192.168.1.* then probably the mask should be 255.255.0.0
you can also have mask like 255.255.255.128 and the range would be 192.18.1.[1-126]. You can practically learn more using http://www.subnet-calculator.com/
The only other possibilities which cause your problem that I see to have these distinct ranges are:
you have more DHCP servers in your network, which is really bad as you will have "race conditions". The solution here is to fix your infrastructure by removing all but 1 DHCP server
you have manually set IP addresses (probably on laptops). The solution is to change to DHCP (if you need a specific IP that will always be assigned to a specific computer, use static DHCP)
Getting back to the problem of finding the problem of checking if "something" is listening on a specific port, the ICMP protocol is not the best here, as the majority of firewalls filter both the broadcast ICMP and single ICMP. If we are truly talking of a server, chances are you had to manually open the port you are looking for. Also, even if all computers respond, you still don't know if they host your wanted service.
The solution below involves computing the possible range of candidate IP addresses. After that you iterate through them to see if you can connect to your port.
In this implementation I test sequentially, which proves to be very slow as the timeout for connect is 30 seconds if the host is not on. For several hundred candidates, it doesn't sound too good. However, if the majority of host are available (even if they don't host your service), everything will go several times faster.
You can improve the program by either finding out how to decrease this timeout (I couldn't find out how in my allocated time) or to use a custom timeout as presented in How to configure socket connect timeout . You could also use multi-threading and adding the address that worked in a thread-safe collection and work with it from there.
Also, you could try pinging (ICMP) before, but you could miss valid servers.
static void Main(string[] args)
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
int wantedPort = 21; //this is the port you want
byte[] msg = Encoding.ASCII.GetBytes("type msg here");
foreach (NetworkInterface netwIntrf in NetworkInterface.GetAllNetworkInterfaces())
{
Console.WriteLine("Interface name: " + netwIntrf.Name);
Console.WriteLine("Inteface working: {0}", netwIntrf.OperationalStatus == OperationalStatus.Up);
//if the current interface doesn't have an IP, skip it
if (! (netwIntrf.GetIPProperties().GatewayAddresses.Count > 0))
{
break;
}
//Console.WriteLine("IP Address(es):");
//get current IP Address(es)
foreach (UnicastIPAddressInformation uniIpInfo in netwIntrf.GetIPProperties().UnicastAddresses)
{
//get the subnet mask and the IP address as bytes
byte[] subnetMask = uniIpInfo.IPv4Mask.GetAddressBytes();
byte[] ipAddr = uniIpInfo.Address.GetAddressBytes();
// we reverse the byte-array if we are dealing with littl endian.
if (BitConverter.IsLittleEndian)
{
Array.Reverse(subnetMask);
Array.Reverse(ipAddr);
}
//we convert the subnet mask as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
uint maskAsInt = BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t subnet={0}", Convert.ToString(maskAsInt, 2));
//we convert the ip addres as uint (just for didactic purposes (to check everything is ok now and next - use thecalculator in programmer mode)
uint ipAsInt = BitConverter.ToUInt32(ipAddr, 0);
//Console.WriteLine("\t ip={0}", Convert.ToString(ipAsInt, 2));
//we negate the subnet to determine the maximum number of host possible in this subnet
uint validHostsEndingMax = ~BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t !subnet={0}", Convert.ToString(validHostsEndingMax, 2));
//we convert the start of the ip addres as uint (the part that is fixed wrt the subnet mask - from here we calculate each new address by incrementing with 1 and converting to byte[] afterwards
uint validHostsStart = BitConverter.ToUInt32(ipAddr, 0) & BitConverter.ToUInt32(subnetMask, 0);
//Console.WriteLine("\t IP & subnet={0}", Convert.ToString(validHostsStart, 2));
//we increment the startIp to the number of maximum valid hosts in this subnet and for each we check the intended port (refactoring needed)
for (uint i = 1; i <= validHostsEndingMax; i++)
{
uint host = validHostsStart + i;
//byte[] hostAsBytes = BitConverter.GetBytes(host);
byte[] hostBytes = BitConverter.GetBytes(host);
if (BitConverter.IsLittleEndian)
{
Array.Reverse(hostBytes);
}
//this is the candidate IP address in "readable format"
String ipCandidate = Convert.ToString(hostBytes[0]) + "." + Convert.ToString(hostBytes[1]) + "." + Convert.ToString(hostBytes[2]) + "." + Convert.ToString(hostBytes[3]);
Console.WriteLine("Trying: " + ipCandidate);
try
{
//try to connect
sock.Connect(ipCandidate, wantedPort);
if (sock.Connected == true) // if succesful => something is listening on this port
{
Console.WriteLine("\tIt worked at " + ipCandidate);
sock.Close();
sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
//else -. goes to exception
}
catch (SocketException ex)
{
//TODO: if you want, do smth here
Console.WriteLine("\tDIDN'T work at " + ipCandidate);
}
}
}
Console.ReadLine();
}
sock.Close();
}
(sorry for my bad english) I am actually needing something similar to this and just found out about multicast. Here you can find an article and example. The sample app from the article worked fine on my lan. I do not know exactly how it works but maybe you can multicast something from the client and have the server(s) to respond with its IP? Or if that do not work, have the server multicasting his IP in a timed interval should do it. Sorry for the lack of informations, i just learned about this :)
An option i am not seeing beeing discussed here is to have a Master Server.
The idea is quite simple: A server where your application's server can register and where you application clients can get a list of active servers.
Server A is loaded and imediatly sends a hello message to the Master Server
Server B is loaded and sends an hello message to the Master Server
Both Server A and B keep sending hello's to Master Server every X Minutes so he knows they are still on
Client A is loaded - Needs to issue command - asks Master Server for List of Active Servers - Picks a server from the list - issues command
Things to keep in mind:
Master Server must be on a known address / port - either fixed ip or get ip throw well known ServerName
Purpose of Master Server is simply register servers and supply clients with their addresses - At first glance i see no other service it could provide your application
If any server is as good as any other for your application, i would advise the list to be ordered according to timestamp of last hello message received from that server - that way client will have at the top of that list the server most likelly to still be up (since it reported beeing up last) and can go down the list subsequentially.
More over, every time the Master Server receives an hello that list changes, so every so often client requests will get a different server list and use a different preferencial server, relieving load on servers accross the board.
can't you use the same method as when you get your ip.
let the client send a broadcast - if no response wait
server receive broadcast and send one back with its own ip.
now the client know that the server is out there and on what ip.
I assume you have a single server. If you can guarantee that the server location (ip address and port) is constant (or can be looked up) then each client application can 'register' with the server by connecting to it and informing the server about the ip address and local port to call back.
ICMP Ping does not determine if a computer is listening on a specific port, only if the computer is configured to response to a ping. ICMP is a protocol, different then TCP or UDP. It's only use for you would be to determine if an IP Address is use, and even then is becoming less viable.
You have two options.
Have the client constantly check every IP address on your local network and try to open port 2121. This is not a good option.
Have every server send out a ICMP ping to the broadcast address with specific data announcing it is on (and optionally not connected to a client) the never every so often (I would recommend a minute for testing, and 5 minutes minimum for production). All your software has to do is look for the broadcast ping and connect to the sending IP Address.
Update:
using System.Net.NetworkInformation;
private Ping _Ping = new Ping();
private PingOptions _PingOptions = new PingOptions(64, true);
private byte[] _PingID = Encoding.ASCII.GetBytes("MyPingID");
private _PingResponse = new AutoResetEvent(false);
public <classname> //Constructor
{
_Ping.PingCompleted += new PingCompletedEventHander(PingCompleted);
}
public void PingCompleted(object Sender, PingCompletedEventArgs e)
{
if (e.Cancelled)
{
//Status Unknown;
}
else if (e.Error != null)
{
//Status Error;
}
else if (e.Reply.Status == IPStatus.Success)
{
// Device Replying
}
else
{
// Status Unknown
}
}
public void StartPing(string AddressToPing)
{
IPAddress ipAddress = IPAddress.Parse(AddressToPing);
_Ping.SendAsync(ipAddress, 15000, _PingID, _PingOptions, _PingResponse);
}
you can make the server send his location to a specific port using UDP, and the client listen to it then the client establish a connection with the server based on the given ip and port.
). I got into a bit of issues today with the TcpListener. Things are strange. Initially, I used the new TcpListener(port) constructor, but that has been marked as obsolete. So I dropped it and used this instead:
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, ServerPort);
TcpListener tcpServer = new TcpListener(ipLocalEndPoint);
_TCPClient = tcpServer.AcceptTcpClient();
GotClient();
I do that in a thread, of course, so that it doesn't lock the application. Now, what happens there, is that even though the ipAddress is correct, the server NEVER accepts ANY incoming connection.
HOWEVER, changing to new IPEndPoint(IPAddress.Any, ServerPort) seems to do the trick! Which is silly in 2 ways:
2 hours ago, IPAddress.Any returned 192.168.1.102 which is my correct local IP. This is the same IP which was in ipAddress! But with ipAddress it didn't work, while with IPAddress.Any it worked (that is, it successfully accepted connections from my client).
Right now: IPAddress.Any returns 0.0.0.0 (!?) while the ipAddress variable continues to be assigned my correct IP (192.168.1.102). The result? My client still cannot connect if using ipAddres, but connects when using IPAddress.Any, even though it is 0.0.0.0.
I'm totally puzzled by this... Any thoughts?
I currently have this in Form_HandleCreated but it was acting weird when I had it in the Form's constructor as well.
LATER EDIT: I think I'm wrong about IPAddress.Any returning 192.168.1.102. I probably printed out something else, as many of you have indicated 0.0.0.0 is what .Any should return. Sorry ::- D.
IPAddress.Any should return 0.0.0.0, that is normal. Are you actually sure it returned something else initially?
As for why you couldn't connect before, if you were listening on 192.168.1.102, and tried to connect to 127.0.0.1 (localhost), then it wouldn't work. You need to listen on 127.0.0.1 if you want to connect to that IP address.
Essentially, you must listen on the IP address you are attempting to connect to. Listening on 0.0.0.0 means, "listen on all available IP addresses". Remember, 127.0.0.1 (localhost) is not a synonym for "my local network IP".
0.0.0.0 is blank IP address meaning "I don't care which IP you would use" - i.e. it means you want to listen on all interfaces. It is documented it should return it.
To later edit: First of all dont call [0]. Your hostname may not have any record associated. Even if it do you a) don't know the order b) you don't know where they are (i.e. it may be only 127.0.0.1 i.e. loopback).
On mono such code work (checked with netstat etc.):
using System;
using System.Net;
using System.Net.Sockets;
public class test {
public static void Main(String[] args) {
IPAddress ipAddress = Dns.GetHostEntry(Dns.GetHostName()).AddressList[0];
IPEndPoint ipLocalEndPoint = new IPEndPoint(ipAddress, 8888);
TcpListener tcpServer = new TcpListener(ipLocalEndPoint);
tcpServer.Start(); // Without this line there is exception
var _TCPClient = tcpServer.AcceptTcpClient();
}
}
I'm guessing it always returned 0.0.0.0...