Platform: Windows 2003 R2, C#
I have an application that sends UDP messages to other instances of itself, running on the same computer and on other computers. This is working fine. But, on some computers, the listener cannot hear messages that other thread/process on the same computer has transmitted. The message is broadcast ok, and other machines on the network hear the message, but a listener on the same machine cannot hear the message.
The weird part is that this happens on SOME machines in my test environment, but not all.
Edit: All machine that fail have the Check Point VPN-1 Securemote client software installed. I took a machine that was working, installed the VPN client, and now it does not work. Note that I am not connected to any VPN hosts, I just have the client installed.
All machines have a single network adapter, subnet mask of 255.255.255.0, and IP address of 10.3.10.xxx.
Here is a test class that demonstrates the problem. The user types some text, and it gets sent to 10.3.10.255. On some machines, the ReceiveFrom returns, and on others it does not. I am calling Controller("10.3.10.255",33333)
public class Controller
{
public Controller(IPAddress broadcastAddress, int port)
{
_broadcastAddress = broadcastAddress;
_port = port;
}
public void Start()
{
Socket s = null;
try
{
IPEndPoint _listenEndpoint = new IPEndPoint(IPAddress.Any, _port);
_broadcastEndpoint = new IPEndPoint(_broadcastAddress, _port);
s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 10);
s.EnableBroadcast = true;
s.Bind(_listenEndpoint);
SocketState receiveState = new SocketState();
receiveState.s = s;
receiveState.buf = new byte[1024];
EndPoint lep = (EndPoint)_broadcastEndpoint;
s.BeginReceiveFrom(receiveState.buf, 0, receiveState.buf.Length, SocketFlags.None, ref lep, new AsyncCallback(OnReceive), receiveState);
bool done = false;
while (!done)
{
string msg = Console.In.ReadLine();
byte[] msg_bytes = Encoding.ASCII.GetBytes(msg);
if (msg_bytes.Length == 0)
done = true;
else
{
Console.Out.WriteLine("---> {0}", msg);
s.SendTo(msg_bytes, msg_bytes.Length, SocketFlags.None, new IPEndPoint(_broadcastAddress, _port));
}
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
if (s != null)
s.Close();
}
}
internal void OnReceive(IAsyncResult ar)
{
SocketState state = ar.AsyncState as SocketState;
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, 0);
EndPoint ep = (EndPoint)ipep;
int nRead = state.s.EndReceiveFrom(ar, ref ep);
IPEndPoint myipep = ep as IPEndPoint;
Console.WriteLine("<--- {0} {1}", myipep.Address.ToString(), System.Text.Encoding.ASCII.GetString(state.buf, 0, nRead));
EndPoint lep = (EndPoint)_broadcastEndpoint;
state.s.BeginReceiveFrom(state.buf, 0, state.buf.Length, SocketFlags.None, ref lep, new AsyncCallback(OnReceive), state);
}
IPAddress _broadcastAddress;
int _port = 0;
IPEndPoint _broadcastEndpoint;
}
internal class SocketState
{
internal Socket s;
internal byte[] buf;
}
What does the Check Point VPN-1 Securemote client software do? It sounds like it might do some sort of firewalling in which case it would be blocking data coming in on the specified port.
1) If you can configure it to allow data through that port, then you should be good to go.
2) Another less likely option is that maybe it is listening on the port that you are trying to listen to in which case it is receiving the udp packet as opposed to your application. I would expect you app to throw an error though in that case.
In the SecureClient settings (right click on the tray icon and select Settings), on the Security tab you can enable an option to "log all connections that are blocked by the desktop security policy".
You should then be able to see if that's indeed what is blocking your application - if it is, you'll have to get the default policy changed to allow your application. I'm not sure how to do that - I've never administered the server side of SecureRemote, but I'm sure Check Point can help you out if your network admins can't.
Related
I am having trouble with my c# tcp code.
When I run the server and the client on the same computer, it will connect just fine.
But when I run the client on a different PC or on a phone, I get: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
Here is the server code:
private static void CreateServer()
{
TcpListener server = null;
try
{
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection... ");
/*
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
var ipAddress = ipHostInfo.AddressList;
Console.WriteLine(ipHostInfo.HostName);
Console.WriteLine(ipAddress[0]);
*/
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
try
{
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
}
}
catch(IOException e)
{
//Console.WriteLine(e);
Console.WriteLine("Restarting Server");
//client.Close();
//CreateServer();
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
//Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
I removed most of the comments. But that is the basic example for a tcp server from the documentation.
the client connect code is very simple:
tcpClient = new TcpClient();
tcpClient.Connect("192.168.0.7", 13000);
with the declaration for tcpClient saved in a less local spot for retaining and quickly reconnecting.
What I have tried:
I have made sure the IP address is correct, I even port forwarded and used my external IP, but got the same issue.
I made sure the firewall is not blocking the app on either device.
I tried using either device as the server.
I've looked up the problem and the only other person to have this issue needed to make sure he put in the correct IP and fix his firewall settings. I'm probably missing something super obvious.
One final piece of information, one device is wired to the router, I don't know if that is messing with anything.
One other thing, I tried:
tcpClient.Connect(new IPEndPoint(IPAddress.Parse("192.168.0.7"), 13000));
as well.
Whelp I was right. It was something very obvious and honestly dumb on my part.
on the server side:
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
does not result in the server listening on its ipv4, instead it listens on an ipv6
so what you want:
Remove the localAddr declaration, as it is not important, and instead of calling:
server = new TcpListener(localAddr, port);
call:
server = new TcpListener(IPAddress.Any, port);
IPAddress.Any is used to listen across all of the network interfaces the device has.
I'm trying to implement Hole punching using C# but unfortunately I spent hours to figure out why it doesn't work for me. Here is my problem:
I have a third part server that I can manage all external IPs for the peers on, and of course my router is behind a NAT, and I assume all my peers are also behind NATs.
Say if I managed to figure out all slaves (peers), End points (external ips). Where to put the external ip address of my server which runs on my pc (not the third party one), and where to put the peer ip address?
This is my code:
public void HolePunch(String ServerIp, Int32 Port) // if I put my external ip here I get Exception (An address incompatible with the requested protocol was used)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
// This Part Sends your local endpoint to the server so if the two peers are on the same nat they can bypass it, you can omit this if you wish to just use the remote endpoint.
byte[] IPBuffer = System.Text.Encoding.UTF8.GetBytes(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0].ToString());
byte[] LengthBuffer = BitConverter.GetBytes(IPBuffer.Length);
byte[] PortBuffer = BitConverter.GetBytes(Port);
byte[] Buffer = new byte[IPBuffer.Length + LengthBuffer.Length + PortBuffer.Length];
LengthBuffer.CopyTo(Buffer,0);
IPBuffer.CopyTo(Buffer, LengthBuffer.Length);
PortBuffer.CopyTo(Buffer, IPBuffer.Length + LengthBuffer.Length);
Client.BeginSend(Buffer, Buffer.Length, RemotePt, new AsyncCallback(SendCallback), Client);
// Wait to receve something
BeginReceive(Client, Port);
// you may want to use a auto or manual ResetEvent here and have the server send back a confirmation, the server should have now stored your local (you sent it) and remote endpoint.
// you now need to work out who you need to connect to then ask the server for there remote and local end point then need to try to connect to the local first then the remote.
// if the server knows who you need to connect to you could just have it send you the endpoints as the confirmation.
// you may also need to keep this open with a keepalive packet untill it is time to connect to the peer or peers.
// once you have the endpoints of the peer you can close this connection unless you need to keep asking the server for other endpoints
Client.Close();
}
public void ConnectToPeer(String PeerIp, Int32 Port)
{
IPEndPoint LocalPt = new IPEndPoint(Dns.GetHostEntry(Dns.GetHostName()).AddressList[0], Port);
UdpClient Client = new UdpClient();
Client.ExclusiveAddressUse = false;
Client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
Client.Client.Bind(LocalPt);
IPEndPoint RemotePt = new IPEndPoint(IPAddress.Parse(PeerIp), Port);
Client.Connect(RemotePt);
//you may want to keep the peer client connections in a list.
BeginReceive(Client, Port);
}
public void SendCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)ar.AsyncState;
Client.EndSend(ar);
}
public void BeginReceive(UdpClient Client, Int32 Port)
{
IPEndPoint ListenPt = new IPEndPoint(IPAddress.Any, Port);
Object[] State = new Object[] { Client, ListenPt };
Client.BeginReceive(new AsyncCallback(ReceiveCallback), State);
}
public void ReceiveCallback(IAsyncResult ar)
{
UdpClient Client = (UdpClient)((Object[])ar.AsyncState)[0];
IPEndPoint ListenPt = (IPEndPoint)((Object[])ar.AsyncState)[0];
Byte[] receiveBytes = Client.EndReceive(ar, ref ListenPt);
}
EDIT :
the code works will if I give it my local ip and if my clients in my pc .. but if I supply it an external ip it doesn't work ( the exception in the first line comment )
I've made a simple chat application in c#.net that sends and receives data between 2 computers.
So, I used this method to send the data:
int port = 11000;
private void send(string data, string ip)
{
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint sending_end_point = null;
byte[] send_buffer = Encoding.ASCII.GetBytes(data);
sending_end_point = new IPEndPoint(IPAddress.Parse(ip), port);
try { sending_socket.SendTo(send_buffer, sending_end_point); }
catch { }
}
And to receive I used this:
string receiveddata = "";
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
UdpClient listener = new UdpClient(port);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);
byte[] receive_byte_array;
try
{
receive_byte_array = listener.Receive(ref groupEP);
receiveddata = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
}
catch { }
listener.Close();
}
This works without any problems between 2 computers on a LAN, but I would like to know (if possible) how to do the same thing over the Internet.
From what I've searched on the Internet, it seems that I have to use port-forwarding in order to do that, so I already did that, but I don't know what should I do know.
So my question is, how should I change this code (if I have to) so I could send and receive data (UDP) over the internet, assuming I have port-forwarded correctly already and assuming I know the external IPs of both routers?
Thank you in advance.
This should work just fine, as long as your (public) IP-address is correct and the ports are forwarded correctly on your router (meaning, forwarded to the correct private IP, on the correct protocol, in your case UDP).
You are aware that this is UDP though, so it's not reliable data transfer.
I am using UdpClient class in .net 3.5
I need to bind multiple applications to the same port .
So, if UDP servers broadcast any request - all the applications thats listen on the port can receive the message but the problem is, when I try bind to an application to the same port, only one application receive the message and the other does not.
Below is some sample code for the two application:
UdpClient udpClient = new UdpClient();
Thread thread;
IPEndPoint endPoint = new IPEndPoint(IPAddress.Loopback, 11000);
public Form1()
{
//CheckForIllegalCrossThreadCalls = false;
InitializeComponent();
udpClient.ExclusiveAddressUse = false;
udpClient.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(endPoint);
}
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape)
{
thread.Abort();
udpClient.Close();
Close();
}
}
private void ReceiveMessage()
{
//while (true)
//{
// IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, 11000);
// byte[] content = udpClient.Receive(ref endPoint);
udpClient.BeginReceive(new AsyncCallback(Read_Callback), null);
//if (content.Length > 0)
//{
// string message = Encoding.ASCII.GetString(content);
// this.Invoke(myDelegate, new object[] { message });
//}
// }
}
public void Read_Callback(IAsyncResult ar)
{
try
{
byte[] buffer = udpClient.EndReceive(ar, ref endPoint);
// Process buffer
string s = Encoding.ASCII.GetString(buffer);
// richTextBox1.Text = s;
udpClient.BeginReceive(new AsyncCallback(Read_Callback), null);
}
catch (Exception ex)
{ }
}
PS : I am unable to figure out the reason or am I missing something. ?
That's the nature of sockets. Even in cases (such as UDP) where multiple applications can access the same port, the data is handed out first-come, first-serve. UDP is also designed with minimum overhead, so there isn't even an opportunity to "check the queue," like you (hypothetically) could with TCP.
It's designed around having multiple processes share a server load, alternating who receives the request based on who's idle.
You'd need to build something external to get around this, like a retransmission protocol or a database to make sure every inbound message is shared.
If you can deal with the changes, a smarter way to handle this would be UDP Multicast, where multiple programs essentially enroll to receive group messages. In that case, the single-port restriction can (and should) be abandoned.
I've the following code to read multicast message coming from the network, for a specified IP+Port
private static void ReceiveMessages(int port, string ip, CancellationToken token)
{
Task.Factory.StartNew(() =>
{
using (var mUdpClientReceiver = new UdpClient())
{
var mReceivingEndPoint = new IPEndPoint(IPAddress.Any, port);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.Bind(mReceivingEndPoint);
mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255);
while (!token.IsCancellationRequested)
{
byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint);
Console.WriteLine("Message received from {0} ",mReceivingEndPoint);
}
}
});
}
I've two network adapter from which I've data coming on this multicast ip+port(confirmed by two instances of wireshark monitoring each network adapter). I see on wireshark a lot of traffic coming on those port+Ip) for both network cards.
The problem is that on my console, I only see messages coming from one network card.
I double checked with netstat, I don't have any other software listening on my port:
So why am I getting traffic from only one of my two network cards?
EDIT:
I even tried the following:
private static void ReceiveMessages(int port, string ip, CancellationToken token, IEnumerable<IPAddress> ipAddresses)
{
foreach (IPAddress ipAddress in ipAddresses)
{
IPAddress ipToUse = ipAddress;
Task.Factory.StartNew(() =>
{
using (var mUdpClientReceiver = new UdpClient())
{
var mReceivingEndPoint = new IPEndPoint(ipToUse, port);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
mUdpClientReceiver.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontRoute, 1);
mUdpClientReceiver.ExclusiveAddressUse = false;
mUdpClientReceiver.Client.Bind(mReceivingEndPoint);
mUdpClientReceiver.JoinMulticastGroup(IPAddress.Parse(ip), 255);
Console.WriteLine("Starting to listen on "+ipToUse);
while (!token.IsCancellationRequested)
{
byte[] receive = mUdpClientReceiver.Receive(ref mReceivingEndPoint);
Console.WriteLine("Message received from {0} on {1}", mReceivingEndPoint,ipToUse);
}
}
});
}
}
I see the "Starting to listen on theCorrectIP" twice(for my two IPs), but it still display only data coming from one network card.
EDIT 2
I did notice something else that is strange too. If I disable the interface on which I receive all data, and then start the software, I now get data from the other interface. If I activate again the interface and restart the software, I still get the traffic on the non-deactivated card.
And I know for sure that I've devices that respond to me, that are connected only to one network(not both)
EDIT 3
Another thing: if I send a message from me(localhost), on all network card that I've, I see them coming on my two network interfaces. BUT, if I start my program twice, only the first programm get messages, not the second one.
Edit 4
Additional info, following the first comment:
I've two ethernet cards, one with the 10.10.24.78 ip, the other with the 10.9.10.234 ip.
It's not me that send data, but network pieces(the port 5353 with this ip is a know multicast address used for mDNS, so I should receive traffic from things like printer, itunes, macs, and some other pieces of software we created). Data are multicasted on the ip
224.0.0.251 and port 5353.
Here is a code that you could use to send data on severals IPs, but like I described, if you start it in local it almost works(except that only one local client receive the message).
private static void SendManuallyOnAllCards(int port, string multicastAddress, IEnumerable<IPAddress> ipAddresses)
{
foreach (IPAddress remoteAddress in ipAddresses)
{
IPAddress ipToUse = remoteAddress;
using (var mSendSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp))
{
mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership,
new MulticastOption(IPAddress.Parse(multicastAddress)));
mSendSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastTimeToLive, 255);
mSendSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
var ipep = new IPEndPoint(ipToUse, port);
//IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(multicastAddress), port);
mSendSocket.Bind(ipep);
mSendSocket.Connect(ipep);
byte[] bytes = Encoding.ASCII.GetBytes("This is my welcome message");
mSendSocket.Send(bytes, bytes.Length, SocketFlags.None);
}
}
}
EDIT 5
Here is the result of my route print(Didn't know that command), and on my two IPs, I always receive data on the 10.9.10.234
Edit 6
I tried several other things:
Use a socket to receive instead of the UdpClient --> Didn't worked
Set some addition socketOption on the reader(DontRoute =1, Broadcast=1) -->Didn't worked
Specify the MulticastInterface that the reader Socket has to use(using socketOption MulticastInterface) --> Didn't work
I had the same problem that I wanted to receive multicasts from all my network interfaces. As EJP already said, you need to call JoinMulticastGroup(IPAddress multicastAddr, IPAddress localAddress) on the UdpClient for all network interfaces:
int port = 1036;
IPAddress multicastAddress = IPAddress.Parse("239.192.1.12");
client = new UdpClient(new IPEndPoint(IPAddress.Any, port));
// list of UdpClients to send multicasts
List<UdpClient> sendClients = new List<UdpClient>();
// join multicast group on all available network interfaces
NetworkInterface[] networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface networkInterface in networkInterfaces)
{
if ((!networkInterface.Supports(NetworkInterfaceComponent.IPv4)) ||
(networkInterface.OperationalStatus != OperationalStatus.Up))
{
continue;
}
IPInterfaceProperties adapterProperties = networkInterface.GetIPProperties();
UnicastIPAddressInformationCollection unicastIPAddresses = adapterProperties.UnicastAddresses;
IPAddress ipAddress = null;
foreach (UnicastIPAddressInformation unicastIPAddress in unicastIPAddresses)
{
if (unicastIPAddress.Address.AddressFamily != AddressFamily.InterNetwork)
{
continue;
}
ipAddress = unicastIPAddress.Address;
break;
}
if (ipAddress == null)
{
continue;
}
client.JoinMulticastGroup(multicastAddress, ipAddress);
UdpClient sendClient = new UdpClient(new IPEndPoint(ipAddress, port));
sendClients.Add(sendClient);
}
I am also creating a list of UdpClients so I can send my multicasts on all network interfaces.
I finally found how to do it!
In fact, if I keep exactly the same code, but using it with async methods, it work!!! I just can't understand why it doesn't work with sync method(if someone knows, you're welcome to tell me :) )
Since I've lost 3 days on this, I think it worth an example:
private static void ReceiveAsync(int port, string address, IEnumerable<IPAddress> localAddresses)
{
IPAddress multicastAddress = IPAddress.Parse(address);
foreach (IPAddress localAddress in localAddresses)
{
var udpClient = new UdpClient(AddressFamily.InterNetwork);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(new IPEndPoint(localAddress, port));
udpClient.JoinMulticastGroup(multicastAddress, localAddress);
udpClient.BeginReceive(OnReceiveSink,
new object[]
{
udpClient, new IPEndPoint(localAddress, ((IPEndPoint) udpClient.Client.LocalEndPoint).Port)
});
}
}
And the async method:
private static void OnReceiveSink(IAsyncResult result)
{
IPEndPoint ep = null;
var args = (object[]) result.AsyncState;
var session = (UdpClient) args[0];
var local = (IPEndPoint) args[1];
byte[] buffer = session.EndReceive(result, ref ep);
//Do what you want here with the data of the buffer
Console.WriteLine("Message received from " + ep + " to " + local);
//We make the next call to the begin receive
session.BeginReceive(OnReceiveSink, args);
}
I hope that helps ;)
You need to join the multicast group via all available interfaces. By default, the outgoing IGMP JOIN message will be routed according to the unicast routing tables, which will send it out via the 'cheapest' route, using whichever NIC accesses that route. If your multicast group can be sourced via more than one of those routes, you need to iterate.