I'm following a tutorial # http://www.geekpedia.com/tutorial239_Csharp-Chat-Part-1---Building-the-Chat-Client.html to try and gather the basics of networking. For those not wanting to hit the jump, it's a quick tut demonstrating how to program a simple client-server-model chat application.
When I try and run the code in the tut, it works fine as long as both the client and the server are on the same network, but the second I try and do it externally (getting a mate to run the client app, and running the server app my side), it all goes to pot. The fact that the code works when in the same network leads me to believe that it's not a coding issue, but an issue with the way my network is set up.
I'm trying to run the server on my IP address at port 21719, which I have opened, but still other people can't connect to my server, not able to get any form of response at all.
The code (from the tut) that is being used for the server to listen to connections is:
public void StartListening()
{
IPAddress ipaLocal = ipAddress; //ipAddress is parsed from txtIP
tlsClient = new TcpListener(ipaLocal, 21719);
tlsClient.Start();
ServRunning = true; //for the running loop
// Start the new tread that hosts the listener
thrListener = new Thread(KeepListening);
thrListener.Start();
}
Now, the tutorial does actually point out that
IPAddress ipaLocal = ipAddress;
Will cause issues on some configurations, and I'm beginning to fear that my configuration may be included in that.
So, does anyone have any solution for me?
Thanks,
Sam
What is the local IP address that you're using? (ipAddress) If it's 127.0.0.1, that's not correct (I don't know how it would work internally either, but Windows seems to use magic from time to time). Also, if you have multiple NICs in your local machine, maybe the port forwarding is only set up to forward to one of them, and you're using the IP of the other?
If that's not the problem, here are a few generic suggestions:
Grab a copy of netcat. It's a small network testing util whose only job is to form a simple TCP connection. That will allow you to eliminate your code as a variable in all this. If netcat can form a connection, then you know the problem is your code. If not, you've confirmed that it's your router.
You can use WireShark (or TShark) to look for ICMP packets. Capture ICMP packets on the remote machine. If you get "Destination Unreachable" from the router, you've again proved that it's your router.
As Spencer said you need to make sure Port Forwarding is setup on your router, to forward all packets that come in on port 21719 to your internal machine. As for exactly how to do that, it's hard to say without knowing what type of router.
Are you having people use your external (internet) IP address? (See yours here.)
Have you pinholed your router to forward all communications from port 21719 to your server?
Some tips:
What kind of operating system are you using? Please check the Scope and/or Profiles (under Advanced tab) of your firewall rule.
While your friend is trying to telnet to the port (connect to the im server) monitor the traffic using Wireshark or Network Monitor (Wireshark have problems with Vista and Win 7). If you don't see anything hitting your machine the problem is probably on the router side. Double check the settings - you said you set the forward rule (NAT) but did it also set the rule on firewall of your router?
Related
I have two computers and they are connected via ethernet, i have set up an WCF connection and this all works ok, however when i host the same wcf on the local pc as the one i want to comunicate to and then do a wcf request via a channel, the request does not go to the remote pc but to my local pc. Is there a way to force a wcf request from a channel to go trough a specific ipaddress and not just go to any?
i'll try to explain how i use this:
there are two computers they are both similar and have two network adapters who have the same ipaddess and run thesame wcf software. so for example ipaddress for adapter 1 is: 10.10.10.1 and the other adapter is 10.10.10.2 on the same pc, and the other pc is similar. now these two pc need to communicate so i wire the two network adapters in cross example: pc 1 network adapter one goes to pc 2 network adapter 2. this so they are connected in 2 ways. so if i want to communicate with a simple socket from one to the other and back over the second adapter this all goes ok becouse i can bind a socket to a ipaddress and it will send it via the adapter it is bound to. but this does not seem to work with WCF. if i have two hosts on one pc, one for adapter 10.10.10.1 and one on 10.10.10.2 for the other adapter and i send a message to 10.10.10.2 that is on the remote pc, it will go in via the second network adapeter.
PC1 network adapter 1 (10.10.10.1) <--direct patch cable connection--> PC2 network adapter 2 (10.10.10.2)
PC1 network adapter 2 (10.10.10.2) <--direct patch cable connection--> PC2 network adapter 1 (10.10.10.1)
These connection arrows are direct connection patch cables!
all network adapters have a wcf hosted, and the software on both pc's is thesame.
this is all done for redundancy, more then two pc can be connected in a chain with this.
this is a little example of how i setup a request to the remote host:
public void Test()
{
string endPoint = "net.tcp://10.10.10.2:9985/connection";
NetTcpBinding binding = new NetTcpBinding(SecurityMode.None);
binding.ListenBacklog = 2000;
binding.MaxConnections = 2000;
binding.TransferMode = TransferMode.Buffered;
binding.MaxReceivedMessageSize = 104857600;
binding.SendTimeout = new TimeSpan(0, 1, 0);
binding.CloseTimeout = new TimeSpan(0, 0, 1);
binding.OpenTimeout = new TimeSpan(0, 0, 1);
binding.ReceiveTimeout = new TimeSpan(0, 1, 0);
//binding.HostNameComparisonMode = HostNameComparisonMode.Exact;
//binding.PortSharingEnabled = false;
ChannelFactory<Connection> pipeFactory = new ChannelFactory<Connection>(binding, new EndpointAddress(endPoint));
var pipeProxy = this.ChannelFactory.CreateChannel();
//fictional method: pipeProxy.SendRequestTunnelTo("10.10.10.1"); //this is the ipaddress that it should go out to however it goes out to "10.10.10.2"
//and this is another network adapter also on the local mashine and here is also a wcf host on
((IClientChannel)pipeProxy).AllowOutputBatching = true;
((IClientChannel)pipeProxy).Open();
pipeProxy.SystemRequest(); //do function
}
Ok, the issue here is routing. If windows thinks it can deliver the traffic directly to the other IP Address, it will do so.
In this case, it can't differentiate between the local 10.10.10.2 that it knows about and one that's on another network hidden behind a NAT.
The preferred solution is to not use the same subnet (so have 10.10.10.2 and 10.11.10.2 or similar), however that can sometimes require significant changes.
The next best option is to use the IP address of the NAT and have it port forward.
Say you have a setup like this (where the boxes with 2 ip addresses are NATing routers with both public and internal IPs)...
10.10.10.2 --- [10.10.10.1 | 1.2.3.4] --- Internet --- [5.6.7.8 | 10.10.10.1] -- 10.10.10.2
Then the machine on the left should try to connect to 5.6.7.8 which should forward connections to the machine on the right (and vice-versa with the right machine connecting to 1.2.3.4).
If you've got a WAN setup that makes the machines appear to be in the same network, that's as much of a problem as being on the same network. None of the routers on the network will be able to determine which 10.10.10.2 you mean,
If you weren't using exactly the same IP address, you might be able to force the issue using routing tables on your windows box. This can allow you to specify preferential routes so that all traffic for a given IP address goes out over the specified NIC. Unfortunately, beyond that point it's out of your control and entirely up to the network hardware how the packets are routed. If you have the ability to configure routing on the intermediate hardware, you could fix the route the whole way to the destination but this is usually an awful lot of work and likely to be broken when kit is updated/replaced as it's non-standard.
If you decide to look into forcing routes, start with the Windows route command
Edit: Re: Forcing routing over an interface...
the syntax is route add target mask gateway costmetric interfaceid
run route print at a command prompt and make a note of the interface id you want to use form the top of the output
then add a route like this:
route add 10.10.10.2 255.255.255.255 10.10.10.2 1 [interface id from above]
on my machine that would be
route add 10.10.10.2 255.255.255.255 10.10.10.2 1 11
Note that in this case we're telling it to use 10.0.0.2 as a gateway. I have no idea what the consequences of doing this will be as software attempting to access itself via a locally bound port might get very confused. Last caveat: I don't have a pair of physical machines to hand that I can test this on, and VMs don't really count as their networking is slightly different.
We're providing a cost metric of 1. This should give it a very high priority meaning it should be chosen above all other routes to that IP address.
The route will be lost when the system reboots. You can use a -p flag after route add to make the route persistent. I suggest you don't do this until you're sure it's working as intended.
2nd Edit: I think you're heading down a rabbit hole here. While it may be possible to trick the system into working this way, it's definitely not a common usage and I haven't been able to find anything that says it's supported.
It seems like your fundamental problem is that you've got no way to negotiate before assigning IP addresses as you have no network connectivity.
Some thoughts...
Sharing the IP is not going to be robust, so decouple from it. Instead of using a fixed IP in the url, determine the other IP address programatically.
You could have two builds, one which uses .1/.2 and the other which uses .3/.4. Any build1 could then talk to any build2 but not 1-1 or 2-2. This is a bit awkward but would work with little effort on your part.
Better would be to assign unique IPs to every machine you build, then provide a way to detect the other machine's address. Service location protocol is a likely candidate for this approach. Once you know the IP address you need to communicate with, configuring WCF should be trivial.
If assigning unique IPs is problematic, you could potentially have DHCP servers on all nodes but only turn them on if another one doesn't exist on that network (pair). That way, every machine would end up with valid IP addresses with no prior configuration.
Your endpoint address needs to identify the IP address you are targetting.
Edit/Summary
After a lot of trial and error, Paul Kearney - pk helped lead me to the answer, although I still don't know why this happens, at least I know how to get it to work.
Quick Summary: Clients can connect to port 8080 on my laptop when I'm directly connected to my network at work. Clients cannot connect to port 8080 when I'm on a home network. To solve this, I created a firewall rule (on my laptop) to allow inbound traffic on 8080. I'd really like to know why this is the case. Does my laptop's Windows Firewall service actually change its settings based on the network I'm connected to?
Note: This all works when I'm on my network at work, but it doesn't work on my home network, or someone else's home network. The host computer (my laptop) is the same at both locations.
I have a web app that uses SignalR. Everything works when I run the web app on the same machine as where the SignalR host is running. When I try to connect from a different machine, I get this error:
> GET http://10.0.0.13:8080/signalr/hubs net::ERR_CONNECTION_TIMED_OUT. Cannot read property 'client' of undefined.
That error comes from my index.html page:
<script src="http://10.0.0.13:8080/signalr/hubs"></script>
From the research that I've done, I know that I shouldn't be using localhost in my SignalR URL. So I used an asterisk. This is in my self-hosted SignalR app:
class Program
{
static void Main(string[] args)
{
string url = "http://*:8080";
using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
Console.ReadLine();
}
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
public class RaceHub : Hub
{
public void Send(string name, string message)
{
Clients.All.addMessage(name, message);
}
}
And this is my JavaScript to connect:
var signalRUrl = 'http://10.0.0.13:8080/signalr';
$.connection.hub.url = signalRUrl;
var hub = $.connection.raceHub; // proxy reference to hub
// Create a function that the hub can call to broadcast messages.
hub.client.addMessage = function (name, message) {
receiveSignalRMessage(name, message);
};
$.connection.hub.start(); // Start the connection.
Like I said, this all works locally. But it doesn't work from another machine. I do not have Windows Firewall enabled, so that's not the issue. Any ideas?
HTTPS didn't work. It works when I'm on my network at work, but not at home. The configuration is the same. Must have something to do with my home network.
Also, this is what the page looks like when it's working properly:
And this is what happens when it's not working:
(Full disclosure - #BobHorn typed up this answer based on my comments)
There are different firewall settings on your machine, depending on the type of network you are attached to.
Have you ever noticed when you connect to a new network for the very first time, it asks you to define it as "work, private, public, home, etc"?
Whatever you choose for that network is sticky, and the related firewall policy is applied when you are on that type of network.
To check this, you can either completely turn off your firewall, or make sure inbound port 8080 is open for all firewall profiles, especially "home" networks and/or the "home" firewall profile.
ahh.. so you say your windows firewall is off. Are you sure it's not OFF only for the WORK network profile, but enabled for the HOME network profile ?
To troubleshoot this, I would put wireshark on one of the client computers trying to connect to port 8080 at home, and see how/why it's being blocked or cannot connect.
You can also try to telnet to port 8080 from the client machine at home (if the Telnet Client feature is enabled). You'll know right away if the port is open and connection succeeds, or a big fat denied. Quick and easy test. type TELNET ServerIPAddress PortNumber from a command line. If Telnet command not found, you need to turn on the Telnet Client in Windows Features/Components.
Does your network use IP security? You might try using HTTPS instead to see if that alleviates anything.
It looks like your work network is blocking your IP. Try whitelisting your home IP on your work network.
I believe the issue here is that your laptop's IP address changes from one network (i.e. work) to another (i.e. home), but you may not be updating the value of the signalRUrl variable in your javascript file accordingly, thus the client side of your app is looking for a hub at an IP address that doesn't exist on your home network.
When you change networks, you need to update the value of signalRUrl in javascript to reflect the current IP address of the host machine.
i've written a simple local messenger with c# for use of myself. now it works over a local network(lan,wifi) and works fine.
now i want to give it to my friend and use it over internet but have no idea how to use different ip except local host.
i'd be grateful for any help.
thanks in advance.
private void InitializeConnection()
{
ipAddr = IPAddress.Parse(txtIp.Text);
tcpServer = new TcpClient();
tcpServer.Connect(ipAddr, 1986);
Connected = true;
UserName = txtUser.Text;
txtIp.Enabled = false;
txtUser.Enabled = false;
txtMessage.Enabled = true;
btnSend.Enabled = true;
btnConnect.Text = "Disconnect";
swSender = new StreamWriter(tcpServer.GetStream());
swSender.WriteLine(txtUser.Text);
swSender.Flush();
thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
thrMessaging.Start();
}
this the client part
public ChatServer(IPAddress address)
{
ipAddress = address;
}
private Thread thrListener;
private TcpListener tlsClient;
bool ServRunning = false;
public static void AddUser(TcpClient tcpUser, string strUsername)
{
ChatServer.htUsers.Add(strUsername, tcpUser);
ChatServer.htConnections.Add(tcpUser, strUsername);
SendAdminMessage(htConnections[tcpUser] + " has joined us");
}
and this server part.
Intro
To be able to get another user to connect to a computer of yours, there are a quite a few things you are going to have to do. Hopefully, this should work but networking can get complex in general and not all networks run alike. I assume you are running this behind some sort of router that you have access to. Networking is complex and that really is why this answer is so awfully long (if you are questioning yourself on reading the rest of it). For the most part it is pretty straight and forward, but might take some time.
And before you get started, just a:
Forewarning
Thinking security wise, like almost everything on computers and with networking in general, there is not really something called "entirely safe" (at least as far as I know). As with networking, opening ports is not entirely safe. I'm not a top notch security expert, but by doing this, you are allowing other computers to send and receive data with your computer. This should be safe in your case of just having a simple text chat, but in other cases this might not be the same. With more complex and important cases such as dealing with SSH and FTP, there is more security involved. Just as a warning, make sure to take care when messing with your network, or with computers in general.
Getting Started
Anyways, (if I have not scared you off yet) these are the steps that I had to take to get something like your chat server working:
Forwarding the port on your router
The first thing you are going to have to do is forward or open the port on your router. Well, before you can even do this, there are several things you need to understand about networking:
Basically, your router is what connects your network of computers to the internet and allows connections to be be made through ports. If you don't understand what a port is, it is what is used for internet connections to be made and basically acts like the house number to a street address. It tells where on that street the house it and is more specific than just the street address. In terms of networking, this is a number which tells the specific place the communication is going. The port number ("the house number") is telling where on the computer's IP address ("the street address") to connect.
Specifically, the port number is an 16-bit unsigned integer ranging from 0 to 65535 (but port number 0 actually cannot be used according to Wikipedia) Even though this is a 16-bit unsigned integer which would be a ushort or a UInt16 in C#, when using a TcpClient or a TcpListener, they instead use a signed 32-bit integer instead which is the standard int or a Int32. Also, The port is generally denoted after an IP address with a colon (":"), for example 123.45.67.89:80 but might be different in other cases. This is using IPv4 but there is also IPv6 which I have not yet worked with.
Now, what about forwarding the port and why do you need to do that? What forwarding the port does is forward connections to a certain port on the router to a computer which is behind the router instead. There is not always a simple, straight and forward way to do this since router companies have different ways of accomplishing this. Generally, to figure this out, you can Google for instructions on how to forward the port on your particular router, so for example you can search for "forward port on router company's name router" to find it. To do this, you are probably also going to need a few things before getting started with that:
You are going to need your routers admin user name and password which is generally not (and probably should not be) what is used to connect to it with. If you don't know what it is, whoever setup your router should know. Once you have got this working you are ready to move on.
You are also probably going to need the your computer's local IP address which is used to address the computers in the router's network. To find this, your router will probably tell you what it is, but here are the steps to do it on Windows if you can't seem to find it.
Open up command prompt
Open the run dialog by going to Start >> Run... or by pressing Win+R
Type cmd and press enter
Run ipconfig by typing it in and pressing enter to find your computers IP address
You should see a list of network interface connections
To find the one we are looking for, you want to find the network connection you are using to connect to the internet through your router. It is probably different on computer but in my case its named Wireless LAN adapter Wireless Network Connection since I'm using a laptop. The name, I would assume, probably has LAN in it.
This should not have: Media State . . . . . . . . . . . : Media disconnected listed under it since you need to be connected to your router. If you are not then simply do so.
Instead, there should be IPv4 Address. . . . . . . . . . . : with the IP address of your actual computer listed next to it. This is the IP address of the computer whose port you want to forward. Of course, this might be different if you are using a router using IPv6.
Also, in the process of doing this, your port number that were using may be taken by another process or service. This is okay and easy to fix; you just have to change the port number. You are going to want to trying a high number such as 8500 for example until you find one that works. Once you have that number, just update the port number in your code. To make this even easier it, is much easier to have a constant that stores this such as:
const int Port = 8500;
So then you can have the client connect with:
tcpClient.Connect(ipAddress, Port)
And then have the server listen with
TcpListener tcpListener = new TcpListener(ipAddress, Port);
As with other global variables such as the port number that you might have, it may be better to create a global variable class, but at the same time, that may also introduce other issues by using it such as with global properties with threading. Just a suggestion and a heads up.
Though, once you have managed to complete forwarding the port, you can move on to the much simpler part of getting your friend to actually connect to your server.
Geting your router's IP address
Once you have managed to do all of that, you probably should give your a pat on the back because that is the real actual part of getting your router to cooperate with what you were trying to do. Now you just have you give your IP address, port number, and of course your client program to your friend, so he or she can connect to the server. To get your router's public IP address you can go over to the ironically called website at http://www.whatismyip.com/. Here you can get your public IP address but also make sure that it says "No Proxy Detected" below it. If you are using a proxy, hopefully you know what that is and can connect to the internet without to get your IP address. (Trust me, you don't want me to explain want a proxy is for now)
Now once you have got that, you are going to want to send that IP and also your port number to your friend. To be smart about it, you don't want this publicly displayed as you probably don't want a bunch of random people trying to break into your network. Sending it over IM or email should (hopefully) be fine as long as your friend does not publicly display it. So when sending your IP address, just be smart about it.
Once you have done that, just don't forget to actually start your server! Without your server running, there is no way to communicate to the clients and accept incoming connections. This will save a lot of frustration from accidentally forgetting to.
Conclusion
Hopefully, this will help you be able to create a cool chat program and also understand a few other things in the process. I really wish this was not so long, but networking is really just complicated in for the most part.
Hope this helps you quite a bit!
My situation: I have an xspeech for voip, when there is an action about phone, the messages(packets) are sent to the xspeech interface. And from this interface the logs of these action are sent to specific IP address which is my IP address. And also these logs are sent from a specific port.
I am trying to develop an application that reads these logs(not a file). I tried TCPListener and TCPClient, they worked but not in my situation. I thought these logs are not sent from TCP port. This is the problem.
From your post I suspect it is using UDP... this would mean that you need to use UDPClient class to receive and process...
Depending on whether they offer a TAPI provider you can use:
http://www.codeproject.com/KB/IP/devangpro.aspx
http://www.codeproject.com/KB/dotnet/CShart_TAPI_3x.aspx
http://www.codeproject.com/KB/IP/Video_Voice_Conferencing.aspx
http://msdn.microsoft.com/en-us/library/ms734214.aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/ms734257%28v=vs.85%29.aspx
It may be necessary to build a SIP proxy (this would be able to generate for example "Pickup event"):
http://www.codeproject.com/KB/cs/SIP_stack_with_SIP_proxy.aspx
http://sipsorcery.codeplex.com/
http://www.independentsoft.de/sip/index.html
http://www.konnetic.com/products/products_sip_sdk_std.aspx
http://www.voiceelements.com/Products/VEToolkit.aspx
EDIT - as per comments other possibilities:
If what you try to catch is sent as syslog message then see http://michael.chanceyjr.com/useful-code/syslogd-class-for-sending-and-receiving-syslogd-events/ .
Another possibility is SNMP - for this see http://www.snmpsharpnet.com/
SIP uses UDP per default.
It's not as simple as being able to take packets from one endpoint, log them and then send them to the real destination. You'll break things like NAT handling if you do so.
You need to act as a full SIP proxy (stateful) or as a B2BUA.
The easier way is to download an existing sip-proxy and just make it log to a file and read that file.
If you're recieving the information on at your IP address then I too would have thought that TCP/IP was being used. Have you checked that your firewall isn't blovking the port in question.
I would suggest that you have another look at what protocol is being used (it may be UDP) and use the Socket class instead.
I'm trying to add networking over the internet to my game, using Peer to Peer.
I have already implemented a LAN only version, which uses .NET's peer to peer classes to connect within the local network.
I realized I need to use UDP hole punching in order to establish a connection to other clients that are behind a firewall.
This is how I have started to implement it:
The server is a HTTP server using very simple PHP scripts to get the job done.
register name on server, sending the private ip address and port as a GET variable
when the server gets a registration request, it will save the public endpoint and the private endpoint
request to connect to another client.
the server will return the private and public endpoints of the client
every two seconds, the second client will check in with the server, and if there is another client attempting to connect with it, it will get its endpoints too
both clients start spamming each others public endpoints until they get a valid response
Now I have a bunch of questions
Can the server be a HTTP server?
When I make a request to an HTTP server, the client port changes each time a request is made. Is a private endpoint always matched to the same public endpoint?
Does the request to the server have to have the same source endpoint as the UDP messages to the client?
Is there a way to connect to an HTTP server in C# using a specified source endpoint?
Are there any problems with my implementation?
Thanks!
UDP hole punching is a complex topic, and many attempts have been made to find a solution that works. The problem is that there are so many different NAT routers out there, and there is no standard way of implementing NAT, so all routers behave a bit different.
Some attempts have been standardized, e.g. STUN, ICE. They still work only in most cases, not all, but they accumulate a lot of knowledge and address many concerns -- more than your attempt will ever be able to, simply because you can't test your solution with every NAT router under the sun. Skype, for example, spent years of perfecting its NAT traversal mechanism.
I recommend you have a look at STUN or preferably ICE. Try to implement one of them or look for existing implementations.
Another option might be to simply create a port forward at the router, e.g. using UPnP or NAT-PMP.
That said, I wouldn't be surprised if the .NET peer to peer classes came with a NAT traversal mechanism, but I'm not familiar with them.
STUN is a best solution for the problem. it works for most of the scenarios.here is a simple example(C#) that gives you the NAT type,Local IP:Port and Public IP:Port.
try
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(new IPEndPoint(IPAddress.Any, 0));
STUN_Result result = STUN_Client.Query("stunserver.org", 3478, socket);
Console.WriteLine("Net Type : " + result.NetType.ToString());
Console.WriteLine("Local IP : " + socket.LocalEndPoint.ToString());
if (result.NetType != STUN_NetType.UdpBlocked)
{
Console.WriteLine("Public IP : " + result.PublicEndPoint.ToString());
}
else
{
Console.WriteLine("");
}
}
catch (Exception x)
{
Console.WriteLine(x.StackTrace.ToString());
}
You can just add some breakpoints and check the behaviour of the code.
also you can traverse NAT using vs2010 onwords (.net4.0 < ) . there is a method AllowNATTraversal (bool value). set the value true for NAT Traverse. It uses Ipv6 address for connectivity. You can get Ipv6 global address from "Teredo" server by writing some commands in command prompt. Actually IPV6 is the technology that is used to avoid this problem.