Make a connection using an external IP address in Java - java

I'm trying to build a chat program. I wrote the code and everything worked and still works great when I'm using my computer and connecting using 127.0.0.1. I also succeeded to connect successfully between my laptop and my computer, which run on the same router. (I used an internal IP address to do this, 10.0.0.3).
Now I'm trying to make a connection between my router and other routers. And to this I'm trying to connect to an external IP address. I do the port forwarding part through my router and I also made a static IP. When I run the code I always get a "connection refused error".
Here is the code:
MainServer.java:
import java.util.*;
import java.io.*;
import java.net.*;
public class MainServer {
private ArrayList<Socket> sockets;
public MainServer() {
ServerSocket server_socket;
try {
server_socket = new ServerSocket(5005);
sockets = new ArrayList<Socket>();
System.out.println("server is now running");
while(true) {
Socket socket = server_socket.accept();
sockets.add(socket);
try {
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.println("---you are connected to the server---\r\n");
writer.flush();
} catch(Exception e) {e.printStackTrace();}
System.out.println("server connected to " + socket.getInetAddress());
Reader reader = new Reader(socket);
Thread thread = new Thread(reader);
thread.start();
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public static void main(String[] args) {
MainServer server = new MainServer();
}
class Reader implements Runnable {
Socket socket;
public Reader(Socket socket) {
this.socket=socket;
}
public void run() {
while(true) {
try {
InputStreamReader stream_reader = new InputStreamReader(socket.getInputStream());
BufferedReader reader = new BufferedReader(stream_reader);
while(true) {
String str = reader.readLine();
if(str==null)
continue;
System.out.println("message from the client " + socket.getInetAddress() + ": " + str);
send_back_message(str);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void send_back_message(String str) {
try {
for(Socket send_to_socket: sockets) {
PrintWriter writer = new PrintWriter(send_to_socket.getOutputStream());
writer.println(send_to_socket.getInetAddress()+ ": " + str);
writer.flush();
}
} catch(Exception e) {e.printStackTrace();}
}
}
}
Client.java:
public Client() {
frame = new JFrame();
JPanel panel = new JPanel();
chat = new JTextArea(20,40);
chat.setEditable(false);
JScrollPane scroll = new JScrollPane(chat);
text = new JTextField(32);
JButton send = new JButton("Send");
send.addActionListener(new SendButtonListener());
panel.add(scroll);
panel.add(text);
panel.add(send);
frame.getContentPane().add(panel);
frame.setSize(500,500);
frame.setVisible(true);
try {
socket = new Socket("77.126.189.65",5005);
} catch (Exception e) {
e.printStackTrace();
}
Thread thread = new Thread(new ClientReader());
thread.start();
}
public static void main(String[] args) {
Client client = new Client();
}
class SendButtonListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
try {
PrintWriter writer = new PrintWriter(socket.getOutputStream());
writer.println(text.getText());
writer.flush();
text.setText("");
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
class ClientReader implements Runnable {
public void run() {
try {
InputStreamReader stream_reader = new InputStreamReader(socket.getInputStream());
BufferedReader reader = new BufferedReader(stream_reader);
while(true) {
String str = reader.readLine();
if(str==null)
continue;
chat.setText(chat.getText() + str + "\r\n" );
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
I also tried this tool. When I run the MainServer file and try the tool, I get a positive answer. I also get a positive on my own Eclipse. When my MainServer makes a successful connection, it prints a message about it using these lines:
Socket socket = server_socket.accept();
System.out.println("server connected to " + socket.getInetAddress());
So every time I'm clicking the "check" button in the tool above, I get a message in my Eclipse console (system.out.println part):
server connected to /69.163.149.200
Therefore I think the problem is probably not connected to the MainServer or the portforwading/firewall/static IP.
I also thought maybe the problem occurs because I'm trying connecting from my own router device to my own router. I will leave the MainServer file open for the next half hour so if someone can run the Client.java on his computer it will be helpful.

What you trying to do is a bit weird but it is possible.
You just need to know if your router supports NAT Loopback / NAT Reflection and activate it.
NAT-loopback
Also known as NAT-hairpinning or NAT-reflection. NAT-loopback is a
feature in many consumer routers which allows a user to connect to
its own public IP address from inside the LAN-network. This is
especially useful when a website (with domain) is hosted at that IP
address.

You won't be able to do this without configuring your router appropriately. Most routers do not allow (by default) incoming connections on their external (WAN) port. If you want to allow this, you'll need to go into your router configuration and configure it to allow connections on the external IP for the specific port you are using. Then, you'll have to configure the router to redirect that incoming connection from the external IP address/port to the internal IP address/port of your actual server.
This is frequently how online gamers set up servers in their own home. It is also how many people connect to their own internal networks from the outside world.

Before anything, set up a static IP (like 192.168.1.6) internally.
If youu want to connect via an external IP, there are two ways:
If you have a router, use port forwarding.
If you have a dongle, no need to port forward; you can directly access the server. Just give the dongle's external IP (to find that, use a what's-my-IP service like this one) and a port number (any). (Dongles are not blocked by any ISP.)

You can add your internal IP address along with your server name to /etc/hosts, for example, if you have external IP 10. 10. 123. 123, and with the server name YOURCOMPUTER_1.XXX.XXX, you want to connect inside network, you can add:
127.0.0.1 YOURCOMPUTER_1.XXX.XXX to your /etc/hosts

Related

Socket connection not workin in flutter release apk

I am new to working with sockets, and I am working on this project where a connection between my android flutter app and a java server is needed, to do this I am trying socket programming.
The server code is fairly simple, I create a new thread for every client connected and I give them a bunch of URLs, later on, this should be replaced by a query result. here is the java code:
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class CrawlitServer {
// The port number on which the server will listen for incoming connections.
public static final int PORT = 6666;
//main method
public static void main(String[] args) {
System.out.println("The server started .. ");
// Create a new server socket
ServerSocket serverSocket = null;
try {
serverSocket = new ServerSocket(PORT);
} catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
// Listen for incoming connections and create a new thread for each one
while (true) {
try {
new CrawlitServerThread(serverSocket.accept()).start();
}
catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
public static class CrawlitServerThread extends Thread {
private final Socket socket;
public CrawlitServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
List<String> list = new ArrayList<>();
//assign a value to list
list.add("http://www.google.com");
list.add("http://www.yahoo.com");
list.add("http://www.bing.com");
list.add("http://www.facebook.com");
list.add("http://www.twitter.com");
list.add("http://www.linkedin.com");
list.add("http://www.youtube.com");
list.add("http://www.wikipedia.com");
list.add("http://www.amazon.com");
list.add("http://www.ebay.com");
list.add("http://stackoverflow.com");
list.add("http://github.com");
list.add("http://quora.com");
list.add("http://reddit.com");
list.add("http://wikipedia.org");
try {
// Get the input stream from the socket
DataInputStream inputStream = new DataInputStream(socket.getInputStream());
Scanner scanner = new Scanner(inputStream);
DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
PrintWriter writer = new PrintWriter(outputStream, true);
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
System.out.println("Received Message from client: " + line);
writer.println(list + "\n");
}
}
catch (Exception e) {
System.out.println("Error: " + e.getMessage());
}
}
}
}
Now I run this server and connect to it using sockets in Flutter, I give it the IP address I get from the ipconfig command, and here is the dart code:
import 'dart:async';
import 'dart:io';
//Utilities that manage connections with server sockets.
//ServerUtil Class
class ServerUtil {
static const port = 6666;
static const host = MY_IP_GOES_HERE;
static late Socket socket;
static bool connected = false;
//a list of urls returned by the server
static List<String> urls = [];
//Constructor
ServerUtil() {
//Initialize the socket.
Socket.connect(host, port).then((Socket sock) {
socket = sock;
connected = true;
socket.listen(dataHandler,
onError: errorHandler, onDone: doneHandler, cancelOnError: false);
//send a message to the server.
}).catchError((e) {
print("Unable to connect: $e");
});
}
//Query method that sends a message to the server. The server will return a list of urls.
//The urls will be added to the urls list.
//The urls list will be returned.
static Future<List<String>> query(String userQuery) async {
urls.clear();
//check if socket is connected.
if (connected) {
//send the query to the server.
socket.writeln(userQuery);
await Future.delayed(const Duration(milliseconds: 200));
print(urls);
return urls;
}
//if socket is not connected, wait for 5 seconds and try again.
await Future.delayed(const Duration(milliseconds: 50));
return query(userQuery);
}
//Handles data from the server.
void dataHandler(data) {
//String of received data.
String dataString = String.fromCharCodes(data).trim();
//remove first and last character from the string.
dataString = dataString.substring(1, dataString.length - 1);
//remove all the whitespace characters from the string.
dataString = dataString.replaceAll(RegExp(r'\s+'), '');
urls = dataString.split(',');
}
//Handles errors from the server.
void errorHandler(error, StackTrace trace) {
print(error);
}
//Handles when the connection is done.
void doneHandler() {
socket.destroy();
}
}
This works perfectly fine while using a debug apk running it on my real Note 9 device. The problem however is that when I build a release apk and try it out, nothing happens.
The way I set it up is that I wait for the query method in an async and then I send the result to a new screen and push that screen into the navigator.
But in the release apk nothing happens, the new screen doesn't load.
So this leads me to my first question:
Is there a way to debug a release apk? see what exceptions it throws or print some stuff to console?
I have the server running on my Laptop, and the app runs on my phone which is on the same WIFI network.
My second question is:
Do I need to enable some sort of option with my router or my laptop to allow my phone to connect? it does connect in debug mode without any modifications
I tried some random things, like using 'localhost' instead of my IP, as I would normally connect say with a java client for example, but it didn't work.
My last question is:
Does the release apk or like android OS prevent connections to local hosts, maybe because it thinks it is not secure? but then it still connects in debug mode.
Thank you for your time.

How to listen to port 80 by using Java Socket

I have a server whose port 80 is for occupied by HTTP transactions. I wanted to see the traffic in that port and I tried to use a socket program to listen to that port.
public Server(int serverPort) throws IOException {
super(serverPort);
try {
while (true) {
Socket socket = accept();
new ServerThread(socket);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
close();
}
}
// inner-class ServerThread
class ServerThread extends Thread {
private Socket socket;
private BufferedReader in;
private PrintWriter out;
// Ready to conversation
public ServerThread(Socket s) throws IOException {
this.socket = s;
in = new BufferedReader(new InputStreamReader(socket
.getInputStream(), "UTF-8"));
out = new PrintWriter(socket.getOutputStream(), true);
start();
}
// Execute conversation
public void run() {
try {
// Communicate with client until "bye " received.
while (true) {
String line = in.readLine();
if (line == null || "".equals(line.trim())) {
break;
}
System.out.println("Received message: " + line);
out.println(line);
out.flush();
}
out.close();
in.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) throws IOException {
new Server(80);
}
However, when I run that java application, it showed a BindException: Address already in use.
So what should I do to my code and make it listen to port 80, or are there any other ways to listen to that port in Java?
If I understand you correctly you are trying to sniff the packets that are being passed to your server. If that is the case there are some answers in this post.
What Server are you running it on?
it all depends on the type of server you're working on. Tomcat for example has the type of port it's running off of in the Server.xml file.
In Windows you can run your program by administrator. In Linux using root user.

Java Socket on Android, connection through 3G internet global ip

I have problems using Sockets on Android. I'm new to this topic so I try to achieve a simple chat, Android phone to another Android phone as a training.
I can use my code to create a ServerSocket and connect to it with another Socket from the same device ( An 'echo' example with only one client on one device works fine) I've done that also using two IP adresses on the same wifi (192.168...) but any tentative to connect a distant client using internet ip address using 3G connection fails with a
java.net.SocketException: recvfrom failed: ETIMEDOUT (Connection timed out)
What I do is, creating the ServerSocket (ServerConnect.java) :
private ServerSocket _mainServer = null;
private void initServer() {
try {
//port I use here is arbitrary: 8081
_mainServer = new ServerSocket(CONNECT_SOCKET_PORT);
} catch (IOException e) {
Log.w("ServerSocket", e.toString());
e.printStackTrace();
}
}
in the same class, in a separate thread I do this to wait for client connections :
while (running) {
GuestConnect ssc = new GuestConnect(_mainServer.accept());
ssc.setListener(this);
ssc.startConnection();
_clientSockets.add(ssc);
performGuestAdded("bra!");
}
it makes the server waiting for multiple client connection, so it can host more than two poeple in the 'chat room'.
The comunication server side is made from the local client callback and dispatch messages to all my guests (I'm still working on this part, its not really done yet but I don't think its relevant to my problem here) :
public void onMessageReceived(TBTGuestConnect sender, String message) {
for(TBTGuestConnect guestConnect : _clientSockets)
if(guestConnect != sender)
guestConnect.sendMessage(message);
}
Clients are store as 'GuestConnect' objects here is how I set them (GuestConnect.java):
public class GuestConnect {
private StringBuilder _currentMessage;
private BufferedReader _is;
private PrintStream _os;
private Socket _clientSocket = null;
private String _hostname;
private boolean _running = false;
public GuestConnect(String hostname) {
_hostname = hostname;
_currentMessage = new StringBuilder();
}
clientSocket initialisation (still GuestConnect.java):
private void initSocket() {
if(_clientSocket==null)
{
// Try to open a server socket on given port
// Here is the fail when I called it from another device
try {
_clientSocket = new Socket(_hostname, ServerConnect.CONNECT_SOCKET_PORT);
} catch (IOException e) {
Log.w("GuestSocket", e.toString());
}
}
// Create a socket object from the ServerSocket to listen and accept
// connections.
// Open input and output streams
try {
_is = new BufferedReader(new InputStreamReader(_clientSocket.getInputStream()));
_os = new PrintStream(_clientSocket.getOutputStream());
} catch (IOException e) {
Log.w("GuestSocket", e.toString());
}
}
again, in the same class there is the comunication part :
initSocket();
_running = true;
performConnectionStarted();
try {
while (_running) {
String received = _is.readLine();
_currentMessage.append(received);
if (received.contains(ServerConnect.CONNECT_SOCKET_MESSAGE_END)) {
String finalMsg = _currentMessage.toString().substring(0, _currentMessage.lastIndexOf(ServerConnect.CONNECT_SOCKET_MESSAGE_END));
performMessageReceived(finalMsg);
_currentMessage.setLength(0);
}
}
} catch (IOException e) {
Log.w("GuestSocket", e.toString());
performError(e);
} finally {
try {
_os.close();
_is.close();
_clientSocket.close();
} catch (IOException e) {
e.printStackTrace();
performError(e);
}
_clientSocket = null;
}
I can then send a message from this method :
public void sendMessage(String toSend) {
if (_running)
_os.println(toSend+ServerConnect.CONNECT_SOCKET_MESSAGE_END);
else
throw new IllegalStateException("Send message : Connection isn't started !");
}
So the question is, what should I do to make this works using global internet ip addresses ?
And more generally, what it the technical difference between same wifi local ip address and internet ip adress ?
i'll start from the end because it's easier - local ip address is private, it's not valid (and not visible) out of your local network, someone out of your local network can't access it directly but you can access hosts with public ip addresses. because they are not universally visible private addresses are not unique, public ip addresses are unique and (normally) visible from any point on the internet. there's more on the subject http://en.wikipedia.org/wiki/Network_address_translation
when it comes to 3g networks take a look here Could I connect to my iphone using 3g ip? and here ServerSocket accept() not accepting connections on Android . so most probably it can't be done
Don't know if this would be of any importance to you but in our country most 3G accounts are blocked by the ISP from incoming connections. You have to apply to unblock the ports. Some ISP's won't unblock them and some will.
Found that out when I wanted to connect my DVR with a 3G modem.

Testing Socket Program

So I wrote a simple Socket program that send message from Client to Server program and wanted to know what is the proper procedure to go about testing this? Both my Client and Server machines are running on Ubuntu 12.04 and I'm remote connecting to both of them.
For my Client code when I instantiate the client socket (testSocket) do I use its IP Address and Port number or Servers IP Address and Port number?
Here is the Code for Client:
public static void main(String[] args) throws UnknownHostException, IOException
{
Socket testSocket = null;
DataOutputStream os = null;
DataInputStream is = null;
try
{
testSocket = new Socket("192.168.0.104", 5932);
os = new DataOutputStream(testSocket.getOutputStream());
is = new DataInputStream(testSocket.getInputStream());
}
catch (UnknownHostException e)
{
System.err.println("Couldn't find Host");
}
catch (IOException e)
{
System.err.println("Couldn't get I/O connection");
}
if (testSocket != null && os != null && is != null)
{
try
{
os.writeBytes("Hello Server!\n");
os.close();
is.close();
testSocket.close();
}
catch (UnknownHostException e)
{
System.err.println("Host not found");
}
catch (IOException e)
{
System.err.println("I/O Error");
}
}
}
Here is the code for Server:
public static void main(String[] args)
{
String line = new String() ;
try
{
ServerSocket echoServer = new ServerSocket(5932);
Socket clientSocket = echoServer.accept();
DataInputStream is = new DataInputStream(clientSocket.getInputStream());
PrintStream os = new PrintStream(clientSocket.getOutputStream());
while (true)
{
line = is.readLine();
os.println(line);
}
}
catch (IOException e)
{
System.out.println(e.getMessage());
}
}
I'm new to Sockets and not sure what I'm supposed be seeing. I compiled both programs in terminal fine but not sure which one should I be running first or do they need to be started simultaneously?
Thanks
Your server is running in a infinite loop. Avoid that.
You have to restart your computer.
while (true)
{
line = is.readLine();
os.println(line);
}
try
while (!line.equals("Hello Server!"))
{
line = is.readLine();
os.println(line);
}
Run the server first. echoServer.accept(); waits for a connection. When it gets the first connection,
http://docs.oracle.com/javase/tutorial/networking/sockets/ this is a short java tutorial on how to work with sockets and also you can learn how to make a server that would accept multiple connections at a time. This tutorial explains you always need to start the server first, which is only logical. You should use threads to manage connections and then close them so that you use resources efficiently

Multiple non-simultaneous Java client-server connections using always the same port

I'm trying to test a scenario where one server accepts connections(one each time) from one client, using always the same ports (on the server and on the client side).
The purpose is to have 1 client application sending little pieces of data at a rate bigger than 100/min. The well obvious solution would be to have an always connected link between the client and the server, but this is production stuff, and that would require bigger changes in the code that is already implemented. With the solution we have implemented today, we always have +-1K of connections in TIME_WAIT, and I want to get rid of them.
I have implemented a simple tester, and the code is:
public class Server {
public static void main(String[] args) {
ServerSocket ssock = null;
try {
ssock = new ServerSocket();
ssock.bind(new InetSocketAddress(Common.SERVER_PORT));
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
while(true){
try{
Socket cSock = ssock.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(cSock.getInputStream()));
reader.readLine();
PrintWriter writer = new PrintWriter(cSock.getOutputStream());
writer.println(Common.SERVER_SEND);
writer.flush();
reader.close();
writer.close();
cSock.close();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
}
}
}
}
public class Client {
public static void main(String[] args) throws Exception {
InetSocketAddress cliAddr = new InetSocketAddress(
InetAddress.getByName(args[0]),
Common.CLIENT_PORT);
InetSocketAddress srvAddr = new InetSocketAddress(
InetAddress.getByName(args[1]),
Common.SERVER_PORT);
for(int j=1;j<=50;j++){
Socket sock = null;
try{
sock = new Socket();
sock.setReuseAddress(true);
sock.bind(cliAddr);
sock.connect(srvAddr);
PrintWriter writer =
new PrintWriter(
sock.getOutputStream());
writer.println(Common.CLIENT_SEND);
writer.flush();
BufferedReader reader =
new BufferedReader(
new InputStreamReader(
sock.getInputStream()));
reader.readLine();
}catch (Exception e) {
System.out.println(e.getClass().getName() + ": " + e.getMessage());
System.exit(-1);
}finally{
if(sock!=null) sock.close();
System.out.println("Done " + j);
}
}
}
}
public class Common {
public static final int SERVER_PORT = 9009;
public static final int CLIENT_PORT = 9010;
public static final String CLIENT_SEND = "Message";
public static final String SERVER_SEND = "OK";
}
When executing the client and server, on windows hosts, in one client execution I always get
java.net.ConnectException: Connection timed out
When executing the client and the server in linux hosts, on some client executions I get a
java.net.NoRouteToHostException: Cannot assign requested address
I've been killing my head over this behavior. Can someone please tell me if it is possible to do what I want, and what I am doing wrong?
If you want to get rid of the TIME_WAIT state, don't be the peer that receives the close. Be the peer that initiates the close. In this case, close the connection immediately after reading the response, and have the server cycle around looking for another request so that it reads the EOF rather than just closing the connection immediately after sending the response. However this will only make the problem worse, as all the TIME_WAIT states will accumulate at the server rather than at the client. On the other hand, the server is now structured to accept multiple requests per connection, so then all you have to do is adapt the clients to use a connection pool and all your problems are solved.

Categories