I have connected to a wifi and also i have access to the internet by ethernet.
Is there anyway to control WebClient.DownloadString to use ethernet instead of wifi or wifi instead of ethernet?
This is somewhat advanced functionality which is abstracted away by both HttpWebRequest, WebRequest, WebClient and the like. You can, however, do this using TcpClient (using the constructor taking a local endpoint) or using sockets and calling Socket.Bind.
Use the Bind method if you need to use a specific local endpoint. You must call Bind before you can call the Listen method. You do not need to call Bind before using the Connect method unless you need to use a specific local endpoint.
Bind to a local endpoint for the interface you want to use. If your local machine have ip address 192.168.0.10 for the WiFi address, then using that a local endpoint will force sockets to use that interface. Default is unbound (really 0.0.0.0) which tells the network stack to resolve the interface automatically, which you want to circumvent.
Here's some example code based on Andrew's comment. Note that specifying 0 as local endpoint port means that it is dynamic.
using System.Net;
using System.Net.Sockets;
public static class ConsoleApp
{
public static void Main()
{
{
// 192.168.20.54 is my local network with internet accessibility
var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.20.54"), port: 0);
var tcpClient = new TcpClient(localEndPoint);
// No exception thrown.
tcpClient.Connect("stackoverflow.com", 80);
}
{
// 192.168.2.49 is my vpn, having no default gateway and unable to forward
// packages to anything that is outside of 192.168.2.x
var localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.49"), port: 0);
var tcpClient = new TcpClient(localEndPoint);
// SocketException: A socket operation was attempted to an unreachable network 64.34.119.12:80
tcpClient.Connect("stackoverflow.com", 80);
}
}
}
Related
I am using a TcpClient in C# to communicate with a server.
When I view the first SYN request in Wireshark, I see 12 bytes specifying 6 TCP Options in the following order:
-Maximum Segment size
-NOP
-Window Scale
-NOP
-NOP
-SACK Permitted
TCP_Options <<< A screenshot of the Wireshark capture
I am using the default constructor of the TcpClient object being passed into the function.
I believe there is a way to specify an option using the Socket.SetSocketOption Method (described here), however, I wish to remove these options to verify that the server doesn't require them to establish connections.
Is it possible to remove (or perhaps modify) the options that I am seeing in Wireshark?
Here is a small sample of how I am using the TcpClient (instantiated with defaults):
public static IPStatus PingThenConnect(TcpClient tcpClient, IPEndPoint serverEndpoint)
{
IPStatus ipStatus = IPStatus.Unknown;
// Ping the given IP Address
ipStatus = Network.PingIP(serverEndpoint.Address);
if (ipStatus == IPStatus.Success)
{
// Connect TcpClient to given endpoint.
tcpClient.Connect(serverEndpoint.Address, serverEndpoint.Port);
tcpClient.LingerState = new LingerOption(true, 10);
}
return ipStatus;
}
I have the following UDP server listening on Port 11000:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace UDPServer
{
class Program
{
static byte[] dataToSend = new byte[] { 1, 2, 3, 4, 5 };
// get the ip and port number where the client will be listening on
static IPEndPoint GetClientInfo()
{
// wait for client to send data
using (UdpClient listener = new UdpClient(11000))
{
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 11000);
byte[] receive_byte_array = listener.Receive(ref groupEP);
return groupEP;
}
}
static void Main(string[] args)
{
var info = GetClientInfo(); // get client info
/* NOW THAT WE HAVE THE INFO FROM THE CLIENT WE ARE GONG TO SEND
DATA TO IT FROM SCRATCH!. NOTE THE CLIENT IS BEHIND A NAT AND
WE WILL STILL BE ABLE TO SEND PACKAGES TO IT
*/
// create a new client. this client will be created on a
// different computer when I do readl udp punch holing
UdpClient newClient = ConstructUdpClient(info);
// send data
newClient.Send(dataToSend, dataToSend.Length);
}
// Construct a socket with the info received from the client
static UdpClient ConstructUdpClient(IPEndPoint clientInfo)
{
var ip = clientInfo.Address.ToString();
var port = clientInfo.Port;
// this is the part I was missing!!!!
// the local end point must match. this should be the ip this computer is listening on
// and also the port
UdpClient client = new UdpClient(new IPEndPoint(IPAddress.Any, 11000));
// lastly we are missing to set the end points. (ip and port client is listening on)
// the connect method sets the remote endpoints
client.Connect(ip, port);
return client;
}
}
I also have opened a port in my router so when data is received from my router's gateway address, it will map to my hosting computer on 192.168.1.101:1000 as shown here:
I also have the following client defined, which is running on another machine (192.168.1.108) on the LAN:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace UDPClient
{
class Program
{
static void Main(string[] args)
{
string ipOfServer = "205.172.111.250";
int portServerIsListeningOn = 11000;
// send data to server
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPAddress send_to_address = IPAddress.Parse(ipOfServer);
IPEndPoint sending_end_point = new IPEndPoint(send_to_address, portServerIsListeningOn);
sending_socket.SendTo(Encoding.ASCII.GetBytes("Test"), sending_end_point);
// get info
var port = sending_socket.LocalEndPoint.ToString().Split(':')[1];
// now wait for server to send data back
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, int.Parse(port));
byte[] buffer = new byte[1024];
sending_socket.Receive(buffer); // <----- we can receive data now!!!!!
}
}
}
Please notice the ipOfServer. This is my external gateway (not really since I obfuscated it, but it is not 192.168.1.101 - the internal IP of my UDP server).
When I direct the client to send to the internal LAN IP of 192.168.1.101:11000, the UDP Server connects.
However, when I use the gateway's IP address and port, the UDP Server does not connect. Since I have the port directed to 192.168.1.101:1000 in the NAT, I'm not sure what gives.
I know the NAT setting are good since I also have port 80 for HTTP and port 808 for net.tcp all working from anywhere, even outside of my network.
Please give me some insight as to what I am doing wrong.
Kind regards
It's hard to know exactly what's wrong without having access to your actual network setup. However, the scheme of creating a socket just to receive some data which is discarded, only to then create a new socket which you then "connect" to the client, seems wrong. You probably shouldn't be using Connect() with a UDP socket in the first place, and if you feel you must, you should just connect the original socket, once you have received some data.
In any case, it's really the client side of things that you need to worry about. You have already set up the router to forward datagrams inbound for the server, so the server should always be able to receive on that port. It's the return traffic to the client that is in question; the fact is, not all routers support this scenario, and always require port forwarding for UDP traffic (TCP traffic is easier because there is an on-going connection the router can maintain with the client).
I recommend that you make the server simpler – just create a single socket used to receive datagrams (and so of course don't dispose it with using). I'd also advise not using Connect() as all that will do is unnecessarily restrict the server. I.e. it will prevent the server's socket from being able to handle more than one client. If you really want to do some per-client filtering, a better mechanism is for the server to always receive all datagrams, and then check the receive-from address itself to decide how to deal with the datagram.
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 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...
I am trying to get some simple UDP communication working on my local network.
All i want to do is do a multicast to all machines on the network
Here is my sending code
public void SendMessage(string message)
{
var data = Encoding.Default.GetBytes(message);
using (var udpClient = new UdpClient(AddressFamily.InterNetwork))
{
var address = IPAddress.Parse("224.100.0.1");
var ipEndPoint = new IPEndPoint(address, 8088);
udpClient.JoinMulticastGroup(address);
udpClient.Send(data, data.Length, ipEndPoint);
udpClient.Close();
}
}
and here is my receiving code
public void Start()
{
udpClient = new UdpClient(8088);
udpClient.JoinMulticastGroup(IPAddress.Parse("224.100.0.1"), 50);
receiveThread = new Thread(Receive);
receiveThread.Start();
}
public void Receive()
{
while (true)
{
var ipEndPoint = new IPEndPoint(IPAddress.Any, 0);
var data = udpClient.Receive(ref ipEndPoint);
Message = Encoding.Default.GetString(data);
// Raise the AfterReceive event
if (AfterReceive != null)
{
AfterReceive(this, new EventArgs());
}
}
}
It works perfectly on my local machine but not across the network.
-Does not seem to be the firewall. I disabled it on both machines and it still did not work.
-It works if i do a direct send to the hard coded IP address of the client machine (ie not multicast).
Any help would be appreciated.
Does your local network hardware support IGMP?
It's possible that your switch is multicast aware, but if IGMP is disabled it won't notice if any attached hardware subscribes to a particular multicast group so it wouldn't forward those packets.
To test this, temporarily connect two machines directly together with a cross-over cable. That should (AFAICR) always work.
Also, it should be the server half of the code that has the TTL argument supplied to JoinMulticastGroup(), not the client half.
I've just spent 4 hours on something similar (I think), the solution for me was:
client.Client.Bind(new IPEndPoint(IPAddress.Any, SSDP_PORT));
client.JoinMulticastGroup(SSDP_IP,IP.ExternalIPAddresses.First());
client.MulticastLoopback = true;
Using a specific (first external) IP address on the multicast group.
I can't see a TTL specified anywhere in the code. Remember that TTL was originally meant to be in unit seconds, but is has become unit hops. This means that by using a clever TTL you could eliminate passing through the router. The default TTL on my machine is 32 - I think that should be more than adequate; but yours may actually be different (UdpClient.Ttl) if your system has been through any form of a security lockdown.
I can't recommend the TTL you need - as I personally need to do a lot of experimentation.
If that doesn't work, you could have a look at these articles:
OSIX Article
CodeProject Article
All-in-all it looks like there has been success with using Sockets and not UdpClients.
Your chosen multicast group could also be local-only. Try another one.
Your physical network layer could also be causing issues. I would venture to question switches and direct (x-over) connections. Hubs and all more intelligent should handle them fine. I don't have any literature to back that, however.