I'm trying to run a game TCP/UDP server on my computer. It's working fine within the local network, but when I'm trying to run the server with my public IP, it just doesn't work. I've tried to disable the firewall in my router, set port forwarding for port 17000 and added a firewall rule to my computer. I've also bound IP to my computer.
I've checked client calls with Wireshark and I found out that the client (Unity game) is sending data to my IP, but it's giving TCP Retransmission error for every TCP packet that it is trying to send.
There is some of the code from server and client.
Server IP is set to 192.168.0.*:17000
And the client is connecting to my IP with port 17000
SERVER:
public static void Start(byte _maxPlayers)
{
MaxPlayers = _maxPlayers;
Port = 17000;
Console.WriteLine("Starting server..");
InitializeServerData();
tcpListener = new TcpListener(GetLocalIPAddress(), Port);
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(new AsyncCallback(TCPConnectCallback), null);
udpListener = new UdpClient(Port, GetLocalIPAddress().AddressFamily);
udpListener.BeginReceive(UDPReceiveCallback, null);
Console.WriteLine($"Server started on {tcpListener.LocalEndpoint}.");
}
CLIENT:
public void Connect()
{
socket = new TcpClient
{
ReceiveBufferSize = dataBufferSize,
SendBufferSize = dataBufferSize
};
receiveBuffer = new byte[dataBufferSize];
socket.BeginConnect(instance.ip, instance.port, ConnectCallback, socket);
}
private void ConnectCallback(IAsyncResult _result)
{
socket.EndConnect(_result);
if (!socket.Connected)
return;
stream = socket.GetStream();
receivedData = new Packet();
stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallback, null);
}
So I've found out, that I have two-router set up, and because I was forwarding port 17000 just on one router, it didn't work.
Related
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 am making a simple server application to send messages to all clients that connected at a certain time. Basically, I start a server, which grabs its internal IP and port and listens. Then on clients, they connect to my routers external IP and port, and send a tcp packet. The problem is this, my client application is never able to successfully send a packet out. It times out.
Here is the code for the server:
...
try
{
server_listener = new TcpListener(IPAddress.Parse(192.168.0.xxx), 5000);
server_listener.Start();
isRunning = true;
Console.WriteLine("[{0}] The server is now listening for all clients!", DateTime.Now);
Listen();
}
...
void Listen() // Listen to incoming connections.
{
while (isRunning)
{
TcpClient tcpClient = server_listener.AcceptTcpClient(); // Accept incoming connection.
(new Thread(() => SetupAndListen(tcpClient))).Start(); //handle in a new thread
}
}
And Client:
//attempt to connect once...
string textToSend = "CA";
try
{
//---create a TCPClient object at the IP and port no.---
TcpClient client = new TcpClient(EXTERNAL_SERVER_IP, 5000);
NetworkStream nwStream = client.GetStream();
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(textToSend);
//---and see if connected---
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
//---read back the text---
byte[] bytesToRead = new byte[client.ReceiveBufferSize];
int bytesRead = nwStream.Read(bytesToRead, 0, client.ReceiveBufferSize);
Debug.Log("Received : " + Encoding.ASCII.GetString(bytesToRead, 0, bytesRead));
client.Close();
}
catch { }
The server runs fine, no errors, and appears to be listening properly from what I see in the debugger, but none of my clients work. Moreover, if EXTERNAL_SERVER_IP is changed to localhost, or 192.168.0.xxx it does infact work. Any thoughts as to what is going on?
Just to note, the port 5000 has indeed been forwarded.
Are you trying to send a packet to your server from inside your network, by using your external IP? This will not work with many SoHo routers. The router feature you are asking for is called NAT Loopback.
When I try to create a new TcpClient I am getting a SocketException, here is my code:
public void TcpOpenConnection()
{
// The next line is where the exception is occurring.
tcpClient = new TcpClient(ipAddress, port);
connected = true;
}
I have checked to make sure the port is open with netstat -a in cmd, and I even made another function to check if the port is open:
public static bool PortCheck(int port)
{
bool portOpen = false;
IPGlobalProperties ipGlobalProperties = IPGlobalProperties.GetIPGlobalProperties();
TcpConnectionInformation[] tcpConnInfo = ipGlobalProperties.GetActiveTcpConnections();
foreach (var tcpConn in tcpConnInfo)
{
if (tcpConn.LocalEndPoint.Port == port)
{
portOpen = true;
break;
}
}
return portOpen;
}
which returns true. The exception that I am getting is a SocketException and it is saying the machine I am trying to connect to is actively refusing the connection. What could be the issue here? I have also tried other ports, with no luck.
If you need more info please ask, and I will gladly supply more.
The exception that I am getting is a SocketException and it is saying the machine I am trying to connect to is actively refusing the connection.
This is likely an indication that the target host isn't listening on the port which could be caused by a number of reasons:
The router of the server's network is not correctly port-forwarded
The router's firewall / server's firewall is blocking the connections
The server and the client are not using the same port
The server is misconfigured
The list goes on... but essentially, this error means that the server isn't allowing the connection.
If the port is open and you try to connect to. You get SocketException because there is nothing for get the client connection.
So you need to host a Tcplistner on this port.
static void StartServer()
{
int port = 150;
TcpListener listner = new TcpListener(IPAddress.Any, port);
listner.Start();
// This line waits the client connection.
TcpClient remote_client = listner.AcceptTcpClient();
// do something with remote_client.
}
And you can connect to.
static void StartClient()
{
int port = 150;
IPAddress ip = IPAddress.Parse("127.0.0.1");
TcpClient client = new TcpClient();
client.Connect(ip, port);
// Do something with client.
}
I seem to be having a hard time figuring out how to get my client app to automatically connect to a server app running on a separate machine on my LAN.
Right now the only way I'm able to get the client to connect to the server is by manually specifying the server's IP address in code:
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = neIPEndPoint(IPAddress.Parse("Server IP address goes here"), 8888);
My server app uses a TCP Listener, so I figured my client could do something similar, to be able to find the server, but I can't figure out how to implement it in code.
Code from my server app for finding the client to connect to:
private TcpListener tcpListener;
private Thread listenThread;
private int connectedClients = 0;
private delegate void WriteMessageDelegate(string msg);
public Form1()
{
InitializeComponent();
Server();
}
private void Server()
{
this.tcpListener = new TcpListener(IPAddress.Any, 8888);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
I've tried using a TextBox that the user can manually enter their server's IP address into (since they wouldn't have access to the code), but I think an automatic connection would be much more user friendly, especially since I don't know how to permanently save the user's server IP address if they use the above method of setting the IP for the client to connect to.
So, my question is: What would be the best method for me to enable my client to automatically connect to a server running on my LAN?
Thanks,
Patrick
UPDATE
I tried implementing the code for a UDP broadcast, but I can't seem to get it working.
Here is what I've added to my client (Along with the client code I had in there before):
public partial class Console : Form
{
//FIND SERVER
private void FindServer()
{
var Client = new UdpClient();
var RequestData = Encoding.ASCII.GetBytes("SomeRequestData");
var ServerEp = new IPEndPoint(IPAddress.Any, 0);
Client.EnableBroadcast = true;
Client.Send(RequestData, RequestData.Length, new IPEndPoint(IPAddress.Broadcast, 8888));
var ServerResponseData = Client.Receive(ref ServerEp);
var ServerResponse = Encoding.ASCII.GetString(ServerResponseData);
Console.WriteLine("Recived {0} from {1}", ServerResponse, ServerEp.Address.ToString());
Client.Close();
}
// SEND MESSAGES TO SERVER (VIA USER INTERACTION)
private TcpClient client = new TcpClient();
private IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("My IP Address was here (I tried changing it to "broadcast" as well"), 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();
}
Here is what I've added to my server code:
private void BroadcastToClients()
{
var Server = new UdpClient(8888);
var ResponseData = Encoding.ASCII.GetBytes("SomeResponseData");
while (true)
{
var ClientEp = new IPEndPoint(IPAddress.Any, 0);
var ClientRequestData = Server.Receive(ref ClientEp);
var ClientRequest = Encoding.ASCII.GetString(ClientRequestData);
Console.WriteLine("Recived {0} from {1}, sending response", ClientRequest, ClientEp.Address.ToString());
Server.Send(ResponseData, ResponseData.Length, ClientEp);
}
}
I'd imagine there must be some conflicting code in there, but since I'm so new to this, I can't seem to figure it out...
UPDATE
I've still not managed to make any progress on this. Anyone out there that might be able to chime in and help me figure out why this isn't working for me?
Your client app can send a broadcast on the local subnet, on startup, 'asking for server'.
Your server will be listening for that message, and replies to the client.
Now the client knows the server's IP address and can start the TCP connection.
You have it here: C# How to do Network discovery using UDP Broadcast
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.