I am developing an action multiplayer game with the help of the System.Net.Sockets.UdpClient class.
It's for two players, so one should open a server and wait for incoming connections. The other player inputs the host IP and tries to send a "ping", to make sure a connection is possible and there is an open server. The host then responds with a "pong".
Once the game is running, both have to send udp messages to each other, so they both need the opponents ip address.
Of course the server could also input the clients IP, but that seems unneccessary to me.
How can I get the clients IP from the udp package when the "ping" message is received?
Here is my receiving code (server waiting for ping):
private void ListenForPing()
{
while (!closeEverything)
{
var deserializer = new ASCIIEncoding();
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] recData = udp.Receive(ref anyIP);
string ping = deserializer.GetString(recData);
if (ping == "ping")
{
Console.WriteLine("Ping received.");
InvokePingReceiveEvent();
}
}
}
In your example, when a client connects, the anyIP IPEndPoint object will contain the address and port of the client connection.
private void ListenForPing()
{
while (!closeEverything)
{
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] recData = udp.Receive(ref anyIP);
string ping = Encoding.ASCII.GetString(recData);
if (ping == "ping")
{
Console.WriteLine("Ping received.");
Console.WriteLine("Ping was sent from " + anyIP.Address.ToString() +
" on their port number " + anyIP.Port.ToString());
InvokePingReceiveEvent();
}
}
}
http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.receive.aspx
Related
I´m trying to make a Windows Service which waits a conexion but not in a determinate port. It has to wait a conexion and then, get the port which the sender is trying to connect. The check if the port is free is done by me in the Sender part.
Listener:
Here is where I need help. I need to do something to don´t need a port to inicializate the conexion.
{
// Get Host IP Address that is used to establish a connection
// In this case, we get one IP address of localhost that is IP : 127.0.0.1
// If a host has multiple addresses, you will get a list of addresses
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, port);
try
{
// Create a Socket that will use Tcp protocol
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// A Socket must be associated with an endpoint using the Bind method
listener.Bind(localEndPoint);
// Specify how many requests a Socket can listen before it gives Server busy response.
// We will listen 10 requests at a time
listener.Listen(10);
Console.WriteLine("Waiting for a connection...");
Socket handler = listener.Accept();
// Incoming data from the client.
string data = null;
byte[] bytes = null;
while (true)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
//_installerProcess = (Process) BinarySerialization.Deserializate(bytes);
//Console.WriteLine("Proceso recibido");
data += Encoding.ASCII.GetString(bytes, 0, bytesRec);
if (data.IndexOf("<EOF>") > -1)
{
break;
}
break;
}
{...}
Sender:
Here is where i check te port and where I send the data.
public static void StartClient(String toSend)
{
byte[] bytes = new byte[1024];
try
{
// Connect to a Remote server
// Get Host IP Address that is used to establish a connection
// In this case, we get one IP address of localhost that is IP : 127.0.0.1
// If a host has multiple addresses, you will get a list of addresses
IPHostEntry host = Dns.GetHostEntry("localhost");
IPAddress ipAddress = host.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, FreeTcpPort() );
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
// Connect to Remote EndPoint
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes(toSend);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
{...}
}
static int FreeTcpPort()
{
TcpListener l = new TcpListener(IPAddress.Loopback, 0);
l.Start();
int port = ((IPEndPoint)l.LocalEndpoint).Port;
l.Stop();
return port;
}
I'm trying to broadcast a message from server to a remote client, my problem is that I'm not able to receive the message on the client, the approach I'm currently playing with is as follows:
//Server
UdpClient udpServer = new UdpClient();
udpServer.Client.Bind(new IPEndPoint(IPAddress.Any, port));
var send = Task.Run(() =>
{
var to = new IPEndPoint(IPAddress.Broadcast, port);
while (true)
{
var response = gameWorld.GetStateJson();
var responseInBytes = Encoding.ASCII.GetBytes(response);
udpServer.SendAsync(responseInBytes, responseInBytes.Length, to);
Console.WriteLine(response);
gameWorld.Update();
}
});
send.Wait();
And for the client:
//Client
UdpClient receivingUdpClient = new UdpClient(8081);
while (true)
{
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Parse("11.111.111.111"), 0);
try
{
byte[] receiveBytes = receivingUdpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine(returnData.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
So the current client code works as expected, but only for my LAN (if I understand correctly), I'm not sure what should I change in order to be receiving the messages over the internet "globally", advice would be highly appreciated.
Side question: does the server code as is broadcast the data "globally" ? Or is it also for my LAN only?
EDIT: Is this somehow possible or do I have to send data to each client explicitly, even though they're the same for all
I have a c# client. The client's task is to log in to the server.
The issue is:
When I want to log in, I use a TCP socket which is created when the "wpf" window is initialized. After sending data using the socket once, everything is ok but when I want to send data again, using the same socket, this exception pops up:
System.ObjectDisposedException: 'Cannot access a disposed object.
Object name: 'System.Net.Sockets.Socket'.'
After some testing, I found out that the problem is caused by the Socket.Receive function. I checked the socket before the function was called, and the socket was connected (Socket.Connected == true), after returning from the function, the socket wasn't connected (Socket.Connected == false)
private static Socket ConnectSocket(string server, int port)
{
Socket s = null;
// Get host related information.
IPHostEntry hostEntry = Dns.GetHostEntry(server);
// Loop through the AddressList to obtain the supported AddressFamily.
foreach (IPAddress address in hostEntry.AddressList)
{
//attempting to connect.
IPEndPoint ipe = new IPEndPoint(address, port);
//making a temp socket to check the connection (if something went wronge/ the server isnt active)
Socket tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
// attempting connection.
tempSocket.Connect(ipe);
}
catch (Exception)
{
Console.WriteLine("Request timed out");
}
//if we connected to the server, we are ok to continue.
if (tempSocket.Connected)
{
s = tempSocket;
break;
}
//else the connection isnt successful (the server might not respond) we need to try again.
else
{
continue;
}
}
Globals.SOCKET = s;
return s;
}
//This func will send a request to the server and returns the server's response.
public static string SocketSendReceive(string server, int port, string request, Socket socket = null)
{
Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
Byte[] bytesReceived = new Byte[256];
string response = "";
// Create a socket connection with the specified server and port.
if (socket == null)
socket = ConnectSocket(server, port);
using (socket)
{
// If the connection faild and couldnt maintain a socket.
if (socket.Connected == false)
return ("Connection failed");
// Send request to the server.
socket.Send(bytesSent, bytesSent.Length, 0);
// Receiving the packet from the server.
int bytes = socket.Receive(bytesReceived, bytesReceived.Length,0);//***The problem occures Here***
response = response + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
}
return response;
}
the second function is the one that sends and receives data from the server.
the first one is just connecting and creating a socket
Thanks for your help!
-Anthon
Change
socket.Receive(bytesReceived, bytesReceived.Length,0)
To
socket.Receive(bytesReceived, 0, bytesReceived.Length)
When I start multiple instances of application listening on the same UDP port, only the last receives datagrams. Is there any way to send data to all instances other than sending broadcast (broadcasts are received in all instances)?
My application (commandline):
UdpClient client = new UdpClient();
client.Client.SetSocketOption(
SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
client.Client.Bind(new IPEndPoint(0, 7894));
client.EnableBroadcast = true;
Console.WriteLine("Press key to send datagram");
while (true)
{
if (client.Available > 0)
{
IPEndPoint ep = null;
client.Receive(ref ep);
Console.WriteLine("Received");
}
if (Console.KeyAvailable)
{
Console.ReadKey();
client.Send(new byte[] { 1 }, 1, new IPEndPoint(IPAddress.Parse("127.0.0.1"), 7894));
Console.WriteLine("Sent");
}
}
A port can only been owned by one application/process at a time, so a datagram sent to that port can only be received by one instance.
A clean way would be for each listener to use an ephemeral port and register it with the sender application.
i use in UDPClient in c#. i invoke the receive function, but the when i am running the app. the program enter to eternity loop. Why is this phenomenon? Maybe because no data were available on this port? what can i do?
I write the following code:
UdpClient udpClient = new UdpClient(623);
try
{
udpClient.Connect("10.0.0.16", 623);
// Sends a message to the host to which you have connected.
Byte[] sendBytes = Encoding.ASCII.GetBytes("Is anybody there?");
udpClient.Send(sendBytes, sendBytes.Length);
// Sends a message to a different host using optional hostname and port parameters.
UdpClient udpClientB = new UdpClient();
udpClientB.Send(sendBytes, sendBytes.Length, "10.0.0.16", 623);
//IPEndPoint object will allow us to read datagrams sent from any source.
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// Blocks until a message returns on this socket from a remote host.
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
// Uses the IPEndPoint object to determine which of these two hosts responded.
Console.WriteLine("This is the message you received " +
returnData.ToString());
Console.WriteLine("This message was sent from " +
RemoteIpEndPoint.Address.ToString() +
" on their port number " +
RemoteIpEndPoint.Port.ToString());
udpClient.Close();
udpClientB.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
thanks
I suspect it's because of no data, but to test this, you could try implementing 'BeginRecieve' instead of recieve. MSDN has an example:
http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx