I connected to PCs with a cable in an attempt to simulate server\client. Server starts listening at specific EndPoint and sometimes later a client connects. All went well and I settled on maximum speed of about 24 Mbps for one connection (port).
So now I reversed the roles and can't get connection Socket.BeginConnect(ServerEndPoint, new AsyncCallback(OnConnectCallback), _ClientSocket) times out and sets localEndpoint to 0.0.0.0
Here is the code for client:
public void ConnectToServer(IPAddress iPAddress, int Port)
{
connected.Reset();
IPEndPoint ServerEndPoint = new IPEndPoint(iPAddress, Port);
try
{
_ClientSocket = new Socket(iPAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_ClientSocket.BeginConnect(ServerEndPoint, new AsyncCallback(OnConnectCallback), _ClientSocket);
connected.WaitOne();
// Here I would like to start async receiving but there's no connection
}
catch (SocketException)
{
// TODO:
}
}
private void OnConnectCallback(IAsyncResult result)
{
try
{
Socket client_StateSocket = (Socket)result.AsyncState;
client_StateSocket.EndConnect(result);
/// Here I get 0.0.0.0
connected.Set();
}
catch (SocketException)
{
// TODO:
}
}
The server is bascialy from MSDN example. It starts listening for incoming connections, goes in perpetual while cycle and sits waiting for Socket.BeginAccept to trigger (but it never does).
I suspected firewall, but the settings look the same on both PCs and works fine in reversed way, so what might be the problem?
When you do development of a Server/Client architecture, it is usually enough to have both run on the same machine and let them talk via the Loopback IP adress. As a general rule the networking code does not care if the other end is on the same computer, the same switch - or the Voyager 2 probe (well, they do care a little as the Latency is quite high).
If you are having issues in deployment/testing, then with 99% propability you are dealing with a Networking problem, not a programming one. Sometimes there will be some required changes (like exposing the option to set proxy settings). But debugging will be a Networking operation first.
My first guesses are towards firewalls (including the one built into Windows). And then things that work similar to a firewall, like NAT layers.
Related
I'm debugging a strange problem, happening on one of the machines in the live environment.
My app (slave) is supposed to be receiving UDP multicast messages at any time from another host (master) in the LAN, but apparently it does so only if the slave has previously sent a message.
What I expected is:
Slave asks for data
Master sends the data
Slave receives and consumes
Master waits 2-3 minutes
Master sends new data
Slave receives and consumes the new data
Steps from 4 to 6 are repeated
What I see is:
Slave doesn't receive anything
BUT if I make the slave asks for new data continuously (polling, i.e. repeat step 1) I finally get the message.
I see in Wireshark that the message from the master is indeed received by the slave host. Just my app is not receiving it. What is more surprising, is that another master-slave pair running on the same network, with the same apps, is working fine, as well as my pair in the test environment.
The slave app uses UdpClient in asynchronous mode. Here is how the listener is initialized:
private void ListenMain()
{
try
{
UdpClient udpClient = new UdpClient();
udpClient.Client.ExclusiveAddressUse = false;
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, 1000);
IPv4InterfaceProperties p = adapter.GetIPProperties().GetIPv4Properties();
udpClient.Client.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastInterface, (int)IPAddress.HostToNetworkOrder(p.Index));
udpClient.Client.Bind(endPoint);
udpClient.JoinMulticastGroup(12345);
ListenState listenState = new ListenState();
listenState.udpClient = udpClient;
listenStates.Add(listenState);
logger.Debug("Waiting for messages");
udpClient.BeginReceive(new AsyncCallback(OnPacketReceived), listenState);
}
catch (Exception e)
{
logger.Error(e, "ListenMain() encountered an error");
}
}
And here is the handler of a received packet:
private void OnPacketReceived(IAsyncResult result)
{
logger.Trace("OnPacketReceived");
IPEndPoint recvAddress = new IPEndPoint(IPAddress.Any, MULTICAST_PORT);
ListenState state = result.AsyncState as ListenState;
byte[] receive_byte_array;
try
{
logger.Trace("before EndReceive");
receive_byte_array = state.udpClient.EndReceive(result, ref recvAddress);
logger.Trace("after EndReceive, got {0} bytes", receive_byte_array.Length);
// packet handling goes here...
// do the loop
logger.Trace("waiting for another packet");
state.udpClient.BeginReceive(new AsyncCallback(OnPacketReceived), state);
}
catch (ObjectDisposedException)
{
logger.Info("Socket is now closed");
return;
}
catch (Exception e)
{
logger.Warn(e, "exception in handling incoming message");
}
}
Of course, polling for new data is not an optimal solution and introduces unwanted delays. I'd like to know which phenomenon makes UdpClient lose incoming packets unless the same UdpClient has sent something before.
I think there is an error in the code: udpClient.JoinMulticastGroup(); takes the multicast IP address as argument, not the port. Does it work when you fix this? If so, this explains it:
Not joining a multicast group leads to the typical "multicast group not joined" erratic behavior, which includes the favorite "it works for two to five minutes and then suddenly stops" and "it works when I send something in the other direction and then suddenly stops" and "it works when using a different multicast address and then stops, leaving unusable multicast addresses behind".
The behaviour you see is typical for IPv4 multicast with more or less intelligent routers and switches. They all support some version of IGMP snooping (with timeouts, bugs and incompatible versions), and routers, switches and OSes cache network paths and MACs and registered and unregistered multicast IPs for an undefined amount of time. This makes it impossible to reason about the behaviour in a logical way.
Check whether you joined the expected multicast group on the receiver/listener. When this looks ok and you still have problems, trace IGMP messages and look for anything which does not make sense, like never seeing a join, or seeing erratic leaves.
(Note that IGMP messages are sent by the OS on a machine level, and not by your application. This means that not every JoinMulticastGroup() will generate an IGMP join message.)
I want to learn about socket communication so I decided to try to write WP 8.1 text communicator. It is based on TCP sockets. I almost managed to finish it, but I am searching for improvemenets.
What is worth mentioning I use a socket server between phones (console application), to avoid problems with private ip addresses. It contains information about all connected users and forwards messages to clients (for instance user A sends message to user B, so firstly message goes to server and server forward it to destination address).
The problem appeared when i realized that I need to send special messages from server to client and vice versa (for example when two clients want to have conversation, they send request to server, so it knows where to forward messages).
This is my connection listener method from server application
private void ConnectionListener()
{
IPEndPoint localDataEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 1234);
IPEndPoint localMessageEndPoint = new IPEndPoint(IPAddress.Parse(LocalIpAddress), 4321);
Socket dataConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket messageConnectionListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
dataConnectionListener.Bind(localDataEndPoint);
dataConnectionListener.Listen(100);
messageConnectionListener.Bind(localMessageEndPoint);
messageConnectionListener.Listen(100);
while (true)
{
TcpSocket.clientDone.Reset();
IAsyncResult tmp1 = dataConnectionListener.BeginAccept(ConnectionCallback, null);
IAsyncResult tmp2 = messageConnectionListener.BeginAccept(ConnectionCallback, null);
TcpSocket.clientDone.WaitOne();
Socket dataSocket = dataConnectionListener.EndAccept(tmp1);
Socket messageSocket = messageConnectionListener.EndAccept(tmp2);
TcpSocket tmpTcpSocket = new TcpSocket(dataSocket, messageSocket);
tmpTcpSocket.Start();
connectedUsersSockets.Add(tmpTcpSocket);
UpdateConnectedUserList();
}
}
catch (Exception ex)
{
Log.E("Connection listener ran into an exception", ex);
}
}
As you can see I have created two TCP sockets to liesten on different ports. dataSocket is for normal messages and messageSocket is for special messages (sorry for confusing names, I have to refractor code).
On client side it works the same way: there are two different socket to communicate with and through the server.
I wanted to avoid managing two sockets rather then one. But the only way I can imagine is that on every received message server would have to check if it's special (and handle it in special way) or just send to client.
The question: Is there a better way to manage these special messages?
Thanks to all in advance!
P.S.
Sorry for my poor english, it's not my native language
I'm using UdpClient to broadcast my program location so a centralize computer can find it and start working with it.
It works great, until 2 users on the same computer at the same time try to broadcast. Since this is a valid use case (think Windows Terminal Server), I'm trying to figure out the best way to address it:
Here is the code I'm currently trying:
m_UDPClients = new List<UdpClient>();
IPAddress[] localIPs = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ip in localIPs)
{
string ipStr = ip.ToString();
if (!ipStr.Contains(".")) // I only want readable addresses
continue;
IPEndPoint ipLocalEndPoint = new IPEndPoint(ip, port);
try
{
UdpClient udpClient = new UdpClient();
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(ipLocalEndPoint);
m_UDPClients.Add(udpClient);
}
catch (Exception e)
{
BSSLog.Error(e);
}
}
if there is another instance of the program running already, the bind will throw this exception:
An attempt was made to access a socket in a way forbidden by its access permissions
This broadcast is just the program 'advertising' some details about how to connect to it's services; The broadcast happens every few seconds and it's payload is probably < 1k.
I did try to create and destroy the UDPclients as needed and just accept the collision, but it was ugly.
So...the question is: How do I handle 30 instances of the same program all attempting to advertise themselves via the same UDP port (no listening, just post the payload and move on) on a single computer?
I know I could build a Windows service and play traffic cop, etc... but I'm trying to keep this simple and 'limited user rights' friendly.
Before I run off and attempt to use a predefined system wide named pipe or something, I thought I was ask for help. :)
There isn't anything wrong with the code. In our test environment we had a monitoring program that wasn't opening the port correctly.
Good thing we wasted 2 days chasing a red herring.
thank you everyone.
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.
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.