My local ip is : 192.168.0.70,
External ip is : 192.168.0.50 : 60000
I want receive data from external ip sending to local ip. I use Socket class because i can send data using remote IPEndPoint. But when Udp connection closed, local ip's port dynamically changing. How can i receive data?
private static void UdpConnect()
{
try
{
IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse("192.168.0.50"), 60000);
Socket client = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
client.Connect(remoteEP);
byte[] sendbuffer = { 1, 2, 3 };
client.Send(sendbuffer);
byte[] receivebuffer = new byte[512];
client.Receive(receivebuffer);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
If you need to listen on a specific local port, use Socket.Bind and then Socket.ReceiveFrom.
You don't need the Socket.Connect call since UDP is a connectionless protocol.
Related
I'm writing a very simple .NET TCP Server and very simple TCP Client that should both run on the same machine (Window 10 Home PC) and connect each other (for testing purposes only).
In the server I'm waiting for the connection in this way:
public static void StartListening()
{
string hostname = Dns.GetHostName();
IPHostEntry ipHostInfo = Dns.GetHostEntry(hostname);
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, Properties.Settings.Default.Port);
Socket listener = new Socket(
ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(Properties.Settings.Default.Port);
while (true)
{
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
var frames = Directory.EnumerateFiles(Properties.Settings.Default.FramesPath);
foreach (string filename in frames)
{
Console.Write("Sending frame: {}...", filename);
SendFile(handler, filename);
Thread.Sleep(Properties.Settings.Default.FrameDelay);
}
}
In the client I'm creating a connection in this way:
private void startClient(string host, int port)
{
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
ClientTCP = new TcpClient();
ClientTCP.Connect(serverEndPoint);
Reader = new StreamReader(ClientTCP.GetStream());
Listen = true;
listner = Listener();
}
startClient is called in this way.
startClient(txtAddr.Text, (int)int.Parse(txtPort.Text));
When I run the client setting host variable to the current machine name (the same the server retrieve trough Dns.GetHostName() I got this exception:
An invalid ip address was specified.
I tried using 127.0.0.1 and I got:
Connection could not be established. Persistent rejection of the target computer 127.0.0.1:5002
I tried with localhost and I got
An invalid ip address was specified
again. I tried with the IP address assigned to WiFi and I got again
Connection could not be established. Persistent rejection of the target computer 192.168.10.11:5002
I'm sure the computer network works since I'm using it for many other things including connecting to local TCP services and I'm sure both client and server code works since on a different PC I'm able to connect them setting localhost as client host variable value. Why I'm unable to use loopback connections in my code?
Where did I fail?
P.S. I allowed connection to server binary in Windows firewall rules, I also allowed outgoing connection for client binary also.
For anyone willing to inspect the server code here it is:
Server code
You are using the constructor with the "IPEndPoint" parameter. This constructor does not connect to the server automatically and you must call the "Connect" method before using the socket. That is why you are getting the error message "Operation not allowed on unconnected sockets". Also, you have provided a wrong IPEndPoint for client.
Please try this on client:
private void startClient(string host, int port)
{
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse(host), port);
ClientTCP = new TcpClient();
ClientTCP.Connect(serverEndPoint);
Reader = new StreamReader(ClientTCP.GetStream());
Listen = true;
listner = Listener();
}
You may need some exception handling here, but it should work now.
UPDATE:
The ipHostInfo.AddressList may have more than one addresses and just one of them is what you wanted. It is not necessarily the first one. I specified this manually and it works:
//string hostname = Dns.GetHostName();
//IPHostEntry ipHostInfo = Dns.GetHostEntry("127.0.0.1");
//IPAddress ipAddress = ipHostInfo.AddressList[0];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5002);
I have a very strange problem. I'm not able to find the IP Address of the client which my server receives data from. Below is my UDP Listener class.
The IPPacketInformation does not contain the IP. The clientEndPoint which I reference in my EndReceiveMessageFrom does neither.
When I
Console.Writeline(((IPEndPoint)clientEndPoint).Address);
I get the IP Address of the server. I have the server hosted on my own machine so I get my own IP Address. When I try to access clientEndPoint.remoteEndPoint it throws an error because the socket isn't connected (due to being UDP).
So basically, a client from an external IP is able to send data, but I can't answer the client since I'm not able to retrieve it's IP. Any help is appreciated!
public class UdpListener
{
private Socket s;
public byte[] ReceiveBuffer = new byte[2048];
public UdpListener()
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
s.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
s.Bind(new IPEndPoint(IPAddress.Any, 36200));
}
public void Listen()
{
try
{
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
}
private void Recv(IAsyncResult res)
{
try
{
Socket receiveSocket = (Socket)res.AsyncState;
EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
IPPacketInformation packetInfo;
SocketFlags flags = SocketFlags.None;
int udpMessageLength = receiveSocket.EndReceiveMessageFrom(res, ref flags, ref clientEndPoint, out packetInfo);
byte[] udpMessage = new byte[udpMessageLength];
Array.Copy(ReceiveBuffer, udpMessage, udpMessageLength);
Console.WriteLine(
"{0} bytes received from {1} to {2}",
ReceiveBuffer,
clientEndPoint,
packetInfo.Address
);
EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, ((IPEndPoint)receiveSocket.LocalEndPoint).Port);
s.BeginReceiveMessageFrom(ReceiveBuffer, 0, ReceiveBuffer.Length, SocketFlags.None, ref remoteEndPoint, Recv, s);
//Process data
RaiseDataReceived(new ReceivedDataArgs(packetInfo.Address, ((IPEndPoint)clientEndPoint).Port, udpMessage));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
throw;
}
}
public delegate void DataReceived(ReceivedDataArgs args);
public event DataReceived DataReceivedEvent;
private void RaiseDataReceived(ReceivedDataArgs args)
{
DataReceivedEvent?.Invoke(args);
}
}
I've tried to disable my firewall but that does not help. I've also done Port Forwarding on my router thus I can receive data from external clients.
EDIT to clarify the problem:
Server hosted on my machine behind a NAT with public IP 214.214.214.214.
The client is another machine, behind another NAT with public IP 910.910.910.910.
The client sends a message to the server, server receives it and able to read the content. When server get the IPEndPoint of the client, the displayed IP is 214.214.214.214 (IP of the server, not the Client)
EDIT Maybe I should say that I wasn't able to receive messages from clients on external networks until I ordered a "Dynamic IP" from my ISP. Still can't get the public IP of the source.
EDIT When using Wireshark and sniff a packet sent from external client to my server I can see it's the wrong src IP as well. In the picture below the src IP is my server IP and not the IP of the client that sent the data.
After several days of reading everything I possibly could on routers, network and writing different examples of Receive, ReceiveFrom, ReceiveMessageFrom, BeginReceive, BeginReceiveFrom, BeginReceiveMessageFrom, and ReceiveAsync - I've solved my issue.
I changed my router. I can now get the source IP of the external client using a very old router. The router I was using before was a new Docsis 3.1.
Why it works with an old router, I don't know, but for some reason, the Docsis 3.1 changed the source IP to its own IP before letting the UDP message to my machine.
With using the UdpClient class you can actually retrieve the remote endpoint when receiving a message.
I have used a solution like the following to solve this task:
public void StartServer()
{
var udpServer = new UdpClient(new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT));
udpServer.BeginReceive(new AsyncCallback(detectionCallback), udpServer);
}
private void detectionCallback(IAsyncResult ar)
{
var client = (ar.AsyncState as UdpClient);
if (client.Client == null) return;
var endPoint = new IPEndPoint(IPAddress.Any, ConnectionInformation.DETECTION_PORT);
var bytes = client.EndReceive(ar, ref endPoint);
Debug.WriteLine($"Detection request from: {endPoint}");
}
I have a system monitor app that needs to listen to messages from various UDP sockets on another machine. The other sockets continuously send heartbeats to this given IP/port.
This exception gets thrown when calling BeginReceiveFrom:
"A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied"
I shouldn't have to call connect because data is already getting sent to this ip endpoint. plus the data is coming from various sockets.
private Socket m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// bind socket
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
m_localEndPoint = new IPEndPoint(ipAddress, 19018);
m_socket.Bind(m_localEndPoint);
m_socket.BeginReceiveFrom(m_data,
m_nBytes,
MAX_READ_SIZE,
SocketFlags.None,
ref m_localEndPoint,
new AsyncCallback(OnReceive),
null);
}
private void OnReceive(IAsyncResult ar)
{
int nRead = m_socket.EndReceiveFrom(ar, ref m_localEndPoint);
}
I was able to get the desired behavior with the UdpClient class.
Your problem was you were binding to the IP assigned to you, you should bind to IP you want receive from - in your case:
m_socket.Bind(new IPEndPoint(IPAddress.Any, 12345));
I am currently using this function to send data from the server to the clients
private static void send_message(string ip, string message)
{
byte[] packetData = System.Text.UTF8Encoding.UTF8.GetBytes(message);
int port = 11000;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
client.SendTo(packetData, ep);
}
But this would mean a destination IP/port can only have one client open to receive the data, because having two clients open would mean one client can retrieve data that was meant for another (if I'm correct).. how do I solve this?
Receiving function:
private static Int32 port = 11000;
private static UdpClient udpClient = new UdpClient(port);
public static void receive_threaded()
{
Thread t = new Thread(() =>
{
while (true)
{
IPEndPoint remoteIPEndPoint = new IPEndPoint(IPAddress.Any, port);
byte[] content = udpClient.Receive(ref remoteIPEndPoint);
if (content.Length > 0)
{
string message = Encoding.UTF8.GetString(content);
parseMessage(message);
}
}
});
t.Start();
}
1) You should implement some kind of protocol so that your server has a "well known" port to accept connections. Use this port to inform your client ANOTHER port where the client must connect. Use a different port for each client.
Your client conects to the server at 11000. Your server assigns a unique port for the client, let's say 11001 for the firts client. Then the server opens a connection at 11001. The client closes connection at 11000 and opens a new connection at 11001 to receive the data.
2) Why UDP?
I don't see why you need to open a new socket at all. You already have each client's address and port, from the first packet they sent you. Just send a packet to that address:port. I absolutely don't get the other suggestion of setting up extra ports either.
newbie here. I successfully created a chat server using c# (server partial code below, got it somewhere though. rights goes to the owner) and clients able to connect and it is working as expected. now my question is can I make a client application that will connect from android?
private void loadchatserver()
{
try
{
// Initialise the ArrayList of connected clients
this.clientList = new ArrayList();
// Initialise the delegate which updates the status
this.updateStatusDelegate = new UpdateStatusDelegate(this.UpdateStatus);
// Initialise the socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Initialise the IPEndPoint for the server and listen on port 30000
IPEndPoint server = new IPEndPoint(IPAddress.Any, pubcommandport);
// Associate the socket with this IP address and port
serverSocket.Bind(server);
// Initialise the IPEndPoint for the clients
IPEndPoint clients = new IPEndPoint(IPAddress.Any, 0);
// Initialise the EndPoint for the clients
EndPoint epSender = (EndPoint)clients;
// Start listening for incoming data
serverSocket.BeginReceiveFrom(this.serverdataStream, 0, this.serverdataStream.Length, SocketFlags.None, ref epSender, new AsyncCallback(ReceiveServerData), epSender);
}
catch (Exception ex)
{
MessageBox.Show("Loadchatserver: " + ex.Message);
}
}
Sure you can.
Sockets are a global protocol that any major programming language supports.
Here's a nice tutorial for Sockets in Java (should work the same way with Dalvik - the Android implementation of Java):
http://docs.oracle.com/javase/tutorial/networking/sockets/