Commit 7d3b571b authored by 刘家荣's avatar 刘家荣 💬
Browse files

feat(Searcher & Provider)

parent a89f6675
Loading
Loading
Loading
Loading
+12 −5
Original line number Diff line number Diff line
package model;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;

public class Room {
    private static List<Room> roomList = new ArrayList<>();
    public final static List<Room> roomList = new ArrayList<>();
    
    public Room(String ip, int playerPort, int watcherPort, Account host) {
        this.ip = ip;
        this.playerPort = playerPort;
        this.watcherPort = watcherPort;
        this.host = host;
    }
    
    public String ip;
    
    public String name;
    public int playerPort;
    
    public URL url;
    public int watcherPort;
    
    public Account host;
    
+81 −1
Original line number Diff line number Diff line
package network;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import model.Account;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

public class Responser {
    private static Responser instance;
    
    public final int RESPONSE_PORT = 20000;
    
    public final int LISTEN_PORT = 20010;
    
    private Thread listenerThread;
    
    public static void start(){
        if(instance != null) stop();
        instance = new Responser();
    }
    
    private Responser(){
        //TODO:给前端刷新
        listenerThread = new Thread(() -> {
            DatagramSocket listenerSocket = null;
            while (listenerSocket == null) {
                try {
                    listenerSocket = new DatagramSocket(LISTEN_PORT);
                } catch (SocketException e) {
                    listenerSocket = null;
                }
            }
            while (!Thread.interrupted()) {
                final byte[] buf = new byte[1024];
                DatagramPacket recvPack = new DatagramPacket(buf, buf.length);
                try {
                    listenerSocket.receive(recvPack);
                    recvCallback(recvPack);
                } catch (IOException ignored) {}
            }
        });
        listenerThread.start();
    }
    
    /**
     * <pre>
     *     {
     *         "type": "Searching",
     *         "id": SEARCHER'S ID,
     *         "replyTo": LISTENING_PORT
     *     }
     * </pre>
     * <pre>
     *     {
     *         "type": "Response",
     *         "id": SEARCHER'S ID,
     *         "playerPort": port,
     *         "watcherPort": port,
     *         "host": Account Object,
     *     }
     * </pre>
     */
    public void recvCallback(DatagramPacket packet) {
        try {
            JSONObject recvData = JSON.parseObject(new String(packet.getData(), 0, packet.getLength()));
            String ip = packet.getAddress().getHostAddress();
            if(!recvData.get("type").equals("Searching")) return;
            String id = recvData.getString("id");
            int port = recvData.getIntValue("replyTo");
            
            if(Server.getInstance() == null) return;
            JSONObject responseData = new JSONObject();
            responseData.put("type", "Response");
            responseData.put("id", id);
            responseData.put("playerPort", Server.playerPort);
            responseData.put("watcherPort", Server.watcherPort);
            responseData.put("host", Account.SELF);
            String dataString = responseData.toString();
            try {
                DatagramPacket responsePack = new DatagramPacket(
                    dataString.getBytes(), 0, dataString.length(), InetAddress.getByName(ip), port);
                DatagramSocket responseSocket = new DatagramSocket(RESPONSE_PORT);
                responseSocket.send(responsePack);
            } catch (IOException ignored) {}
        } catch (JSONException ignored){}
    }
    
    public static void stop(){
@@ -16,7 +96,7 @@ public class Responser {
        instance = null;
    }
    private void instanceStop(){
        
        listenerThread.interrupt();
    }
    
}
+98 −5
Original line number Diff line number Diff line
package network;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONException;
import com.alibaba.fastjson2.JSONObject;
import model.Account;
import model.Room;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.UUID;

public class Searcher {
    private static Searcher instance;
    
    public final int BROADCAST_PORT = 20000;
    
    public final int LISTEN_PORT = 20010;
    
    private String currentId = UUID.randomUUID().toString();
    
    public static void start() {
        if (instance != null) stop();
        instance = new Searcher();
    }
    
    private Searcher() {
        search();
    }
    
    /**
     * <pre>
     * {
     *     "type": "Searching",
     *     "id": SEARCHER'S ID,
     *     "replyTo": LISTENING_PORT
     * }
     * </pre>
     */
    public void search() {
        this.currentId = UUID.randomUUID().toString();
        JSONObject data = new JSONObject();
        data.put("type", "Searching");
        data.put("id", this.currentId);
        String dataString = data.toString();
        try {
            DatagramPacket packet = new DatagramPacket(
                dataString.getBytes(), 0, dataString.length(), InetAddress.getByName("255.255.255.255"), BROADCAST_PORT);
            DatagramSocket broadcastSocket = new DatagramSocket();
            broadcastSocket.send(packet);
        } catch (IOException e) {
            return;
        }
        Room.roomList.clear();
        new Thread(() -> {
            String listenId = currentId;
            DatagramSocket listenerSocket = null;
            while (listenerSocket == null) {
                try {
                    listenerSocket = new DatagramSocket(LISTEN_PORT);
                } catch (SocketException e) {
                    listenerSocket = null;
                }
            }
            while (Searcher.instance.currentId.equals(listenId)) {
                final byte[] buf = new byte[1024];
                DatagramPacket recvPack = new DatagramPacket(buf, buf.length);
                try {
                    listenerSocket.receive(recvPack);
                    recvCallback(recvPack);
                } catch (IOException ignored) {}
            }
        }).start();
    }
    
    /**
     * <pre>
     *     {
     *         "type": "Response",
     *         "id": SEARCHER'S ID,
     *         "playerPort": port,
     *         "watcherPort": port,
     *         "host": Account Object,
     *     }
     * </pre>
     */
    public void recvCallback(DatagramPacket packet) {
        //TODO:给前端刷新
        try {
            JSONObject recvData = JSON.parseObject(new String(packet.getData(), 0, packet.getLength()));
            String ip = packet.getAddress().getHostAddress();
            if(!recvData.get("type").equals("Response")) return;
            String id = recvData.getString("id");
            if(!id.equals(this.currentId)) return;
            int playerPort = recvData.getIntValue("playerPort");
            int watcherPort = recvData.getIntValue("watcherPort");
            Account host = recvData.getObject("host", Account.class);
            Room.roomList.add(new Room(ip, playerPort, watcherPort, host));
        } catch (JSONException ignored){}
    }
    
    public static void stop() {
        instance.instanceStop();
        instance = null;
    }
    private void instanceStop(){
    
    private void instanceStop() {
        this.currentId = "";
    }
    
}

test/Ciphertext.java

0 → 100644
+29 −0
Original line number Diff line number Diff line
/**
 * 通讯协议
 */
public class Ciphertext {
    private static final String SN_HEADER = "ID";
    private static final String PORT_HEADER = "PORT";
    
    public static String buildWithPort(int port) {
        return PORT_HEADER + port;
    }
    
    public static int parsePort(String data) {
        if (data.startsWith(PORT_HEADER)) {
            return Integer.parseInt(data.substring(PORT_HEADER.length()));
        }
        return -1;
    }
    
    public static String buildWithSn(String sn) {
        return SN_HEADER + sn;
    }
    
    public static String parseSn(String data) {
        if (data.startsWith(SN_HEADER)) {
            return data.substring(SN_HEADER.length());
        }
        return null;
    }
}

test/UDPProvider.java

0 → 100644
+76 −0
Original line number Diff line number Diff line
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.util.UUID;

/**
 * UDP 提供者,用于提供服务
 */
public class UDPProvider {
    
    public static void main(String[] args) throws IOException {
        // 生成一份唯一标示
        String sn = UUID.randomUUID().toString();
        Provider provider = new Provider(sn);
        provider.start();
        
        System.in.read();
        provider.exit();
    }
    
    private static class Provider extends Thread {
        private final String sn;
        private boolean done = false;
        private DatagramSocket ds = null;
        
        public Provider(String sn) {
            super();
            this.sn = sn;
        }
        
        @Override
        public void run() {
            System.out.println("UDPProvider Started.");
            try {
                ds = new DatagramSocket(20000);
                while (!done) {
                    final byte[] buf = new byte[512];
                    DatagramPacket receivePack = new DatagramPacket(buf, buf.length);
                    ds.receive(receivePack);
                    
                    String ip = receivePack.getAddress().getHostAddress();
                    int port = receivePack.getPort();
                    int dataLen = receivePack.getLength();
                    String data = new String(receivePack.getData(), 0, dataLen);
                    System.out.println("UDPProvider receive form ip:" + ip + ",port:" + port + ",data:" + data);
                    // 解析端口号
                    int responsePort = Ciphertext.parsePort(data);
                    if (responsePort != -1) {
                        // 构建一份回送数据
                        String responseData = Ciphertext.buildWithSn(sn);
                        byte[] responseDataBytes = responseData.getBytes();
                        // 直接根据发送者构建一份回送信息
                        DatagramPacket responsePacket = new DatagramPacket(responseDataBytes, responseDataBytes.length,
                            receivePack.getAddress(),responsePort);
                        ds.send(responsePacket);
                    }
                }
            } catch (Exception ignored) {
            } finally {
                close();
            }
            System.out.println("UDPProvider Finished.");
        }
        private void close() {
            if (ds != null) {
                ds.close();
                ds = null;
            }
        }
        
        void exit() {
            done = true;
            close();
        }
    }
}
Loading