Can I host Chat Server on Dynamic IP using Java Socket?

890 Views Asked by At

Investigating the Servlets I've created a simple chat and tested it on local IP - everything works. But when I tried to test it through the real network the connection refused - java.net.ConnectException: Connection refused: connect. Is the reason in Dynamic IP which I have, or additional settings are needed? Thanks in advance!

Server:

/**
 * Created by rnd on 7/4/2017.
 */

import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;

public class VerySimpleChatServer {

    ArrayList clientOutputStreams;

    public static void main (String[] args) {
        new VerySimpleChatServer().go();
    }

    public void go() {
        clientOutputStreams = new ArrayList();
        try {
            ServerSocket serverSock = new ServerSocket(5000);

            while(true) {
                Socket clientSocket = serverSock.accept();

                Charset charset = StandardCharsets.UTF_8;
                OutputStreamWriter osw = new OutputStreamWriter( clientSocket.getOutputStream(), charset );
                PrintWriter writer = new PrintWriter( new BufferedWriter( osw ) );

//                PrintWriter writer = new PrintWriter(clientSocket.getOutputStream());

                writer.println("Welcome to the chat 7 kids.... Семеро Козлят");
                writer.flush();

                clientOutputStreams.add(writer);
                Thread t = new Thread(new ClientHandler(clientSocket));
                t.start() ;
                System.out.println("got a connection");
            }
        } catch(Exception ex) {
            ex.printStackTrace();
        }
    } // Закрываем go


public class ClientHandler implements Runnable {

    BufferedReader reader;
    Socket sock;

    public ClientHandler(Socket clientSocket) {

        try {
            sock = clientSocket;
            InputStreamReader isReader = new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8);
            reader = new BufferedReader(isReader);
        } catch(Exception ex) {ex.printStackTrace();}

    } // Закрываем конструктор

    public void run() {
        String message;

        try {
            while ((message = reader.readLine()) != null) {
                System.out.println("read " + message);
                tellEveryone(message);
            } // Закрываем while
        } catch(Exception ex) {ex.printStackTrace();}
    } // Закрываем run
} // Закрываем вложенный класс


    public void tellEveryone(String message) {
        Iterator it = clientOutputStreams.iterator();
        while(it.hasNext()) {
            try {
                PrintWriter writer = (PrintWriter) it.next();
                writer.println(message);
                writer.flush();
            } catch(Exception ex) {
                ex.printStackTrace();
            }
        } // Конец цикла while
    } // Закрываем tellEveryone

} // Закрываем класс

Client:

/**
 * Created by rnd on 7/4/2017.
 */

import java.io.*;
import java.net.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;


public class SimpleChatClient {

    JTextArea incoming;
    JTextField outgoing;
    BufferedReader reader;
    PrintWriter writer;
    Socket sock;

    public static void main(String[] args) {
        SimpleChatClient client = new SimpleChatClient();
        client.go();}

    public void go(){
        JFrame frame = new JFrame("Ludicrously Simple Chat Client");
        JPanel mainPanel = new JPanel();
        incoming = new JTextArea(15,50);
        incoming.setLineWrap(true);
        incoming. setWrapStyleWord (true) ;
        incoming.setEditable(false);
        JScrollPane qScroller = new JScrollPane(incoming);
        qScroller. setVerticalScrollBarPolicy (ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) ;
        qScroller. setHorizontalScrollBarPolicy (ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS) ;
        outgoing = new JTextField(20);
        JButton sendButton = new JButton("Send") ;

        sendButton.addActionListener(new SendButtonListener());
        mainPanel.add(qScroller);
        mainPanel.add(outgoing);
        mainPanel.add(sendButton);

        setUpNetworking();

        Thread readerThread = new Thread(new IncomingReader());
        readerThread.start();

        frame.getContentPane().add(BorderLayout.CENTER, mainPanel);
        frame.setSize(800,500);
        frame.setVisible(true);

    }

    private void setUpNetworking() {
        try {
            sock = new Socket("178.165.87.221", 5000);
            InputStreamReader streamReader = new InputStreamReader(sock.getInputStream(), StandardCharsets.UTF_8 );
            reader = new BufferedReader(streamReader);


            Charset charset = StandardCharsets.UTF_8;
            OutputStreamWriter osw = new OutputStreamWriter( sock.getOutputStream(), charset );
            writer = new PrintWriter( new BufferedWriter( osw ) );

//            writer = new PrintWriter(sock.getOutputStream());
            System.out.println("networking established");
        } catch (IOException ex) {
                ex.printStackTrace();}
    }

    public class SendButtonListener implements ActionListener {
        public void actionPerformed (ActionEvent ev) {
            try {
                writer.println(outgoing.getText());
                writer.flush();

            } catch(Exception ex) {
                ex.printStackTrace();
            }
            outgoing. setText ("") ;
                    outgoing.requestFocus () ;}
    }

    public class IncomingReader implements Runnable{
        @Override
        public void run() {
            String message;

            try{
                while((message=reader.readLine())!=null ){
                    System.out.println("read " + message);
                    incoming.append(message + "\n");
                }

            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

}
2

There are 2 best solutions below

2
On

If you really have a dynamic ip, you can get yourself a freedns domain (and add a firewall exception), but most probably you're behind NAT. To make it work you need multiple things:

  • Still, get a freedns domain and setup automatic ip address update
  • hardcode the domain in the client
  • expose a fixed set of UDP ports by sending UDP packets to nowhere. The UDP port number on public ip usually matches the port number on your host. This part is the most important. You can check it works using public STUN/TURN servers.
  • Hardcode this set of ports into the client. It should try all ports on the freedns domain, until it finds a working port
  • The handshake packets should have a signature unique for your chat so both sides know they're trying to connect to the right software

As it appears, most NATs are Port-restricted cone NATs, that is, they drop incoming UDP packets from a peer until you send a packet to that peer. Besides, NAT UDP mappings you create by sending a packet expire in around 60 seconds, which is much less than for TCP mappings.

All this makes pure p2p messaging impossible for parties behind NAT. To join a p2p network you still need to exchange a few packets via a public server (e-mail or another Instant messaging provider). There's the library "ice4j" that can produce and parse these packets (SDP) and then create java socket wrappers for direct connections.

And even if two peers save each other's addresses to connect directly in the future, the addresses will eventually expire due to dynamic ip (usually 24h).

15
On

Sounds like either a firewall refusing the connection or a router is not port forwarding, so the request is just being refused. It doesn't sound like anything to do with having a dynamic IP.

If you are behind a router then there are settings in the router to allow port forwarding, and you might need to add a rule to your firewall. Anyway you can test by just trying to ping the server IP address from elsewhere and if that responds then even try a telnet <server ip> port to see if you can connect.

Something is getting in the way and refusing the connection!