Alright, so I'm trying to connect to UDP trackers using c#, but I never get a response. I also don't get any errors. Here's my code.
namespace UDPTester
{
class MainClass
{
public static bool messageReceived = false;
public static Random Random = new Random();
public static void LOG(string format, params object[] args)
{
Console.WriteLine (format,args);
}
public static void Main (string[] args)
{
LOG ("Creating Packet...");
byte[] packet;
using(var stream = new MemoryStream())
{
var bc = new MiscUtil.Conversion.BigEndianBitConverter();
using(var br = new MiscUtil.IO.EndianBinaryWriter(bc,stream))
{
LOG ("Magic Num: {0}",(Int64)0x41727101980);
br.Write (0x41727101980);
br.Write((Int32)0);
br.Write ((Int32)Random.Next());
packet = stream.ToArray();
LOG ("Packet Size: {0}",packet.Length);
}
}
LOG ("Connecting to tracker...");
var client = new System.Net.Sockets.UdpClient("tracker.openbittorrent.com",80);
UdpState s = new UdpState();
s.e = client.Client.RemoteEndPoint;
s.u = client;
StartReceiving(s);
LOG ("Sending Packet...");
client.Send(packet,packet.Length);
while(!messageReceived)
{
Thread.Sleep(1000);
}
LOG ("Ended");
}
public static void StartReceiving(UdpState state)
{
state.u.BeginReceive(ReceiveCallback,state);
}
public static void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
Byte[] receiveBytes = u.EndReceive(ar, ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
LOG("Received: {0}", receiveString);
messageReceived = true;
StartReceiving((UdpState)ar.AsyncState);
}
}
public class UdpState
{
public UdpClient u;
public EndPoint e;
}
}
I was using a normal BinaryWriter, but that didn't work, and I read somewhere that it wants it's data in BigEndian.
This doesn't work for any of the UDP trackers I've found, any ideas why I'm not getting a response? Did they maybe change the protocol and not tell anyone? HTTP trackers all work fine.
Trackers I've tried
udp://tracker.publicbt.com:80
udp://tracker.ccc.de:80
udp://tracker.istole.it:80
Also, I'm not interested in using MonoTorrent(and when I was using it, the UDP didn't work anyways).
Protocol Sources
http://xbtt.sourceforge.net/udp_tracker_protocol.html
http://www.rasterbar.com/products/libtorrent/udp_tracker_protocol.html
UDP is a connectionless protocol, so you won't see any errors if packets are lost or dropped at the destination.
Try following diagnostic steps:
Use packet sniffer (Wireshark is a good one) to check that UDP packets are leaving the machine.
Install some working BitTorrent client, check if it can communicate with the tracker and if yes, use packet sniffer to see how the packets sent by the working client differ from the packets your code generates.
If working client also can not communicate with the tracker, but the UDP traffic is leaving your machine, the UDP packets are likely dropped by a firewall. You can try 'traceroute' tool to diagnose where your packets are dropped (this is not always 100% reliable, because sometimes firewalls drop UDP packets generated by traceroute and do not drop normal UDP traffic).
Related
I need to send a UDP broadcast from a RaspberryPi 3 running Windows 10 IoT Core. My code so far:
internal class UdpInterface : IDisposable
{
private UdpClient udpClient;
internal UdpInterface(int localPort)
{
udpClient = new UdpClient(localPort);
udpClient.EnableBroadcast = true;
}
internal void BroadcastMessage(string message, int targetPort)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, targetPort);
byte[] bytes = Encoding.ASCII.GetBytes(message);
udpClient.Send(bytes, bytes.Length, ip);
}
public void Dispose()
{
udpClient.Close();
udpClient.Dispose();
}
}
I call it like this from a GPIO pin ValueChanged event:
_udp.BroadcastMessage("Video" + PinMapper(sender.PinNumber), _port);
I tried setting the Internet (Client & Server) capability in package.appxmanifest, and I tried using the DatagramSocket class before.
Do I need some other permissions/capabilities or is something wrong with my code? It did work when sending to target IPs before.
I'm verifying the packet with PacketSender on my dev machine.
I would like every client to 'be aware of' every other client that has connected within the UDP network at request.
So far I have a very simple program where every client inputs a username and sends it to the network. Every client stores a list of usernames to keep track of who has communicated with the network at least once. If a new username pops in, it outputs it to the console and stores it in the list as to prevent from outputting it again.
This is all fine and dandy but I've only managed the above by having every client continuously awaiting new data from the network (because it can never know when new clients will stop 'entering' the network).
Here's all the code. The part of interest is probably the displayAllUsers() function.
I've pasted the whole program because it is (i) very short (ii) my knowledge of UDP within C# is very green, and my practices are in no way good, so maybe it is a good idea to have readers be aware of that.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Node
{
class Program
{
static UdpClient client = new UdpClient();
static IPEndPoint localIP;
static IPEndPoint remoteIP;
static String currentUser;
static List<String> currentUsers = new List<String>();
static void Main(string[] args)
{
initialiseListener();
initialiseWriter();
Console.WriteLine("What's your username?");
currentUser = Console.ReadLine();
Byte[] buffer = Encoding.Unicode.GetBytes(currentUser);
//Who is current user?
client.Send(buffer, buffer.Length, remoteIP);
Console.WriteLine("Here are all active users:");
displayAllUsers();
}
private static void displayAllUsers()
{
Byte[] buffer;
while (true)
{
Byte[] data = client.Receive(ref localIP); //blocking call - continuously listening
string strData = Encoding.Unicode.GetString(data);
if (!currentUsers.Contains(strData)) //if data is not found in current users list...
{
Console.WriteLine(strData); //write username on screen
currentUsers.Add(strData); //and add to current users list
buffer = Encoding.Unicode.GetBytes(currentUser); //Convert currentUser to bytes
client.Send(buffer, buffer.Length, remoteIP); //and send new current user to everyone else
}
}
}
private static void initialiseWriter()
{
IPAddress multicastAddress = IPAddress.Parse("239.0.0.222");
client.JoinMulticastGroup(multicastAddress);
//Send data to this multicast address group
remoteIP = new IPEndPoint(multicastAddress, 2222); //To write to the multicastAddress group on port 2222
}
private static void initialiseListener()
{
client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.ExclusiveAddressUse = false;
//More than one client can use the port to be specified
localIP = new IPEndPoint(IPAddress.Any, 2222); //To listen on any IP Address available from the port 2222
client.Client.Bind(localIP); //Associate client with listener
}
}
}
Ideally, each client would be able to request the displayAllUsers() device whenever and have such list generated for them, rather than constantly awaiting new clients to join in.
Eventually I'd like to implement my knowledge of UDP and non-centralized networking to an Xamarin app and have every device be aware of every other device that has such app open.
I have found a solution from here and modified the below in my displayAllUsers() method.
if(client.Available > 0){
data = client.Receive(ref localIP); //blocking call - continuously listening
}else{
break;
}
Using the .Available property proved to be very useful as it checks if there is something to listen to -- just what I needed.
I will mark this as the thread's answer if it is found to be good practice.
I've made a server and a client. The client should re-attempt to connect to the server if I close the server. I've made it so when the try/catch during waitForCommands fails, it restarts the attemptConnection method in a new thread. The problem I have here is that it simply won't reconnect. As a test, I open my TCP server and the TCP client. The client connects to the server as usual. Then, I close the TCP Server, and the clients spits out this error: 'System.Net.Sockets.SocketException' rapidly, and never connects.
class Program
{
public static TcpClient client = new TcpClient();
public static NetworkStream stream;
public static byte[] readBuffer;
static void Main(string[] args)
{
new Thread(attemptConnection).Start();
}
public static void waitForCommands()
{
while (client.Connected)
{
try
{
readBuffer = new byte[client.ReceiveBufferSize];
int data = stream.Read(readBuffer, 0, readBuffer.Length);
string plainText = Encoding.ASCII.GetString(readBuffer, 0, data);
if (plainText.Contains("mbox"))
{
MessageBox.Show("");
}
}
catch
{
new Thread(attemptConnection).Start();
}
}
}
public static void attemptConnection()
{
while(!client.Connected)
{
try
{
client.Connect("127.0.0.1", 23154);
stream = client.GetStream();
new Thread(waitForCommands).Start();
}
catch(Exception ex)
{
Console.WriteLine(ex.Data);
}
}
}
}
An interesting thing I noticed, is that if I write 'client.Close();' on the server exit event, I get no error messages when the client tries to reconnect. It just shows a blank screen and does nothing
If you'd like to see the code that waits for connections on my server, it's really simple so I'm not sure why this problem is occuring.
public static void waitForConnection()
{
server.Start();
client = server.AcceptTcpClient();
stream = client.GetStream();
f.labelControl1.Text = "Connected";
}
To expand on my comment, I think it's due to the underlying TCP connection (the network stream) not closing automatically.
Try closing the stream manually and see what it does:
client.GetStream().Close();
You could also just close the client which closes the stream for you (see https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.close.aspx):
client.Close();
And another way to resolve your issue (see https://stackoverflow.com/a/38006848/4408417):
client.Client.Disconnect(true);
I changed client.Connect() to
client = new TcpClient();
client.Connect("127.0.0.1", 23154);
As Jasper recommended in the comments
I have built a peer to peer C# video conferencing application that uses a specific TCP port(17500) for audio communication. Currently, on my application interface, I enter the other IP address which has the program opened in order to communicate. What I want to do is to find the IP addresses automatically.
So, I though the best way to achieve this is to obtain the local IP addresses that are using the same TCP port number, 17500. How can I do that ? or is there any other methods getting IP addresses using the same application ?
As mentioned in comments, you need some kind of peer-discovery protocol.
As many multimedia devices, routers etc. use multicast based discovery protocols like SSDP, I created a similar discovery service sample .
Usage is simple. Just use
Discoverer.PeerJoined = ip => Console.WriteLine("JOINED:" + ip);
Discoverer.PeerLeft= ip => Console.WriteLine("LEFT:" + ip);
Discoverer.Start();
All your clients will use the same code.
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.Caching; // add this library from the reference tab
using System.Text;
using System.Threading.Tasks;
namespace SO
{
public class Discoverer
{
static string MULTICAST_IP = "238.212.223.50"; //Random between 224.X.X.X - 239.X.X.X
static int MULTICAST_PORT = 2015; //Random
static UdpClient _UdpClient;
static MemoryCache _Peers = new MemoryCache("_PEERS_");
public static Action<string> PeerJoined = null;
public static Action<string> PeerLeft = null;
public static void Start()
{
_UdpClient = new UdpClient();
_UdpClient.Client.Bind(new IPEndPoint(IPAddress.Any, MULTICAST_PORT));
_UdpClient.JoinMulticastGroup(IPAddress.Parse(MULTICAST_IP));
Task.Run(() => Receiver());
Task.Run(() => Sender());
}
static void Sender()
{
var IamHere = Encoding.UTF8.GetBytes("I AM ALIVE");
IPEndPoint mcastEndPoint = new IPEndPoint(IPAddress.Parse(MULTICAST_IP), MULTICAST_PORT);
while (true)
{
_UdpClient.Send(IamHere, IamHere.Length, mcastEndPoint);
Task.Delay(1000).Wait();
}
}
static void Receiver()
{
var from = new IPEndPoint(0, 0);
while (true)
{
_UdpClient.Receive(ref from);
if (_Peers.Add(new CacheItem(from.Address.ToString(), from),
new CacheItemPolicy() {
SlidingExpiration = TimeSpan.FromSeconds(20),
RemovedCallback = (x) => { if (PeerLeft != null) PeerLeft(x.CacheItem.Key); }
}
)
)
{
if (PeerJoined != null) PeerJoined(from.Address.ToString());
}
Console.WriteLine(from.Address.ToString());
}
}
}
}
Now a little bit about the algorithm:
Every client multicasts a packet every seconds.
if the receiver(every client has it) gets a packet from an IP that isn't in its cache, it will fire PeerJoined method.
Cache will expire in 20 seconds. If a client doesn't receive a packet within that duration from another client in cache, it will fire PeerLeft method.
I believe if you are using a peer to peer application to exchange packets, when you need to know if someone "Is Online and Ready for connection", you need to send a broadcast. We can do it easily using an UDP connection.
I'll post an example where you use two methods: one to ask the entire network for ready clients in a broadcast message, and the other will start a listener to answer back broadcast asking message, or start a connection if a response of type "i am here" comes.
Hope it helps!
public sealed class UdpUtility
{
// Our UDP Port
private const int broadcastPort = 11000;
// Our message to ask if anyone is ready for connection
private const string askMessage = "ARE ANYONE OUT THERE?";
// Our answer message
private const string responseMessage = "I AM HERE!";
// We use this method to look for a client to connect with us.
// It will send a broadcast to the network, asking if any client is ready for connection.
public void SendBroadcastMessage()
{
var udp = new UdpClient(broadcastPort);
var endpoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);
try
{
var bytes = Encoding.ASCII.GetBytes(askMessage);
udp.Send(bytes, bytes.Length, endpoint);
}
catch (Exception ex)
{
// Treat your connection exceptions here!
}
}
// This method will start a listener on the port.
// The client will listen for the ask message and the ready message.
// It can then, answer back with a ready response, or start the TCP connection.
public void ListenBroadcastMessage()
{
var udp = new UdpClient(broadcastPort);
var endpoint = new IPEndPoint(IPAddress.Broadcast, broadcastPort);
bool received = false;
try
{
while (!received)
{
// We start listening broadcast messages on the broadcast IP Address interface.
// When a message comes, the endpoing IP Address will be updated with the sender IP Address.
// Then we can answer back the response telling that we are here, ready for connection.
var bytes = udp.Receive(ref endpoint);
var message = Encoding.ASCII.GetString(bytes);
if (message == askMessage)
{
// Our client received the ask message. We must answer back!
// When the client receives our response, his endpoint will be updated with our IP Address.
// The other client can, then, start the TCP connection and do the desired stuff.
var responseBytes = Encoding.ASCII.GetBytes(responseMessage);
udp.Send(responseBytes, responseBytes.Length, endpoint);
}
else if (message == responseMessage)
{
// We received a connection ready message! We can stop listening.
received = true;
// We received a response message!
// We can start our TCP connection here and do the desired stuff.
// Remember: The other client IP Address (the thing you want) will be on the
// endpoint object at this point. Just use it and start your TCP connection!
}
}
}
catch (Exception ex)
{
// Treat your connection exceptions here!
}
}
}
Invoke your command prompt to do "netstat -n" and extract the output.
Here is a piece of code taken from a program that I have wrote modified to fit your requirements. You will still need to further process the data to get the IP addresses
Process netP = new Process();
ProcessStartInfo netPI = new ProcessStartInfo();
netPI.FileName = "cmd";
netPI.UseShellExecute = false;
netPI.RedirectStandardOutput = true;
netPI.RedirectStandardInput = true;
netPI.RedirectStandardError = true;
netPI.CreateNoWindow = true;
netP.StartInfo = NetPI;
netP.Start();
while (!netP.Start())
Thread.Sleep(100);
StreamWriter sW = netP.StandardInput;
StreamReader sR = netP.StandardOutput;
sW.WriteLine("netstat -n")
sW.Close();
string data = sR.ReadToEnd();
sR.Close();
//Do some further processing to filter out the addresses and extract
I wrote two small applications (a client and a server) to test UDP communication and I found the 'connection' (yeah, I know, there's no real connection) between them gets lost frecuently for no reason.
I know UDP is an unreliable protocol, but the problem here does not seem the losing of packets, but the losing of the communication channel between the apps.
Here's client app code:
class ClientProgram
{
static void Main(string[] args)
{
var localEP = new IPEndPoint(GetIPAddress(), 0);
Socket sck = new UdpClient(localEP).Client;
sck.Connect(new IPEndPoint(IPAddress.Parse("[SERVER_IP_ADDRESS]"), 10005));
Console.WriteLine("Press any key to request a connection to the server.");
Console.ReadLine();
// This signals the server this clients wishes to receive data
SendData(sck);
while (true)
{
ReceiveData(sck);
}
}
private static void ReceiveData(Socket sck)
{
byte[] buff = new byte[8];
int cnt = sck.Receive(buff);
long ticks = BitConverter.ToInt64(buff, 0);
Console.WriteLine(cnt + " bytes received: " + new DateTime(ticks).TimeOfDay.ToString());
}
private static void SendData(Socket sck)
{
// Just some random data
sck.Send(new byte[] { 99, 99, 99, 99 });
}
private static IPAddress GetIPAddress()
{
IPHostEntry he = Dns.GetHostEntry(Dns.GetHostName());
if (he.AddressList.Length == 0)
return null;
return he.AddressList
.Where(ip => ip.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork && !IPAddress.IsLoopback(ip))
.FirstOrDefault();
}
}
Here's the server app code:
class ServerProgram
{
private static int SLEEP = 5;
static void Main(string[] args)
{
// This is a static IP address
var localEP = new IPEndPoint(GetIPAddress(), 10005);
Socket sck = new UdpClient(localEP).Client;
// When this methods returs, a client is ready to receive data
var remoteEP = ReceiveData(sck);
sck.Connect(remoteEP);
while (true)
{
SendData(sck);
System.Threading.Thread.Sleep( ServerProgram.SLEEP * 1000);
}
}
private static EndPoint ReceiveData(Socket sck)
{
byte[] buff = new byte[8];
EndPoint clientEP = new IPEndPoint(IPAddress.Any, 0);
int cnt = sck.ReceiveFrom(buff, ref clientEP);
Console.WriteLine(cnt + " bytes received from " + clientEP.ToString());
return (IPEndPoint)clientEP;
}
private static void SendData(Socket sck)
{
DateTime n = DateTime.Now;
byte[] b = BitConverter.GetBytes(n.Ticks);
Console.WriteLine("Sending " + b.Length + " bytes : " + n.TimeOfDay.ToString());
sck.Send(b);
}
private static IPAddress GetIPAddress()
{
// Same as client app...
}
}
(this is just test code, don't pay attention to the infinite loops or lack of data validation)
The problem is after a few messages sent, the client stops receiving them. The server keeps sending, but the client gets stuck at sck.Receive(buff). If I change SLEEP constant to a value higher than 5, the 'connection' gets lost after 3 or 4 messages most of the time.
I can confirm the client machine doesn´t receive any packet when the connection is lost since I use Wireshark to monitor the communication.
The server app runs on a server with direct connection to Internet, but the client is a machine in a local network, behind a router. None of them has a firewall running.
Does anyone have a clue what could be happening here?
Thank you!
EDIT - Additional data:
I tested the client app in several machines in the same network and the connection get lost always. I also tested the client app in other network behind other router and there is no problem there. My router is a Linksys RV042 and never had any problem with it, in fact, this app is the only one with problems.
PROBLEM SOLVED - SHORT ANSWER: It was a hardware problem.
I don't see any overt problems in the source code. If it is true that:
The server keeps sending packets (confirmed by WireShark on the server)
The client never receives the packets (confirmed by WireShark on the client)
..then the problem could be related to networking equipment between the two machines, which don't always handle UDP flows as expected especially when behind routers/firewalls.
I would recommend the following approach to troubleshooting:
Run client & server on the same system and use the loopback interface (confirm UDP code works on the loopback)
Run the client & server on two different systems that are plugged into the same Ethernet switch (confirm that UDP communication works switch-local)
If everything works switch-local you can be fairly sure you have a network configuration problem.