簡體   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