I've started to do some basic network programming.
I have read/written my own programs using TcpClient and TcpListener and that has worked fine.
However, the application I am working on now works a bit differently.
I want to set up a program that listens for tcp/ip packets without having to connect.
For example, have a packet sending app send a packet to my program with the appropriate ip add and port number.
I have also looked into using Sharppcap and packet.net but all of the examples I've found only listens on devices found locally (no opportunity to set parameters such as port number and ip add).
Does anyone have a suggestion on how to go about doing this?
You should look at using the UDP protocol instead of TCP/IP.
http://en.wikipedia.org/wiki/User_Datagram_Protocol
Here is the code for the client:
using System.Net;
using System.Net.Sockets;
...
/// <summary>
/// Sends a sepcified number of UDP packets to a host or IP Address.
/// </summary>
/// <param name="hostNameOrAddress">The host name or an IP Address to which the UDP packets will be sent.</param>
/// <param name="destinationPort">The destination port to which the UDP packets will be sent.</param>
/// <param name="data">The data to send in the UDP packet.</param>
/// <param name="count">The number of UDP packets to send.</param>
public static void SendUDPPacket(string hostNameOrAddress, int destinationPort, string data, int count)
{
// Validate the destination port number
if (destinationPort < 1 || destinationPort > 65535)
throw new ArgumentOutOfRangeException("destinationPort", "Parameter destinationPort must be between 1 and 65,535.");
// Resolve the host name to an IP Address
IPAddress[] ipAddresses = Dns.GetHostAddresses(hostNameOrAddress);
if (ipAddresses.Length == 0)
throw new ArgumentException("Host name or address could not be resolved.", "hostNameOrAddress");
// Use the first IP Address in the list
IPAddress destination = ipAddresses[0];
IPEndPoint endPoint = new IPEndPoint(destination, destinationPort);
byte[] buffer = Encoding.ASCII.GetBytes(data);
// Send the packets
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
for(int i = 0; i < count; i++)
socket.SendTo(buffer, endPoint);
socket.Close();
}
Related
I used this web server for c#:
I tried other projects too, but I can't connect to my IP.
This is the main function:
/// <param name="path">Directory path to serve.</param>
public SimpleHTTPServer(string path)
{
//get an empty port
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
this.Initialize(path, port);
}
For example:
127.0.0.1 - working
localhost - working
122.211.2.27 - not working
the issue is likely related to the fact that you explicitly create the TcpListener bound to the loopback:
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
read the documentation for more details about how to create a listener without an explicit binding or bound to a different ip address.
I am currently working on a C#/Android client/server project.
I have a server application, running C# on Windows, which sends a broadcast message on port 8000.
The idea is the client application (Android) receives the broadcast and then shows the server hostname and IP, from the message sent via the broadcast, on the Android device for the user to select.
Below is how I am attempting to do the broadcast.
int availableTCPSocket = 0;
try
{
//UdpClient udp = new UdpClient();
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
availableTCPSocket = getAvailableTCPSocket();
//IPEndPoint endpoint = new IPEndPoint(IPAddress.Broadcast, BROADCAST_PORT);
IPEndPoint endpoint = new IPEndPoint(IPAddress.Parse("192.168.1.255"), BROADCAST_PORT);
XmlGenerator xmlGenerator = new XmlGenerator();
xmlGenerator.addStartElement("ServerInformation");
xmlGenerator.addElementString("Hostname", Dns.GetHostName());
NetworkAdapterDetails networkAdapterDetails = getNetworkAdapterDetails();
xmlGenerator.addElementString("IP_Address", networkAdapterDetails.ipAddress);
xmlGenerator.addElementString("MAC_Address", networkAdapterDetails.macAddress);
xmlGenerator.addElementString("AvailableTCPSocket", availableTCPSocket.ToString());
xmlGenerator.addEndElement();
xmlGenerator.flushAndCloseXmlWriter();
string udpData = xmlGenerator.returnXml();
byte[] sendBytes = Encoding.ASCII.GetBytes(udpData);
while (true)
{
//udp.Send(sendBytes, sendBytes.Length, endpoint);
socket.SendTo(sendBytes, endpoint);
Console.WriteLine("Broadcast Sent");
System.Threading.Thread.Sleep(5000);
}
}
catch (Exception ex)
{
Console.WriteLine("Broadcast Sender Exception: {0}", ex.Message);
}
If I set the endpoint to be IPAddress.Broadcast it says it is 255.255.255.255 but my devices never receive the broadcast.
If I change the endpoint to be hardcoded to 192.168.1.255 then my devices receive the broadcast.
So because of this I have two questions.
If I use IPAddress.Broadcast why don't my devices receive anything if this is supposed to be broadcast.
If 192.168.1.255 is the correct broadcast address, how can I find out what the addresss should be dynamically, the idea is the server will be provided for download so has to work on different network configurations where 192.168.1.255 might not be the correct address.
It also takes a long time for the device to receive the packet, the server writes to the console each time its looped round and sends the broadcast but it takes about 4 or 5 broadcasts to be sent before the devices receives it. Its on a WIFI network but strong signal on all devices, 60mb download on the internet and 2ms ping between router and devices.
Thanks for any help you can provide.
Windows 7 handles 255.255.255.255 broadcast in a different way. More info here: Send UDP broadcast on Windows 7
use subnet broadcast instead of 255.255.255.255
Code to Get subnet broadcast address
public static IPAddress GetBroadcastAddress(this IPAddress address, IPAddress subnetMask)
{
byte[] ipAdressBytes = address.GetAddressBytes();
byte[] subnetMaskBytes = subnetMask.GetAddressBytes();
if (ipAdressBytes.Length != subnetMaskBytes.Length)
throw new ArgumentException("Lengths of IP address and subnet mask do not match.");
byte[] broadcastAddress = new byte[ipAdressBytes.Length];
for (int i = 0; i < broadcastAddress.Length; i++)
{
broadcastAddress[i] = (byte)(ipAdressBytes[i] | (subnetMaskBytes[i] ^ 255));
}
return new IPAddress(broadcastAddress);
}
You need to enable sending broadcast messages on the socket with socket.EnableBroadcast = true. Then you should be able to send them to 255.255.255.255 just fine.
Reference: http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.enablebroadcast(v=vs.110).aspx
Over wi-fi sometimes doesn't allow the packets send over 255.255.255.255 depending on the security settings in it. Find the broadcast address of the network at run time & use it. You can get the broadcast network address of any network by performing the below operation.
broadcastaddress = (ipaddressofthesystem & netmask) & ~netmask;
Also as an alternative you should consider using multicast address.
I am working on the application which send and receive messages on UDP between client app and server app.
On my server I have 4 different network cards, e.g. nic1 = 169.524.15.12, nic2 = 169.524.15.65, etc. My DNS is point to nic2. The client app resolves the DNS and send data to nic2. However my server app sometime respond to client from nic1.
I'm using an UdpClient to listen for incoming packets.
This is my server application code:
objSocketServer = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint objEndPointOfServer = new IPEndPoint(IPAddress.Any, 5000);
objSocketServer.Bind(objEndPointOfServer);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, BUFSIZE - 1, SocketFlags.None, ref objEndPointOfServer, DoReceiveFromClient, objSocketServer);
private void DoReceiveFromClient(IAsyncResult objIAsyncResult)
{
try
{
// Get the received message.
_objSocketReceivedClient = (Socket)objIAsyncResult.AsyncState;
EndPoint objEndPointReceivedClient = new IPEndPoint(IPAddress.Any, 0);
// Received data.
int intMsgLen = _objSocketReceivedClient.EndReceiveFrom(objIAsyncResult, ref objEndPointReceivedClient);
byte[] arrReceivedMsg = new byte[intMsgLen];
Array.Copy(_arrReceivedDataBuffer, arrReceivedMsg, intMsgLen);
// Client port.
// Get and store port allocated to server1 while making request from client to server.
int _intClientServer1Port = ((IPEndPoint)objEndPointReceivedClient).Port;
// Send external ip and external port back to client.
String strMessage = ((IPEndPoint)objEndPointReceivedClient).Address.ToString() + ":" + _intClientServer1Port.ToString();
byte[] arrData = Encoding.ASCII.GetBytes(strMessage);
objSocketServer.SendTo(arrData, arrData.Length, SocketFlags.None, objEndPointReceivedClient);
// Start listening for a new message.
EndPoint objEndPointNewReceivedClient = new IPEndPoint(IPAddress.Any, 0);
objSocketServer.BeginReceiveFrom(_arrReceivedDataBuffer, 0, _arrReceivedDataBuffer.Length, SocketFlags.None, ref objEndPointNewReceivedClient, DoReceiveFromClient, objSocketServer)
}
catch (SocketException sx)
{
objSocketServer.Shutdown(SocketShutdown.Both);
objSocketServer.Close();
}
}
}
Is there any way so that in code, I can detect that I have received packet on which IP address on server and revert with the response with same IP?
Arguably, I could resolve DNS in server app as well and make sure that my server app only listen to IP on which client app is sending packets, however that approach will not work for me when my server app have to listen on > 1 IP.
The SendTo command will use the appropriate NIC (aka, local interface) for the destination address provided. The system metrics determine that. It's not something you set in your code. To view the system metrics, run the command netstat -rn and look at the Interface column. You many need to adjust those if you have a tie. You can enumerate them in code as well using GetAllNetworkInterfaces() and bind to a specific one (if that is what you wanted).
Giving an object instance from the class System.Web.HttpRequest, say myRequest, then using the property System.Web.HttpRequest.UserHostAddress I can retrieve the IP address of the remote client:
string myIp = myRequest.UserHostAddress;
(...)
My need is to retrieve the IP address of the subnet mask of the remote client exclusively from the instance myRequest.
I know that the following is not possible but I would like to accomplish something similar:
string myMaskIp = myRequest.UserHostMaskAddress;
(...)
This because I can't check the local device network interfaces as I could with System.Net.NetworkInformation namespace, so my only available object to probe is the http request made from the remote client to the server.
Thank you very much for your help
I'm pretty sure you can not determine a subnet mask by simply making a request to a remote host - even if the remote host is you.
Oldyis is right for the general case, however it is possible to determine a classful subnetmask from the IPv4 address. Without any further information, determining an classless subnetmask is indeed impossible.
Keep in mind that the classful adressing scheme is virtually not used any more.
Here is an example from this project:
/// <summary>
/// Returns the classfull subnet mask of a given IPv4 network
/// </summary>
/// <param name="ipa">The network to get the classfull subnetmask for</param>
/// <returns>The classfull subnet mask of a given IPv4 network</returns>
public static Subnetmask GetClassfullSubnetMask(IPAddress ipa)
{
if (ipa.AddressFamily != AddressFamily.InterNetwork)
{
throw new ArgumentException("Only IPv4 addresses are supported for classfull address calculations.");
}
IPv4AddressClass ipv4Class = GetClass(ipa);
Subnetmask sm = new Subnetmask();
if (ipv4Class == IPv4AddressClass.A)
{
sm.MaskBytes[0] = 255;
}
if (ipv4Class == IPv4AddressClass.B)
{
sm.MaskBytes[0] = 255;
sm.MaskBytes[1] = 255;
}
if (ipv4Class == IPv4AddressClass.C)
{
sm.MaskBytes[0] = 255;
sm.MaskBytes[1] = 255;
sm.MaskBytes[2] = 255;
}
return sm;
}
(Think of the SubnetMask class as a byte array of length four)
This question already has answers here:
Can't parse domain into IP in C#?
(6 answers)
Closed 9 years ago.
I am trying to make a TCP socket connection to an IP address. I can do this by directly parsing an IP address like this:
IPAddress ipAddress = IPAddress.Parse("192.168.1.123");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 80);
// Create a TCP/IP socket.
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // This works!
However, I cannot figure out how to divine this IP address from a DNS string. I've tried every combination of the following:
IPAddress ipAddress = Dns.Resolve("www.mydns.org"); // No dice
IPAddress ipAddress = Dns.GetHostEntry("www.mydns.org"); // Nada
IPAddress ipAddress = IPAddress.Parse(Dns.Resolve("www.mydns.org")); // So many errors...
IPAddress ipAddress = IPAddress.Parse(Dns.Resolve("www.mydns.org").toString()); // WTh is this attempt anyway?
Would any of you kind souls have a tip to help me squeeze an IPAddress out of a DNS?
foreach (IPAddress ip in Dns.GetHostAddresses("www.mydns.org"))
{
Console.WriteLine(ip.ToString());
}
or simply IPAddress address = Dns.GetHostAddresses("www.mydns.org")[0]; if you want the first one only.
I've got a very neat extension method for just that!
I takes into account that an IPV6 may be returned as the first address in the list of addresses returned by the DNS class and allows you to "favor" an IPV6 or IPV4 on the result. Here is the fully documented class (only with the pertinent method for this case for reasons of brevity):
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// Basic helper methods around networking objects (IPAddress, IpEndPoint, Socket, etc.)
/// </summary>
public static class NetworkingExtensions
{
/// <summary>
/// Converts a string representing a host name or address to its <see cref="IPAddress"/> representation,
/// optionally opting to return a IpV6 address (defaults to IpV4)
/// </summary>
/// <param name="hostNameOrAddress">Host name or address to convert into an <see cref="IPAddress"/></param>
/// <param name="favorIpV6">When <code>true</code> will return an IpV6 address whenever available, otherwise
/// returns an IpV4 address instead.</param>
/// <returns>The <see cref="IPAddress"/> represented by <paramref name="hostNameOrAddress"/> in either IpV4 or
/// IpV6 (when available) format depending on <paramref name="favorIpV6"/></returns>
public static IPAddress ToIPAddress(this string hostNameOrAddress, bool favorIpV6=false)
{
var favoredFamily = favorIpV6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork;
var addrs = Dns.GetHostAddresses(hostNameOrAddress);
return addrs.FirstOrDefault(addr => addr.AddressFamily == favoredFamily)
??
addrs.FirstOrDefault();
}
}
Don't forget to put this class inside a namespace! :-)
Now you can simply do this:
var server = "http://simpax.com.br".ToIPAddress();
var blog = "http://simpax.codax.com.br".ToIPAddress();
var google = "google.com.br".ToIPAddress();
var ipv6Google = "google.com.br".ToIPAddress(true); // if available will be an IPV6
IPHostEntry entry = Dns.GetHostEntry(hostNameOrAddress: "www.google.com");
foreach (IPAddress addr in entry.AddressList)
{
// connect, on sucess call 'break'
}
Simply enumerate address by calling GetHostEntry, on sucess break the loop