繁体   English   中英

我可以使用Java Socket在动态IP上托管聊天服务器吗?

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

调查Servlets我创建了一个简单的聊天并在本地IP上测试它 - 一切正常。 但是当我试图通过真实网络测试它时连接被拒绝了 - java.net.ConnectException: Connection refused: connect 我有动态IP的原因,还是需要其他设置? 提前致谢!

服务器:

/**
 * 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

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

客户:

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

}

如果你真的有一个动态IP,你可以给自己一个freedns域(并添加一个防火墙例外),但很可能你是NAT背后的。 为了使它工作,你需要多个东西:

  • 仍然,获得一个freedns域并设置自动IP地址更新
  • 在客户端中对域进行硬编码
  • 通过将UDP数据包发送到任何地方来暴露一组固定的UDP端口。 public ip上的UDP端口号通常与主机上的端口号匹配。 这部分是最重要的。 您可以使用公共STUN / TURN服务器检查它是否有效。
  • 将这组端口硬编码到客户端。 它应该尝试freedns域上的所有端口,直到它找到一个工作端口
  • 握手数据包应该具有聊天特有的签名,因此双方都知道他们正在尝试连接到正确的软件

如图所示,大多数NAT都是端口限制的锥形NAT,也就是说,它们会丢弃来自对等体的传入UDP数据包,直到您向该对等体发送数据包为止。 此外,通过发送数据包创建的NAT UDP映射在大约60秒内到期,这比TCP映射要少得多。

所有这些都使得纯粹的p2p消息传递无法用于NAT背后的各方。 要加入p2​​p网络,您仍然需要通过公共服务器(电子邮件或其他即时消息提供程序)交换一些数据包。 有“ice4j”库可以生成并解析这些数据包(SDP),然后为直接连接创建java套接字包装器。

即使两个对等端保存彼此的地址以便将来直接连接,地址最终也会因动态IP(通常为24小时)而到期。

听起来好像防火墙拒绝连接或者路由器不是端口转发,所以请求被拒绝。 这听起来与拥有动态IP无关。

如果您位于路由器后面,则路由器中存在允许端口转发的设置,您可能需要向防火墙添加规则。 无论如何,您可以通过尝试从其他地方ping服务器IP地址进行测试,如果响应,那么甚至尝试使用telnet <server ip> port来查看是否可以连接。

有些事情正在阻碍并拒绝连接!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM