【问题标题】:Android Studio Connect to Socket serverAndroid Studio 连接到 Socket 服务器
【发布时间】:2021-08-12 08:30:40
【问题描述】:

我有一个使用 Eclipse 在 Java 中运行的服务器(这里是完整代码):

public class Main {

public static void main(String[]args) {
    
    // BBDD connection var
    Connection con = null;
    
    // Sockets
    ServerSocket server = null;
    try {
        server = new ServerSocket(5010);
    } catch (IOException e2) {System.out.println("Error at creating server, check if the port is in use");System.exit(-1);}
    
    /*** MySQL driver loading***/
    try {
        Class.forName("com.mysql.jdbc.Driver");
        System.out.println("MySQL driver is UP");
    } catch (ClassNotFoundException e1) {System.out.println("Error loading MySQL driver");}
    
    /*** Stablishing connection with the ddbb ***/
    try {
        con= (Connection) DriverManager.getConnection("jdbc:mysql://IP/Database", "username", "password");
        System.out.println("Connection stablished");
    } catch (SQLException e) {
        System.out.println("SQL ERROR");
        e.printStackTrace();
    }
    
    /*** Assigning thread for client ***/
    System.out.println("Listening for new requests...");
    while (true) {
        
        try {
            Socket clientSocket;
            clientSocket = server.accept();
            System.out.println("Connection stablished");
            
            DataInputStream dis = new DataInputStream(clientSocket.getInputStream());
            DataOutputStream dos = new DataOutputStream(clientSocket.getOutputStream());
            
            ThreadForClient client = new ThreadForClient(con, clientSocket, dis, dos);

            Thread thread = new Thread(cliente);
            thread .start();
        } catch (IOException e) {System.out.println("Error making client socket");}
    }
}

class ThreadForClient implements Runnable {

Connection con;
Socket clientSocket;
DataInputStream dis;
DataOutputStream dos;

public ThreadForClient(Connection con, Socket s, DataInputStream dis, DataOutputStream dos) {
    this.con = con;
    this.clientSocket = s;
    this.dis = dis;
    this.dos = dos;
 }

@Override
public void run() {

    try {
        int opc = dis.readInt();
        switch (opc) {
            case 1:
                String email = dis.readUTF();
                Boolean result = existeUsuario(email);
                dos.writeBoolean(result);
                break;
            default: break;
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

public Boolean userExists(String email) throws SQLException { // 1
    
    email = email.toLowerCase();
    Statement stmt;
    stmt = con.createStatement();
    ResultSet rs=stmt.executeQuery("select * from users where email = '"+email+"'");
    boolean result = rs.first();
    return result;
}

}

如您所见,客户端发送 2 个值并接收 1 个,第一个用于切换,这将指示要执行的内容,现在我只有 on 选项(检查 ddbb 中是否存在电子邮件),第二个值是电子邮件,因为代码已经进入开关。

服务器完全正常工作,我已经在 Eclipse 中使用客户端测试项目对其进行了测试(这是我想在 Android Studio 中做的):

public static void main(String[] args) {
    
    Socket socket = null;
    try {
        socket = new Socket(HOST, PORT);
        System.out.println("Conection succesful");
        
        DataOutputStream dos;
        DataInputStream dis;
        
        dos = new DataOutputStream(socket.getOutputStream());
        dis = new DataInputStream(socket.getInputStream());
        

        dos.writeInt(1);
        dos.writeUTF("email@example.com");
        
        Boolean bool = dis.readBoolean();
        if (bool) {
            System.out.println("Email exists in the BBDD.");
        } else {
            System.out.println("Email does not exist in the BBDD.");
        }
        
        socket.close();
        
    } catch (Exception e) {System.out.println("Server connection failed");}
  
}

现在我想做的是在 Android Studio 中执行相同的客户端,以便它可以连接到服务器。

我试过了:

public class SocketConnection {

UserExists ue;

public SocketConnection() throws IOException {
    connect();
}

public void connect() {
   
    ue = new UserExists();
    ue.execute();

}
}

class UserExists extends AsyncTask<Void, Void, Void> {

int PORT = 5010;
String HOST = "192.168.1.5";
private Socket socket;

private DataOutputStream dos;
private DataInputStream dis;

@Override
protected Void doInBackground(Void... voids) {
    try {
        socket = new Socket(HOST, PORT);
        dos = new DataOutputStream(socket.getOutputStream());
        dis = new DataInputStream(socket.getInputStream());
    } catch (Exception e) {
        System.out.println("Socket error");
        e.printStackTrace();
    }
    return null;
}

@Override
protected void onPostExecute(Void result) {
    super.onPostExecute(result);
}
}

当我运行它时,它不会给我任何错误,但是如果我在 doInBackground 底部记录套接字值以查看套接字值,它会说它是空的。

我也尝试过使用 Thread 和 Handle,但我无法得到服务器返回给我的主线程的结果。

【问题讨论】:

    标签: java mysql eclipse android-studio sockets


    【解决方案1】:

    根据 RFC 1918,192.168.0.0-192.168.255.255 范围内的地址是私有的。此类地址可以在任何网络内部使用,因此它们经常在组织内部使用。它们不能在 Internet 上使用,因为它们不是唯一的。 Why my ip address starts with 192.?

    我认为您的本地网络以某种方式阻止了该连接。但没有进一步的细节,据我所知,没有人能真正说出。

    如果您在同一台计算机上运行所有内容,您可能需要查看“环回”地址。通常是 127.0.0.1 ,应该循环回你的机器。

    如果您想运行完整的服务器,您可能需要更深入地研究网络并想了解网络的运作方式。

    【讨论】:

    • 我现在刚刚尝试使用我的公共 IP 打开端口并将 AsyncTask 主机方向更改为:83.**.**.**:5010 但它不起作用,它没有执行该方法仍然将套接字服务器保留为空。
    • 你从哪里得到 83.xx.xx.xx:5010?
    • 这是我的公网IP,所以我把它换成了'x'。
    • 现在它可以工作了,我尝试使用我的本地 IP 地址 (192.168.1.5) 并且也可以工作!这不是知识产权问题。您可以使用 192.x.x.x、127.0.0.1 (localhost) 和公共地址。您可以在whatismyipaddress.com 找到您的,只是不要忘记在您的路由器中打开正确的端口!
    【解决方案2】:

    我设法解决了这个问题。我刚刚在 Android Studio 的“连接”类中创建了一个线程。

    在“连接”中,我有一些类级变量,我与线程一起使用(线程无法修改创建线程的方法中的变量,但它可以读取类级变量)所以线程本身使与套接字服务器的连接,并将取值保存到类级变量中。

    在主线程中(在调用线程的同一方法中)我使用了一个循环来查看线程状态,如果它已完成,则读取变量并将其应用到我想要的位置。

    代码如下:

    public class Connection{
    
    private String HOST = "83.xx.xx.xx";
    private int PORT = 5010;
    
    private Socket socket;
    
    private DataOutputStream dos;
    private DataInputStream dis;
    
    boolean result;
    String email;
    
    public boolean userExists(String dev) throws InterruptedException { // true = exists, false = does not exist. dev is the email to search
        this.email = dev;
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    socket = new Socket(HOST, PORT);
                    dos = new DataOutputStream(socket.getOutputStream());
                    dis = new DataInputStream((socket.getInputStream()));
                    dos.writeInt(1); // 1 = Sends the option for telling the server that we want to search a user
                    dos.writeUTF(email); //Sends the email
                    result = dis.readBoolean(); // Recieve if email exists or not
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                    System.out.println("Couldn't connect to server");
                }
            }
        });
        thread.start();
        for (int c=0; c<25; c++){ //Wait for the thread to end
            if (thread.isAlive()) {
                //Thread hasn't finished yet...
                Thread.sleep(100);
            } else if (c == 24) {
                //This would be a timeout
                result = false;
            } else {
                //Thread has finished
                break;
            }
        }
        return result; // true in case server found the email, false in case it doesn't or in case of a timeout
    }
    

    我认为另一种可能性是让线程只进行连接(以及另一个用于关闭它)并将套接字保存为类级变量,这样您就可以从主线程发送和接收,我没有尝试还是这样。

    【讨论】: