I'm building a C# chat program, yet I'm facing a problem with outside connection.
When the same computer connects both as server and as client, there seems to be no problem, yet when I try to host the connection on one computer, the other can't connect as a client.
here's the relevant code:
class Server:
public void Connect(string ipAddr, string port)
{
server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, Convert.ToInt32(port));
server.Bind(ipLocal);//bind to the local IP Address...
server.Listen(5);//start listening...
// create the call back for any client connections...
server.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
public void Disconnect()
{
server.Close();
server = null;
tempSocket = null;
}
public void OnClientConnect(IAsyncResult asyn)
{
try
{
if (server != null)
{
tempSocket = server.EndAccept(asyn);
WaitForData(tempSocket);
server.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
}
catch (ObjectDisposedException)
{
Debugger.Log(0, "1", "OnClientConnect: Socket has been closed.");
}
catch (Exception e)
{
MessageBox.Show(e.Message, "OnClientConnect Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
Client class:
public void Connect(string ipAddr, string port)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(ipAddr), Convert.ToInt32(port));
client.Connect(ipe);
clientListener = new Thread(OnDataReceived);
isEndClientListener = false;
clientListener.Start();
}
I have no idea what's wrong here. Hope you can tell me what's wrong.
Your issue is probably not code related. In order for other people outside your network to conenect to you, you need to port forward the port that you are connecting through on your router. You can find many tutorials here. You may also check to see if your connection is open through this tool.
From Wikipedia:
Port forwarding allows remote computers (for example, computers on the Internet) to connect to a specific computer or service within a private local-area network (LAN).
You must allow connections through your router to be able to connect to your chat server.
You need to give your computer a public IP address (maybe your router has this option) or implement port forwarding on your router.
A Public IP address would be the one of your router. Check out this site to find out your public IP whatismyipaddress.com. Your router can or cannot support the option to give its public IP address to your computer, however, your router should be able to do port forwarding. (Forwarding the data from a specific port to a specific computer, so when someone connects to your public IP. For example 93.93.93.93:3333 will be forwarded to your PC.)
Related
I am facing some problems with connect method while attempting to connect to a remote host. The main task deals with an industrial device which accepts TCP connections. The PC has two network cards with different networks families. It seems that the connect method is not able to reach the correct IP address. In fact, if I try to unplug the other network, everything works properly. Variables IPAddress and Port are set from the software. The error is:
System.NetSockets.SocketException (0x80004005): Unknown host at
System.Net.Dns.InternalGetHostEntry()
Below the code:
public void Connect()
{
int port;
try
{
int.TryParse(Port, out port);
socketMarking = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs telnetSocketAsyncEventArgs = new SocketAsyncEventArgs();
telnetSocketAsyncEventArgs.RemoteEndPoint = new IPEndPoint(Dns.GetHostEntry(IPAddress.Trim()).AddressList[0].MapToIPv4(), port);
telnetSocketAsyncEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(telnetSocketAsyncEventArgs_Completed);
socketMarking.ReceiveTimeout = 3000;
socketMarking.Connect(IPAddress, port);
streamWrite = new NetworkStream(socketMarking);
Connected = true;
}
catch (SocketException ex)
{
main.AddMessage("Socket error on IP " + IPAddress + ":" + Port + "-->"+ex.ToString());
}
}
Another discussion point is that debugging on two different PC everything works, but only on that one I have this kind of problem. All firewalls and possible protections are disabled.
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'm using the the examples provided by Microsoft to learn how to use TCP servers in C#. For TCPListener I use this http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx , and for TCPCLient I use this http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx (the examples are at the bottom of the page).
Until now I've managed to connect and send messages to other PCs connected to the same router. What I want now is to connect it to a PC outside my LAN network. How can I do that ?
I should also mention that this is the way that I use to connect PCs in LAN :
on ther server side:
public string LocalIPAddress()
{
IPHostEntry host;
string localIP = "";
host = Dns.GetHostEntry(Dns.GetHostName());
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
localIP = ip.ToString();
break;
}
}
return localIP;
}
private void Form1_Load(object sender, EventArgs e)
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
String localAddrString = LocalIPAddress();
Console.WriteLine(localAddrString);
IPAddress localAddr = IPAddress.Parse(localAddrString);
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
}
}
on the client side:
Int32 port = 13000;
String server = "192.168.X.X"; // here I manually introduce the IP provided by the server in the console
TcpClient client = new TcpClient(server, port);
I wish I could use a simple comment to give you this information but I cannot due to me only recently joining SO. You should ensure you have port forwarded (http://portforward.com/ will help you port forward), if you don't know how to you could use this easy-to-use port checker: http://www.yougetsignal.com/tools/open-ports/.
I created a multithreaded client-server chat application and want to test my application with multiple clients. I'm planning to create a simulator in client side which create a random port and IP. By that I mean my client system should run with multiple ports (without running multiple times).
I tried to find out the part of the code which gives client IP and port number in the client class, but couldn't figure it out. I only found the part which gives server IP and port.
This is my connection establishing part
private void cmdConnect_Click(object sender, System.EventArgs e)
{
try
{
//create a new client socket ...
m_socWorker = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
String szIPSelected = txtIPAddress.Text;
String szPort = txtPort.Text;
int alPort = System.Convert.ToInt16 (szPort,10);
System.Net.IPAddress remoteIPAddress = System.Net.IPAddress.Parse(szIPSelected);
System.Net.IPEndPoint remoteEndPoint = new System.Net.IPEndPoint(remoteIPAddress, alPort);
m_socWorker.Connect(remoteEndPoint);
}
catch (System.Net.Sockets.SocketException se)
{
MessageBox.Show ( se.Message );
}
}
and my data sending part
private void cmdSendData_Click(object sender, System.EventArgs e)
{
try
{
Object objData = txtData.Text;
byte[] byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString ());
m_socWorker.Send (byData);
}
catch(System.Net.Sockets.SocketException se)
{
MessageBox.Show (se.Message );
}
}
If you really need to set the client socket address before making a connection to the server, and it is often a valid scenario when one wants to force the kernel to bind to a specific local address on multihomed systems, you may call Socket.Bind() before you call Socket.Connect():
IPAddress localIPAddress = IPAddress.Parse(szLocalIP);
IPEndPoint localEndPoint = new IPEndPoint(localIPAddress, 0);
m_socWorker.Bind(localEndPoint);
m_socWorker.Connect(remoteEndPoint);
You may also explicitly specify the local port number in the IPEndPoint constructor, but you have to make sure, that the port is not in use. If you leave the port number equal to 0, then the system would pick an (almost) arbitrary free port number.
Note that you cannot just pick an arbitrary client IP address - it must be one of the addresses, configured on your system's enabled network interfaces. See the output of ipconfig /all for what is configured. You can assign more than one IP address to an interface if you simply want to test.
This is related to c# Sockets.
I'm developping a socket program. But there is one problem in my software.
I cannot connect to computers which are connected to internet via theirs local network. But I can connect to computers that are uses internet alone. Be more descriptive,
Consider that 5 computers connects internet via a modem that uses 1 ip address. When I try to reach one of these computers, API connects to modem via its ip address. But there is no response. Because a modem don't respond a computer request. By the mean, my API must reach a computer not only modem. And and an SocketException is thrown. What can I do about this problem?
The problem you're encountering is caused by NAT. This is used by routers who allow multiple clients to go online through one public IP address. None of the clients behind the router will 'know' or 'see' this, but it limits connectivity.
Clients can initiate a connection to the outside, but the other way around is basically* impossible. Unless you use port forwarding, where one or more ports are forwarded to a client behind the router. This way, connections can be initiated from the outside.
This requires configuration on the client side however, so the preferred way would be to let your clients connect to your server, since that will always be possible (firewalls neglected).
*: There also is a workaround, where you let a client connect to your server, and then pass the connection information to another client, so those clients can communicate with each other. This is called 'nat punching' and is used by torrent clients, for example.
you can try something like this.....
server Side Code
namespace Consoleserver
{
class Program
{
static void Main(string[] args)
{
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
Console.WriteLine("Waiting for a connection...");
Socket handler = listener.Accept();
Console.WriteLine("connected");
}
}
catch { Console.WriteLine("error");
}
}
}
Client side code :
namespace consoleclient
{
class Program
{
static void Main(string[] args)
{
try
{
IPHostEntry ipHostInfo = Dns.Resolve("59.178.131.180");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
Socket sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected <strong class="highlight">to</strong> {0}",
sender.RemoteEndPoint.ToString());
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
Console.Read();
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
Console.Read();
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
Console.Read();
}
}
catch
{ Console.WriteLine("could not <strong class="highlight">connect</strong> A"); }
}
}
}
I hope it will helps you