3

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();
            }
        }
    }

}
Zabuzard
  • 25,064
  • 8
  • 58
  • 82
SergeiK
  • 83
  • 1
  • 11

2 Answers2

2

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).

basin
  • 3,949
  • 2
  • 27
  • 63
  • Thanks, but rather complicated for me. Can static IP solve this issue? Or I have to implement all these operations to get it work? – SergeiK Jul 24 '17 at 22:23
  • Then follow only the 1st paragraph of my answerand add a firewall exception. The ip address in your client looks like public. – basin Jul 25 '17 at 06:18
1

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!

Tony Kennah
  • 318
  • 4
  • 18
  • I tried to ping my IP outside - it is not blocked. When I try to write in cmd - telnet "my ip" "my port" I get that telnet is an unknown command. I use Windows 10 64. – SergeiK Jul 25 '17 at 07:30
  • I used this command netstat -an and I didn't find the port I use in open ports. I will try to add an exception into Windows firewall in the evening. – SergeiK Jul 25 '17 at 07:35
  • Yep I had to downoad "telnet". These days it's not included with Windows10. 1. Firewall (rule) and 2. Router (port forwarding). You wont see the open port using netstat from a different machine, netstat only shows information for the local machine.... Good luck – Tony Kennah Jul 25 '17 at 10:39
  • You won't beleive but, in order to open the port in router I have to specify the current IP (dynamic in my case) and reload the router. When I reload the router - the IP changes))) Regarding firewall I've also added the port, but router won't give me to start server((( I guess I need a static IP. – SergeiK Jul 25 '17 at 18:48
  • If it is your router you can sometimes assign an IP to a device and then even after a router reboot your device still gets the same internal dynamic IP. – Tony Kennah Jul 25 '17 at 20:29
  • I checked, after the router reboots the IP changes... ((( – SergeiK Jul 25 '17 at 20:35
  • My router has a section called "DHCP Reservation" in its DHCP settings where I can specify the IP assigned to a particular machine. – Tony Kennah Jul 25 '17 at 20:40
  • Today I got a static IP adress, so in the evening will tune the router and will try to get it work) – SergeiK Jul 26 '17 at 13:54
  • Yesterday I got a static IP, set up the router to work and in parrarel opened a port in router http://prntscr.com/g0uo3u. Then I cheked the firewall settings - and created a rule for internal connections where opened a 5000 port ащк TPC, but I still get "java.net.ConnectException: Connection refused: connect" ((( Don't know the reason. – SergeiK Jul 27 '17 at 07:20
  • When you port forward on a router you select the device that you want requests to be forwarded to. That device usually has an internal IP address like 192.168.0.3. You can find out by using the command `ipconfig` on windows and `ifconfig -a` on *nix machines. Then once the device is set in the routers port forwarding settings, when a request hits that port on the router it is forwarded on to the device specified. This is just basic TCP/IP stuff nothing really to do with Java or your chat application. – Tony Kennah Jul 27 '17 at 14:20
  • Thanks! I found out the mistake few hours ago. I run the server at home, and aplication is working outside, when I run the client on a different IP. May be the last thing that I would like to know and try to fix - is it possible to make the application run on the same computer (IP) that I used for server. For now it doesn't work inside the network, only outside. – SergeiK Jul 27 '17 at 15:30
  • Yes its possible, but you can't use the external IP address [Access external IP from inside the network](https://superuser.com/questions/1047745/access-external-ip-from-inside-the-network) On the local machine you would need to use either its internal IP address (192.168.0.3) or its loopback address 127.0.0.1 (or just "localhost") - I think you could hack the C:\Windows\System32\drivers\etc\hosts file and add 192.168.0.3 xxx.xxx.xxx.xxx #external IP A bit hacky. The best method would be to create a free dynamic DNS account such as [NoIP](https://www.noip.com/remote-access) – Tony Kennah Jul 27 '17 at 17:27
  • I meant if I could sucessfully run the client on the server's machine and the external machine simultainasly. Staret the server, run the client on the same computer, then run the client on another computer and communicate through the chat. – SergeiK Jul 27 '17 at 21:52
  • I haven't checked your code, but that's certainly possible yes. – Tony Kennah Jul 28 '17 at 10:02
  • If you grab yourself an account with NoIP then you can use a URL like xchat.ddns.net which will point to your machine... instead of messing about with IP addresses. – Tony Kennah Jul 28 '17 at 10:30