Thanks in advance for any help.
There is a program, not written by me that sends UDP multicast packets of info on the local LAN. I've looked the source and it appears they are correctly setup to multicast. This program is WSJT-X which if you are a Ham operator you might have heard of.
The UDP packets contain over the air signal decodes so lots of other programs including mine are interested in these packets.
The problem I'm having is that my UDP receive seems to consume the messages so no other software running on the same machine seems to receive them once my test software starts up.
Here is simple receiver:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ReadUDP
{
internal class Program
{
private static void Main(string[] args)
{
// Setup
int port = 2237;
var multicastIP = IPAddress.Parse("225.0.0.1");
// Create endpoints
var remoteEndPoint = new IPEndPoint(multicastIP, port);
var localEndPoint = new IPEndPoint(IPAddress.Any, port);
// Create and configure UdpClient
var udpclient = new UdpClient();
udpclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpclient.ExclusiveAddressUse = false;
udpclient.Client.MulticastLoopback = true;
udpclient.MulticastLoopback = true;
// Bind, Join
udpclient.Client.Bind(localEndPoint);
udpclient.JoinMulticastGroup(multicastIP, IPAddress.Any);
Task.Run(() =>
{
IPEndPoint sender = new IPEndPoint(0, 0);
while (true)
{
var recvBuffer = udpclient.Receive(ref sender);
var recvStr = Encoding.UTF8.GetString(recvBuffer);
Console.WriteLine("--------------------------------------------------------------------------");
Console.WriteLine($"From:{sender} Data:{recvStr}");
Console.WriteLine("--------------------------------------------------------------------------");
}
});
Console.ReadLine();
}
}
}
This simple program receives the data sent by WSJT-X just fine.
If I clone this project to a new directory, build a new copy of the program and run it, the copy never receives any of the broadcast data while the first copy is running. Only the first running copy gets data.
If I shutdown the first copy then the second copy starts to receive the data.
This acts like the first copy is consuming the message and no other clients receive it. I'm trying to prevent that. I just want to in effect, "peek" at the messages and allow other clients to receive them.
I've tried a a bunch of different options and settings, I've looked at many examples but I have not been able to solve this issue.
Any help would be greatly appreciated.
For those of you that don't have WSJT-X, the following simple UDP sender will send UDP packets:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ReadUDP
{
internal class Program
{
private static void Main(string[] args)
{
// Setup
int port = 2237;
var multicastIP = IPAddress.Parse("225.0.0.1");
// Create endpoints
var remoteEndPoint = new IPEndPoint(multicastIP, port);
var localEndPoint = new IPEndPoint(IPAddress.Any, port);
// Create and configure UdpClient
var udpclient = new UdpClient();
udpclient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpclient.ExclusiveAddressUse = false;
udpclient.Client.MulticastLoopback = true;
udpclient.MulticastLoopback = true;
// Bind, Join
udpclient.Client.Bind(localEndPoint);
udpclient.JoinMulticastGroup(multicastIP, IPAddress.Any);
Task.Run(() =>
{
int msgnum = 1;
while (true)
{
var msg = $"Sending message {msgnum++}";
Console.WriteLine("--------------------------------------------------------------------------");
Console.WriteLine($"Send: {msg}");
Console.WriteLine("--------------------------------------------------------------------------");
var bytes = Encoding.UTF8.GetBytes(msg);
udpclient.Send(bytes, bytes.Length, remoteEndPoint);
Task.Delay(2000).Wait();
}
});
Console.ReadLine();
}
}
}
I am doing much the same thing but in VB.net.
WSJT-x runs on my "HamPC" and sends the udp packets to my "Programming" PC for decode.
Program skims the callsigns and looks up the stations Country/State via QRZ's XML service and plays a sound when a new state or country shows up on the band I am listening to.
I have yet to run 2 instances of my program on the "ProgrammingPC" but if I run into what you have I would add code so that the first running instance of my program will rebroadcast all of the packets exactly as received to another port for the second instance of my program to receive.
I found this thread looking for information on finding the Band information in the UDP packets transmitted by WJST-x. I've found and decoded the AudioFreq, TimeStamp and Signal Strength fields easily enough, now I'm scouring the data to locate the Band/Frequency which I need. Was easy in the first generation of my program which repeated read the all.txt file every 15 seconds at 01 16 31 and 41 seconds after the minute and determines which records are new (via simple line counting)
I have Googled high and low but cannot find a published structure of wjst-x's UDP packets - mainly offsets of the fields / how to decode them. I found the fields mentioned above by capturing the UDP packets looking at the contents byte by byte and comparing to the all.txt file for records written during the same transmissions.
The Band/Freq field should be the last one I need.
I believe my suggestion and retransmitting the packets intact to another port for the 2nd instance to receive on will work for you.
Program starts up unware if it is the 1st instance or not. It listen's on the primary port -- If data received on primary uses that port for receive and rebroadcasts the data as received to the 2nd port.
If no data was received on the 1st port it would switch and to listen on the 2nd port and not rebroadcast the data.
Perhaps a bandaid of a workaround but should work.
Best of luck! - 73 ne5B
Related
I have two third party programs running on my PC which communicate with each other via UDP. Program A is simply a user-interface application which connects via UDP and allows the user to send specific hex commands to program B which sends back some acknowledgement in hex. I know that program B receives on port 11001 and sends on port 11000. I am trying to recreate program A myself in C# as a console application to start with. I've written the following code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
network udpNetwork = new network();
Console.WriteLine("Hello World!");
udpNetwork.StartListener();
}
}
class network
{
private const int sendPort = 11001; //Port to transmit to
private const int receivePort = 11000; //Port to receive on
public void StartListener()
{
string IP_Address = Dns.GetHostByName(Environment.MachineName).AddressList[1].ToString();
IPAddress broadcast = IPAddress.Parse(IP_Address); //create IP address
IPEndPoint endpointSend = new IPEndPoint(broadcast, sendPort);
IPEndPoint endpointReceive = new IPEndPoint(broadcast, receivePort);
UdpClient udpServer = new UdpClient(AddressFamily.InterNetwork);
udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer.Client.Bind(endpointSend);
var packetData = new byte[] { 0x1F, 0x7F, 0x80, 0x1F, 0xFF };
try
{
udpServer.Connect(endpointSend);
udpServer.Send(packetData, packetData.Length);
udpServer.Close();
UdpClient udpReceive = new UdpClient(AddressFamily.InterNetwork);
udpReceive.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpReceive.Client.Bind(endpointReceive);
Byte[] receiveBytes = udpReceive.Receive(ref endpointReceive);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("This is the message you received " +
returnData.ToString());
} catch(Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
The code runs fine until the line Byte[] receiveBytes = udpReceive.Receive(ref endpointReceive); where it hangs. I read that this function is blocking which means that the program is waiting for data but obviously not receiving any. Program B listening on port 11001 should send back a response after I have sent the packetData but doesn't. I don't have anyway to use program B to confirm that it is getting the data I am sending. How could I confirm that Program B receives my data in the first place, or do I have some other issue with my code?
edit:
I have edited my code to make use of IPV4 rather than IPV6 as per Jdweng's suggestion. (Shown corrected in the code snippet above). Program B is however still not receiving any data which I can confirm by using TCPView. After launchign the program from within Visual Studio 2019 TCPView shows that there were no received packets by Program B.
I have a program that was written on C that needs to send data to another application written on C#.
Can someone show a basic hello world example on how to make use of UnixDomainSocketEndPoint on linux? . I will like the c# application to be the server. In other words the C application will send data to the C# application. How can I create a unix socket that will be listening for data on dotnet (the application does not need to reply nothing back) ?
When researching on the internet all the stuff I find is relevant to mono such as this question:
How to connect to a Unix Domain Socket in .NET Core in C# . I tried that example and it did not work. Moreover it does not make use of UnixDomainSocketEndPoint.
I also found this tutorial https://medium.com/#goelhardik/http-connection-to-unix-socket-from-dotnet-core-in-c-21d19ef08f8a that uses the same code.
Maybe there are not that many examples on the internet because it is more simple than I thought. I was able to answer the question without researching on the internet. I should had tried it before asking. Anyways here is the answer:
using System;
using System.Net.Sockets;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
var path = "/tmp/foo.sock";
// client
Task.Run(async () =>
{
// wait 2 seconds
await Task.Delay(2000);
using (var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
{
socket.Connect(new UnixDomainSocketEndPoint(path));
// send hello world
var dataToSend = System.Text.Encoding.UTF8.GetBytes("Hello-world!");
socket.Send(dataToSend);
}
});
// Server
{
// delete file if it exists
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
socket.Bind(new UnixDomainSocketEndPoint(path));
socket.Listen(5);
Console.WriteLine("Server started waiting for client to connect...");
var s = socket.Accept();
Console.WriteLine("Client connected");
var buffer = new byte[1024];
var numberOfBytesReceived = s.Receive(buffer, 0, buffer.Length, SocketFlags.None);
var message = System.Text.Encoding.UTF8.GetString(buffer, 0, numberOfBytesReceived);
Console.WriteLine($"Received: {message}");
}
}
}
I'm trying to communicate with a modbus device in my network at ip 192.168.1.76. My host computer address is 192.168.1.132. I'm not able to connect to or listen to device ip.
basically i'm using NModbus4 library. I've created a ModbusTCPSlave and attached the tcp listener to it. then i assigned ModbusSlaveRequestReceived event to that slave. but it gives nothing in return when i try to change register values directly from Modscan software.
Main()
{
var masterEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.132"), 502);
var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, new TcpListener(masterEndpoint), 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
}
private static void Modbus_Request_Event(object sender, Modbus.Device.ModbusSlaveRequestEventArgs e)
{
//disassemble packet from master
byte fc = e.Message.FunctionCode;
byte[] data = e.Message.MessageFrame;
byte[] byteStartAddress = new byte[] { data[3], data[2] };
byte[] byteNum = new byte[] { data[5], data[4] };
Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," + NumOfPoint.ToString());
}
I expect to get function code, start address and number of points in console application when any register value is changed
I copied your code. Changed the IP address to my "server" and it worked.
So, the issue you are having is either in the setup of your "server" or in the PLC program.
I thought that I had to do some port forwarding on my router. I did not. It did not make a difference.
Server setup:
Your "server"'s IP address needs to be static. Whether your 'server' is your development system or not. And don't forget when you deploy... Server's IP address has to be static as well (not that it wouldn't be...just saying)
Add an inbound Firewall rule to allow connections to the port, in this case 502, otherwise you'll have to allow access every time you launch/start a test.
PLC program
I am using Click PLC's by Koyo. Not sure if this is the rule for all PLC's or not; but, we had to add a line of code to "write" the values we wanted to pick up off the TCP stream. Without the write, the PLC was not sending out a request to join the TcpListener.
Last:
The code to start your listener only needs to be this:
var listener = new TcpListener(IPAddress.Parse("192.168.1.244"), 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, listener, 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
I've been following the guide over at http://www.codeproject.com/KB/IP/sharppcap.aspx for implementing a simple packet sniffer to automate authentications for me, I've managed to get to the Filtering section, and have had to make some adjustments to the tutorial code so far for it to work, but I am now stumped.
The error I am receiving is;
The best overloaded method match for 'PacketDotNet.TcpPacket.GetEncapsulated(PacketDotNet.Packet)' has some invalid arguments
Argument 1: cannot convert from 'SharpPcap.RawCapture' to 'PacketDotNet.Packet'
But I've yet to make any references to PacketDotNet my self (everything so far has been SharpPcap).
Entire code I have so far is included, the problem is in the device_OnPacketArrival() function.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PacketDotNet;
using SharpPcap;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string ver = SharpPcap.Version.VersionString;
Console.WriteLine("SharpPcap {0}, Example1.IfList.cs", ver);
// Retrieve the device list
CaptureDeviceList devices = CaptureDeviceList.Instance;
// If no devices were found print an error
if (devices.Count < 1)
{
Console.WriteLine("No devices were found on this machine");
return;
}
// Extract a device from the list
ICaptureDevice device = devices[0];
// Register our handler function to the
// 'packet arrival' event
device.OnPacketArrival +=
new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
// Open the device for capturing
int readTimeoutMilliseconds = 1000;
device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
// tcpdump filter to capture only TCP/IP packets
string filter = "ip and tcp";
device.Filter = filter;
Console.WriteLine();
Console.WriteLine("-- The following tcpdump filter will be applied: \"{0}\"",
filter);
Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...",
device.Description);
// Start capturing packets indefinitely
device.Capture();
// Close the pcap device
// (Note: this line will never be called since
// we're capturing indefinitely
device.Close();
}
private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
{
var tcp = TcpPacket.GetEncapsulated(e.Packet);
}
}
}
A SharpPcap.RawPacket is used to hold the raw data captured over the network adapter but PacketDotNet needs the packet parsed before the GetEncapsulated() methods will work. The step you need will look like:
var packet = PacketDotNet.Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data);
Then you can extract the encapsulated TcpPacket via the GetEncapsulated() method by passing it packet.
Example 12 in the SharpPcap source download at https://sourceforge.net/projects/sharppcap/ shows the syntax and how packets can be modified.
Keep in mind that PacketType.GetEncapsulated() is returning a reference to that portion of the packet so modifying it will alter the original packet.
As an update to Chris Morgan's answer (because I find myself doing this today), getEncapsulated() is now obsolete, instead you should use packet.Extract() to extract the encapsulated packet.
Alternatively, you can use Pcap.Net, which only has one Packet class that you can dynamically parse to get whatever it may contain without doing any packet cast.
You just get a Packet object and do (for example):
uint sequenceNumber = packet.Ethernet.IpV4.Tcp.SequenceNumber;
No need to cast it or know what kind of packet it is in advance, all parsing is done dynamically.
C# .Net application which connects to five different data streams. The data streams are all in the same plaintext format, but have information from different areas. The application creates an array of custom objects, which contains sockets. Each socket connects to its IP/port (same IP, different ports) with no problems. However, when I read data off each socket, I'm getting the same data stream, from the first port number (in range, 10085-10089). For instance, I read data off the socket that's connected to 10088, but I get data from 10085.
The IP/port is grabbed from a database, so I deleted all but the record for port 10088, so the array created has only one object; there is only one socket connection, to port 10088. But I'm still getting only data from 10085.
I've viewed the data from each port through putty; the data is definitely different. Any idea why I'm getting the same data no matter what port a socket's connected to?
This is some simpler code that replicates the problem:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
namespace MultipleFeedConnectionsTest
{
class Program
{
static void Main(string[] args)
{
Socket[] sockets;
IPAddress ipAddress;
IPAddress currentIP;
int portNumber = 10085;
ipAddress = IPAddress.Parse("xxx.xxx.xxx.xxx"); // changed the IP
currentIP = IPAddress.Parse("192.168.5.122");
sockets = new Socket[5];
for (int counter = 0; counter < 5; counter++)
{
if (counter != 1)
{
sockets[counter] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sockets[counter].Bind(new IPEndPoint(currentIP, portNumber + counter));
sockets[counter].Connect(new IPEndPoint(ipAddress, portNumber + counter));
}
}
while (true)
{
for (int counter = 0; counter < 5; counter++)
{
if (counter != 1)
{
byte[] receivedData = new byte[255];
NetworkStream stream = new NetworkStream(sockets[counter]);
stream.Read(receivedData, 0, 255);
Console.WriteLine("FEED " + (portNumber + counter));
Console.WriteLine(Encoding.ASCII.GetString(receivedData));
}
}
}
}
}
}
The above code outputs the same data from each socket. Again, when I access these through putty, they are different.
Tried your code and it works just fine.
You should however get rid of the call to sockets[counter].Bind(........) because it has nothing to do with your code - at all!!
Binding is usually done on the listening socket side, not the connecting one.
Anyway, besides that everything looks normal - I've also made sure I'm sending a unique message to each socket..