Goal
I'm making a chat application for android and am currently testing with 2 phones which must eventually work for a few thousand users.
Problem
I get a ConnectionException saying "Connection refused" whenever the 2 phones try connecting to each other via sockets.
Current Design
Each phone starts a ServerSocket, calls the accept() method waiting for some Socket to connect to, and whichever phone sends a message first will create a client Socket. I'm certain the IP addresses I'm using are correct (they're actually both using the same external IP).
I believe the problem is with the ports. I generate a port number at random, and if it's free to use, I say ServerSocket s = new ServerSocket( randomPortNumber ).
What I think is the source of the problem
What I think is the problem is this port number is one sitting behind an NAT router. So when a Socket tries to connect to the ServerSocket using something like Socket socket = new Socket( ip, serverSocketRandomPortNumber ), it will try to connect to the NAT router and feed it this port number which won't work since the router itself is not listening on this port, but the phone behind the router is.
Questions and thoughts
My question is, how do I deal with this problem?
Do I have to change my design?
If I must, an alternative design I'm thinking of is using a single ServerSocket on a web host and use it to redirect messages sent from client sockets to other client sockets.
I'd be implementing the server-side in php referencing something along these lines:
http://php.net/manual/en/sockets.examples.php
And I would still use Java for the client-side.
Since one of the phones is behind a NAT router, nothing can initiate a connection to it unless port forwarding (or some other techniques) is enabled on the router.
The usual way a chat application is implemented is, there is a common server that all clients will connect to.
You don't have to write your own chat server (unless you really want to). I suggest using the XMPP protocol. A list of already made servers here. On the client side (Android), you can find libraries you can use here.
Related
I've got a server written on Java with ServerSocket.
And I have a client that is over a corporative firewall that is blocking everything except common ports.
I've started server on SMTP port (#25).
The user with firewall connects to it and so far everything is ok.
Then the server processes ServerSocket.accept(). And as far as I understand it creates a socket on a random port (every time the port number is different). And fails because of a firewall.
My question is - how can I make ServerSocket.accept() to choose a port for a socket from my white-list? I understand that it will not suite for massive online, but I want to make one my friend to be able to connect to my server.
Is it possible? And how?
server socket doesn't choose random port. it is the client socket which chose the random port. my guess is that your fire wall is smart and it knows to detect if the connection is approved by some sort of dpi (deep packet inspection).
if you want to mislead it, you can try to run data which looks like smtp in the first 2-3 packets and then switch to your protocol.
Another option it to use a kind of a connector outside the system, in this case both machines are clients which are connected through a 3rd client (there are many such proxies)
The title may sound a bit odd but I wanted to keep the title short.
So I have here a Socket which connects to some server for testing purpose.
Now when I get the IP from the client socket (server side) it will give me one IP (external one).
But I have another IPv4 dedicated IP, can I use that as source?
If you want a Socket to originate on a particular IP/interface, you should be able to bind() it to the appropriate address before issuing the connect().
Ok so I've found out Sockets are not serializable... so I cant pass them over TCP...
My problem is I have a homework assignment where I have 10 servers that must listen on one socket(lets call it request). For input from any of x number of clients that write to that socket. Then after one of the server processes reads a message from request it must communicate with that client over its own socket...
I tried making each server socket and the request socket on the server side, then passing those to the clients when they connected to the server... but this doesn't work...
Any tips on how I might do this? Having TCP not be 1-1 is really toying with me here.
Passing a socket over a TCP connection is like trying to pass a telephone over a telephone call, or trying to fax your fax machine. What you need to do is organize another connection between the parties concerned.
EDIT: In fact your assignment as stated doesn't even make sense:
I have 10 servers that must listen on one socket(lets call it
request).
That's not even correct terminology. Servers listen at ports, not sockets, and 10 servers listening at one port is impossible. They must each have their own port.
For input from any of x number of clients that write to that socket.
See above. Clients don't write to 'that socket'. They create their own socket that is connected to the server port, and they write to that.
Then after one of the server processes reads a message from request it
must communicate with that client over its own socket
If the server has received a connection from a client it already has a socket representing its endpoint to that connection. So all the server has to do is write the response back to the same socket it read the request from.
In short you have a major terminology problem, but you don't have a software problem at all.
Passing sockets seems crazy to me. If you're trying to write a better server, you'll have a hard time beating Netty. I'd recommend giving it a look.
I've a server (Java) and a number of clients (c++), connected by sockets.
I would like to set the ports automatically.
Assuming the IP is already known.
In the Java side I can make :
ServerSocket s = new ServerSocket(0);
So now I've a random free port on the server.
How can I know in the C++ side, what port is the server listening to?
I think is not possible, if you want establish a connection with a server, you must know in which port is the server listening, there are programs like nmap that shows you a list of opened ports in a server, but a server can have many opened ports at the same time and then, How do you know what is the port opened by your server? and in any case, is too slow and inefficient to call external tool, read and parse its output. For what reason do you need a random port service?
Other option can be get the opened socket in the server side calling to s.getLocalPort() and send it via UDP for any listening node in the network with broadcasting, and re-program the client side to listen in broadcast and when it receives a message, check if it is a port number and connect to the server using that port.
You can't, not reliably. In IP, a machine is identified by an address. A server (ie, a service) is identified by an address and a port. You clients need some form of "known service" that they can connect to.
If you, for whatever reason, absolutely want to have dynamic listening port, you could combine it with a "locator" service on a known port. For instance, have a web service/servlet on the standard http port (80). Your clients connect to the "locator" service (always on port 80) and asks which port your application is currently listening on. This is a not entirely uncommon pattern. RMI works is a similar way where you have a registry on a known port. Clients connect to the registry and asks for the location of RMI endpoints.
I created a small chat program, that works flawlessly when client & server are run on the same computer (and probably network, too).
However, as soon as I try to connect to another computer over the internet, the socket connection simply times out.
Is this because of firewalls / routers, etc?
And how can I connect a ServerSocket & Socket over the internet?
However, as soon as I try to connect to another computer over the internet, the socket connection simply times out. Is this because of firewalls / routers, etc?
Yes, most likely. You're running into the NAT problem: essentially, the same externally visible IP address maps to many internally visible endpoints, and external endpoint doesn't know which internal endpoint to give your socket request to.
The easiest way around this is to have both your clients connect to a third party which both of them can see, and then have the third party mediate the communication. This is how most instant-messaging protocols work, for example.
If you have no way to control a third-party entity like that, an alternative to directly connect two clients is to have both clients open up an agreed-upon port, and then map communications on that port to their own internal endpoint. This provides the missing link that the externally visible endpoint (e.g. your home router) needs to deliver the communication to its intended destination.
If your server is behind a NAT router box (and most home computers are, especially if you use WiFi), then it won't be reachable from the outside unless you set up your router to port forward to that server.
What's the IP of your server computer? If it's 192.168.x.x or 10.x.x.x, then it's a non-routable address and can't be reached from outside.
Assuming with running on the same computer you mean that you tell the client the server is at 127.0.0.1 / localhost, it shouldn't be a problem in your code but because of firewalls or routers. If your server is behind a router performing masquerading (i.e., the server doesn't have a public but private IP address like 192.168.x.y for instance), you have to configure the router to pass a connection from the internet to the computer running the server.
Another reason why it doesn't work might be the way you bind your server to the interface. If you specify 127.0.0.1 there, the server will only listen for requests coming from the same system. If you don't specify an address, it will listen on all interfaces.
Edit Your comment indicates that you indeed have the NAT problem like others said. Configuring your router accordingly is probably the easiest solution.
First, test to see if it really works on a LAN; it sounds like you're just assuming it does.
If it works on your local network, perhaps it's failing because the server lacks a public IP, and is running behind a NAT'ing router.