I'm trying to build a netowrk app. I have succesfully made a server that sends and receives packages. So far, testing has been done on one computer pointing to 127.0.0.1 (No place like home). Now I want to switch to the network. How can I find computers on a LAN network that are listening to my specific port?
The service will need to listen for broadcast messages on a known port (if you want to be really well behaved you can register the program and port number with the IANA), when it hears a broadcast message it replies to the sender the server's IP and what port the service is listening for incoming connections on.
Here is a simple example from the link above, this just prints to the console who connected and on what port, but you can use this information to establish a TCP or UDP connection between the two endpoints.
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
class RecvBroadcst
{
public static void Main()
{
Socket sock = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
IPEndPoint iep = new IPEndPoint(IPAddress.Any, 9050);
sock.Bind(iep);
EndPoint ep = (EndPoint)iep;
Console.WriteLine("Ready to receive…");
byte[] data = new byte[1024];
int recv = sock.ReceiveFrom(data, ref ep);
string stringData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine("received: {0} from: {1}",
stringData, ep.ToString());
data = new byte[1024];
recv = sock.ReceiveFrom(data, ref ep);
stringData = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine("received: {0} from: {1}",
stringData, ep.ToString());
sock.Close();
}
}
As a psudo example here is the sequence of events on how I would do it.
For this example lets say we have a network with a IP of 192.168.1.0 and a subnet of 255.255.255.0. We have two servers, Server1 at 192.168.1.2 with the service listening on port 1234, and Server2 at 192.168.1.3 with a port of 4567 for the service. Both are listing on port 3000 for broadcast messages. The client connecting will be at the IP 192.168.1.4
Client chooses a random port in the dynamic port range(49152-65535) and binds to it on UDP (port 50123 for this example) and listens.
The client broadcasts to the broadcast address and the known port for his local subnet (192.168.1.255:3000) using the same port to send as he is listening on. He sends some kind of payload so the servers only send back to your clients, instead of someone else who happened to use the same port as you. (lets say it sends the string Send me your info for XYZ app!)
Server1 receives the broadcast. Checks that the message is Send me your info for XYZ app! and sends the UDP message Name:Server1 IP:192.168.1.2 Port:1234 back to the senders source port and IP combination (192.168.1.4:50123)
Server2 receives the broadcast also. Checks that the message is Send me your info for XYZ app! and sends the UDP message Name:Server2 IP:192.168.1.3 Port:4567 message back to the senders source port and IP combination (192.168.1.4:50123)
The client receives two UDP messages on the same port he sent the message on. He parses the replies and displays to the user the two servers available to connect to.
Related
I wrote a program in C# that sends SMS using GSM LAN Modem(Coniugo). I'm using socket as client to asynchronously connect to the GSM LAN Modem. The Modem IP address is 192.186.2.1, and the port is 10001. I use this code to start the connection to the Modem
AsynchronousClient smsClient; // the clinet manager
IPAddress ipAddress;
int port;
IPEndPoint remoteEP;
// Create a TCP/IP socket.
Socket client;
private void btnStartConnect_Click(object sender, EventArgs e)
{
try
{
ipAddress = IPAddress.Parse("192.186.2.1");
port = 10001;
remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP socket.
client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(smsClient.ConnectCallback), client);
smsClient.connectDone.WaitOne();
if (client.Connected)
{
lblStatus.Text = "Client is Connected";
smsClient.Receive(client);
}
else
{
lblStatus.Text = "Client is Not Connected";
}
}
catch (Exception ex)
{
lblStatus.Text = ex.ToString();
}
}
When i run the code and start to connect to the Modem from a host in the network, the connection works without problem, but when i try run the code on another host, the connection does not work. I got the exception message
No connection could be made because the target machine actively refused it 192.186.2.1:10001.
How to connect to the GSM Modem from several hosts using socket, and avoid this exception?
You cannot. The network adapter (from Lantronix) in the Coniugo GSM modem will only accept one connection at a time.
This is necessary: The modem itself cannot deal with multiple connections. The modem actually uses serial communications - that can only handle one connection. If you allow multiple TCP connections, two users could send data at the same time. The modem cannot deal with that situation.
You have two options:
Your program only connects to the modem for as long as it takes to send the SMS. Enter all your data, hit send, and the program connects, sends the SMS, then disconnects.
You write a server program that connects to the modem. Your clients who want to send an SMS connect to the service, and it handles queueing and sending the SMS as well a keeping indiviual clients informed of the state.
I'd go for option 2.
I've created two apps (A client and a server) which can communicate with each other as long as I input the local IP address of the machine the server app is running on into the client app (in code).
I would like the client app to automatically discover the local IP address of the machine running the server app and connect to it, so they can be run on any network without the need to enter the IP in code.
Both of these apps with be running on the same network (ie. Over WiFi, not the Internet)
Here is what I have so far in my client app:
// COMMUNICATE WITH SERVER
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.35"), 8888);
public Console()
{
InitializeComponent();
client.Connect(serverEndPoint);
}
private void SendMessage(string msg)
{
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
In this example I can only connect to a server running on "192.168.2.35", I would like it to be able to find the server running on port 8888 on any machine on the network.
Alternatively, if this isn't possible I would like the server to broadcast its IP as a message (of some sort) and have the client receive this message and verify it is the server and connect to it.
I think my second example is the proper way to do this, but I can't seem to wrap my head around how to get it working (I'm fairly new to C#), and any other examples I've found I can't seem to get to work with my applications.
Here is my server code if it helps answer my question:
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
TcpClient client = this.tcpListener.AcceptTcpClient();
connectedClients++;
lblNumberOfConnections.Text = connectedClients.ToString();
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
Thanks
EDIT: I've tried adding THIS to my project, but being so new I'm unsure how to implement it properly, and it didn't get me anywhere.
2nd EDIT: I've tried implementing a UDP broadcast a few times now, with no luck on any attempt yet. My latest attempt was at implementing THIS (minus the chat parts). I just can't seem to get a UDP broadcast working at all with my project, as it seems to be way over my head at my current skill level. Unfortunately, having my client automatically connect to the server is 100% necessary for my project to function...
My other problem, which is maybe best to start a separate question for, but somewhat correlates to this issue is: My client GUI consists of a panel that switches between multiple custom classes, each containing different buttons, etc. (works similar to tab pages) that communicate to the server I'm trying to connect to. Once I get the UDP broadcast figured out, will I need to code that into every class separately? or is there a way of having all classes running in my panel connect to the same server?
A simple, but possibly costly(in terms of network traffic) solution would be for your server application to broadcast over UDP it's application and connection info. Your client could listen for all broadcast packets that have your servers custom header. Assuming a connection is made you could stop the broadcast. The downside is you would have to be broadcasting constantly if a client is not connected and this can clog your network if there aren't limits placed on the broadcast speed.
EDIT: Here is a boiled down explanation generated from the MSDN article https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
EDIT #2: I've expanded on this answer on my blog, as well as provided downloadable example projects. the article can be found at http://martialdeveloper.com/wordpress/?p=21
1. Find your network's broadcast IP
A special “Broadcast Address” must be used when using UDP for the purpose of sending a datagram to all machines connected to a given network. For example, the typical home network host/gateway of 192.168.0.1 has a broadcast address of 192.168.0.255. If your network differs from this you can use an IPv4 broadcast address calculator like the one found here http://jodies.de/ipcalc
Or read the introductory section on MSDN describing the broadcast address. https://msdn.microsoft.com/en-us/library/tst0kwb1(v=vs.110).aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
2. Select a listening/broadcast port
Any port that is free on your client & server is fine. The MSDN example uses 11000. This port number is used in your broadcaster, and listener.
3. Code for the Listener
Note to the reader. All error handling has been omitted for clarity of the example.
int listenPort = 11000;
bool done = false;
UdpClient listener = new UdpClient(listenPort);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any,listenPort);
while (!done) // This loop listens for your broadcast packets
{
Console.WriteLine("Waiting for broadcast");
byte[] bytes = listener.Receive( ref groupEP);
Console.WriteLine("Received broadcast from {0} :\n {1}\n",
groupEP.ToString(),
Encoding.ASCII.GetString(bytes,0,bytes.Length));
}
listener.Close();
Note: The third parameter to Console.WriteLine, "Encoding.ASCII..." represents the string value sent over UDP in the datagram packet. This contains the desired negotiation information for a discovery situation, such as the IP address of the client or server you wish to connect to.
4. Code for the Broadcaster
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram,
ProtocolType.Udp);
IPAddress broadcast = IPAddress.Parse("This string should be the broadcast IP address"); //NOTE: Broadcast IP goes here!!
byte[] sendbuf = Encoding.ASCII.GetBytes("This is the message string to be broadcast"); //Your message to the client/server goes here, I.E. an
// app/client name or ID and an IP to connect with over TCP
IPEndPoint ep = new IPEndPoint(broadcast, 11000);
s.SendTo(sendbuf, ep);
Console.WriteLine("Message sent to the broadcast address");
NOTE: This is a very simple example. The broadcaster may need to rebroadcast for a period of time to make sure the Listener receives it. Even after the UDP datagram is sent/received there will need to be some negotiation to ensure the TCP connection is made properly.
I have created a windows service socket programme to lisen on specific port and accept the client request. It works fine.
protected override void OnStart(string[] args)
{
//Lisetns only on port 8030
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, 8030);
//Defines the kind of socket we want :TCP
Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//Bind the socket to the local end point(associate the socket to localendpoint)
serverSocket.Bind(ipEndPoint);
//listen for incoming connection attempt
// Start listening, only allow 10 connection to queue at the same time
serverSocket.Listen(10);
Socket handler = serverSocket.Accept();
}
But I need the service programme to listen on multiple port and accept the client request on any available port.
So I enhanced the application to bind to port 0(zero), so that it can accept the request on any available port.
But then I got the error 10061
No connection could be made because the target machine actively refused it.
I am unable to know whats the reason of getting this error.
Can anybody please suggest the way to enhance the code to accept the request on any port.
But the client need to send request to connect to specific port. e.g client1 should connect to port 8030, client2 should connect to port 8031.
So I enhanced the application to bind to port 0(zero), so that it can accept the request on any available port.
Wrong. 0 means that the OS should assign a port. A server can only listen at one port at a time. The listen socket just accepts new connections.
The new connection will have the same local port, but the combination of Source (ip/port) and destination (ip/port) in the IP header is used to identify the connection. That's why the same listen socket can accept multiple clients.
UDP got support for broadcasts if that's what you are looking for.
Update:
A very simplified example
Socket client1 = serverSocket.Accept(); // blocks until one connects
Socket client2 = serverSocket.Accept(); // same here
var buffer = Encoding.ASCII.GetBytes("HEllo world!");
client1.Send(buffer, 0, buffer.Count); //sending to client 1
client2.Send(buffer, 0, buffer.Count); //sending to client 2
Simply keep calling Accept for each client you want to accept. I usually use the asynchronous methods (Begin/EndXXX) to avoid blocking.
I'm having a problem with sockets.
I've written myself two simple applications, one server and one client.
The server simply waits for a UDP packet to arrive, printing out something in the console once that happens.
The client sends a UDP packet to a specific end point.
// server
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
sock.Bind(new IPEndPoint(IPAddress.Any, 1337));
IPEndPoint remote = new IPEndPoint(IPAddress.Any, 0);
byte[] buf = new byte[1024];
sock.ReceiveFrom(buf, ref remote);
Console.WriteLine("Received packet.");
// client
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint remote = new IPEndPoint(IPAddress.Parse(Console.ReadLine()), UInt16.Parse(Console.ReadLine()));
byte[] buf = { 1, 2, 3, 4 }; // random data
sock.SendTo(buf, remote);
Now the weird thing is that when the client socket sends its packet to the public IP address of my router, the server socket only receives it if the client is not run on the same PC as the server. So if I start the server on my PC and then start the client on my PC, enter my public IP and port 1337, the server doesn't receive anything.
However, if I send the client application to my friend and give him my IP address and port, it works perfectly fine.
It also works if I let the client connect to my local IP instead of my public one.
Am I the only one experiencing this behaviour?
Port 1337 is forwarded to the computer the server is ran on, btw.
This seems to be a NAT configuration issue. You must have configured nat on the router to forward packets coming on the public interface with specific port (1337) to be forwarded to the server. So this works when your friend sends you a UDP packet.
But you must not (don't know if its even possible) have configured natting the other way around meaning the same UDP packet coming to the internal interface. This is the case when you send packet from server to client with both on the same machine.
When both the server and client (on a single machine or two different machines) are on your internal network it will be best to use the server's interface id than depending on natting
Most routers and modems do not normally forward UDP traffic -- see http://www.gotroot.com/blogpost4-Why-your-should-never-forward-UDP-out-of-your-firewall for an explanation. Also try attaching both the client and server to the same physical network (well, subnet) and to try sending datagrams directly to the server instead of forwarding them.
i am sending data to UDP socket using this code
Socket udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Parse(obj.destAddress), obj.destPort);
byte[] buf = new byte[obj.length];
Array.Copy((byte[])obj.data, buf, obj.length);
int n = udpClient.SendTo(buf, ipEndPoint);
udpClient.Close();
this code works fine when IP exists in current network, but it takes 3-5 seconds when I send data to unknown IP address. This causes main application to hang for 3-5 seconds.. What could be the reason behind this problem..
Your IP stack cannot send a UDP packet until it the MAC address is known. The is done with the ARP protocol. The IP stack sends an ARP query and times out waiting for the ARP response. When finished the SendTo returns.
When you send a UDP packet to the internet the MAC address of the gateway is necessary. Since the gateway is usually available the timeout does not appear since your IP stack was able to send to the gateway indenpendent of if the destination is available or not.
You can try to set a socket option to operate asynchronously.