我有一个javafx桌面国际象棋应用程序,可以通过套接字在线玩。一名玩家创建GameRoom(服务器套接字),另一名玩家可以通过在对话框中输入IP地址直接加入。我想列出所有可用的房间,并以这种方式连接,而不是这种方法。
实现这个最简单的方法是什么?我想过把服务器地址放在在线数据库中,比如Firestore,但这似乎不是桌面应用程序的最佳选择。
考察一下:
public class GameServer implements Runnable{
private PrintWriter pw;
private BufferedReader in;
private ServerSocket listener;
public GameServer(){
}
@Override
public void run() {
try {
listener=new ServerSocket(50000);
System.out.println("Server is listening on port 50000");
if(in==null || pw==null){
Socket socket=listener.accept();
System.out.println("A player has connected");
pw=new PrintWriter(socket.getOutputStream(),true);
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
}
Executors.newFixedThreadPool(1).execute(() -> {
try {
OnlineGameFunctions.receiveMoveAndResign(in);
} catch (IOException e) {
e.printStackTrace();
}
});
}catch (IOException e){
e.printStackTrace();
}
}
客户端:
public class ClientSocket {
private Socket socket;
private PrintWriter pw;
private BufferedReader in;
public ClientSocket() {
}
public void Connect(String ip, int port) throws IOException {
if(in==null || pw==null){
socket=new Socket(ip,port);
in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
pw=new PrintWriter(socket.getOutputStream(),true);
}
Executors.newFixedThreadPool(1).execute(() -> {
try {
OnlineGameFunctions.receiveMoveAndResign(in);
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
您可以手动尝试连接到您的网络中可能的ip地址,此答案是SO的答案的组合,我会在帖子末尾添加链接到它们。
你首先需要得到你的局域网Ip地址和它的前缀长度,然后用它们来列出所有可能的Ip地址(使用commons.net),然后将这些Ip地址划分在多个线程上,每个线程将循环通过Ip的一部分,并尝试连接到它们中的每一个,如果连接成功=>将IP添加到结果中
我已经写了这段代码(大部分),并通过创建一个socketServer在我的机器上测试了它,它返回了我的ip,所以我猜它是有效的:
public class SocketScan {
public static void main(String[] args) throws Exception {
System.out.println(scan(50000));
}
public static List<String> scan(int port) throws Exception {
System.out.println("scanning for servers...");
ArrayList<String> res = new ArrayList<String>();
// get your lan ip
InterfaceAddress addr = getLanIp();
String myIp = addr.getAddress().getHostAddress() + "/" + addr.getNetworkPrefixLength();
// list all possible ip addresses using your ip and mask
SubnetUtils utils = new SubnetUtils(myIp);
String[] allIps = utils.getInfo().getAllAddresses();
// split all ips on a number of threads
// and try to connect to each one of them
int threadCount = 24;
Thread[] threads = new Thread[threadCount];
int threadSize = allIps.length / threadCount;
for (int i = 0; i < threadCount; i++) {
final int index = i;
threads[i] = new Thread() {
public void run() {
int start = threadSize * index;
int end = threadSize * (index + 1);
for (int j = start; j < (index == threadCount - 1 ? allIps.length : end); j++) {
String ip = allIps[j];
if(checkIp(ip, port)) {
res.add(ip);
}
}
}
};
}
//start all threads
for (Thread thread : threads) {
thread.start();
}
//wait for all threads to finish
for (Thread thread : threads) {
thread.join();
}
return res;
}
//check if a connection to this ip is possible
public static boolean checkIp(String ip, int port) {
try {
Socket socket = new Socket();
socket.connect(new InetSocketAddress(ip, port), 150);
socket.close();
return true;
} catch (Exception ex) {
return false;
}
}
//This method loops through your network interfaces and returns
//the first address that is ipv4 and not loopback
public static InterfaceAddress getLanIp() throws Exception {
for (final Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces(); interfaces
.hasMoreElements();) {
final NetworkInterface cur = interfaces.nextElement();
if (cur.isLoopback()) {
continue;
}
for (final InterfaceAddress addr : cur.getInterfaceAddresses()) {
final InetAddress inet_addr = addr.getAddress();
if (!(inet_addr instanceof Inet4Address)) {
continue;
}
return addr;
}
}
return null;
}
}
注意,这需要一些时间来完成(在我的机器上,我的/24子网上大约3秒),如果你不想等待所有的ip被检查,你可以在检查成功后传递一个消费者来处理一个ip
使用答案
Ip地址扫描器,不考虑网络子网
获取LAN ip只是用返回
代替打印获取可能的Ip地址
检查IP地址