我正在尝试在 Android Studio 中构建一个 P2P 聊天应用程序。为了实现这一目标,我使用两个不同的项目:一个运行服务器本身并充当第一个客户端,另一个项目作为新客户端运行。考虑到这一点,我一直在尝试连接我的手机和 A.S.模拟器在同一台服务器上。问题是,每次我尝试运行我的代码时,我都会收到一条警告:(使用我的 IP 地址 (ipv4)):
java.net.BindException: bind failed: EADDRNOTAVAIL (Cannot assign requested address)
此警告出现在服务器应用程序中:
public class MainActivity extends AppCompatActivity {
private static final int SERVER_PORT = 8080;
private static final String SERVER_IP = "0.0.0.0";
private List<Socket> clients = new ArrayList<>();
private ServerSocket serverSocket;
private TextView messageDisplay;
private EditText messageInput;
private Button sendButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
messageDisplay = findViewById(R.id.message_display);
messageInput = findViewById(R.id.message_input);
sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessageToAllClients();
System.out.println(serverSocket.getLocalPort());
System.out.println(serverSocket.getLocalSocketAddress());
}
});
startServer();
}
private void startServer() {
new Thread(new Runnable() {
@Override
public void run() {
try {
serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress(SERVER_IP, SERVER_PORT));
System.out.println("Servidor criado com sucesso");
while (true) {
Socket clientSocket = serverSocket.accept();
Toast.makeText(MainActivity.this, "Cliente STARTADO", Toast.LENGTH_SHORT).show();
clients.add(clientSocket);
listenToClient(clientSocket);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private void listenToClient(final Socket clientSocket) {
new Thread(new Runnable() {
@Override
public void run() {
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String message;
Toast.makeText(MainActivity.this, "TÁ OUVINDO", Toast.LENGTH_SHORT).show();
while ((message = reader.readLine()) != null) {
displayMessage("Client: " + message);
}
} catch (IOException e) {
Toast.makeText(MainActivity.this, "NÃO TA OUVINDO", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}).start();
}
private void sendMessageToAllClients() {
final String message = messageInput.getText().toString();
if (!message.isEmpty()) {
new Thread(new Runnable() {
@Override
public void run() {
for (Socket client : clients) {
try {
PrintWriter writer = new PrintWriter(client.getOutputStream(), true);
writer.println(message);
Toast.makeText(MainActivity.this, "TÁ MANDANDO", Toast.LENGTH_SHORT).show();
} catch (IOException e) {
Toast.makeText(MainActivity.this, "NÃO TÁ MANDANDO", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
}).start();
messageInput.setText("");
displayMessage("Me: " + message);
}
}
private void displayMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
//Toast.makeText(MainActivity.this, "TÁ MOSTRANDO", Toast.LENGTH_SHORT).show();
messageDisplay.append("\n" + message);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (serverSocket != null) {
serverSocket.close();
}
for (Socket client : clients) {
client.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}```
When I tried to use localhost (127.0.0.1) or 0.0.0.0 (which I don't actually understand what is), I get this warning, now at the client app logcat:
java.net.ConnectException: failed to connect to localhost/127.0.0.1 (port 8080) from /:: (port 48262): connect failed: ECONNREFUSED (Connection refused)
Here's the client-side code: ```
package com.example.desafio6_client;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class MainActivity extends AppCompatActivity {
private static final int SERVER_PORT = 8080;
private static final String SERVER_IP = "0.0.0.0";
private TextView messageDisplay;
private EditText messageInput;
private Button sendButton;
private Socket clientSocket;
private PrintWriter writer;
private BufferedReader reader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
messageDisplay = findViewById(R.id.message_display);
messageInput = findViewById(R.id.message_input);
sendButton = findViewById(R.id.send_button);
sendButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendMessageToServer();
}
});
connectToServer();
}
private void connectToServer() {
new Thread(new Runnable() {
@Override
public void run() {
try {
clientSocket = new Socket(SERVER_IP, SERVER_PORT);
Toast.makeText(MainActivity.this, "CONNECTED", Toast.LENGTH_SHORT).show();
if (clientSocket.isConnected()) {
writer = new PrintWriter(clientSocket.getOutputStream(), true);
reader = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
if(writer == null){
Toast.makeText(MainActivity.this, "WRITER IS NULL", Toast.LENGTH_SHORT).show();
}
if(reader == null){
Toast.makeText(MainActivity.this, "READER IS NULL", Toast.LENGTH_SHORT).show();
}
listenToServer();
} else {
// Handle the case when the socket connection is not established
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Connection failed. Please check server status.", Toast.LENGTH_SHORT).show();
}
});
}
} catch (IOException e) {
e.printStackTrace();
System.out.println("CRASHO");
// Handle any other exceptions that might occur during the socket connection
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "b " + e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
}
private void listenToServer() {
new Thread(new Runnable() {
@Override
public void run() {
try {
String message;
while ((message = reader.readLine()) != null) {
displayMessage("Server: " + message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
private void sendMessageToServer() {
final String message = messageInput.getText().toString();
if (!message.isEmpty()) {
new Thread(new Runnable() {
@Override
public void run() {
if (writer != null) {
writer.println(message);
} else {
// Handle the case when the writer is null
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, "Connection to server is not established.", Toast.LENGTH_SHORT).show();
}
});
}
}
}).start();
messageInput.setText("");
displayMessage("Me: " + message);
}
}
private void displayMessage(final String message) {
runOnUiThread(new Runnable() {
@Override
public void run() {
messageDisplay.append("\n" + message);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
if (clientSocket != null) {
clientSocket.close();
}
if (writer != null) {
writer.close();
}
if (reader != null) {
reader.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
} ```
I tried disabling my firewall, using an IP finder in my browser (because my cmd-ipconfig ipv4 is different compared to the one the site tells me), tried binding the server socket to a random IP, but nothings seems to work. I thought it was an AndroidManifest,xml missing statement, but it also changed nothing.
Client-side xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:enableOnBackInvokedCallback="true"
android:networkSecurityConfig="@xml/network_security_config"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Desafio6client"
tools:targetApi="tiramisu">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Server-side xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:networkSecurityConfig="@xml/network_security_config"
android:enableOnBackInvokedCallback="true"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Desafio6server"
tools:targetApi="tiramisu">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
network_security_config.xml:
<?xml version="1.0" encoding="utf-8"?>
<network-security-config xmlns:tools="http://schemas.android.com/tools">
<base-config cleartextTrafficPermitted="true"
tools:ignore="InsecureBaseConfiguration">
<trust-anchors>
<certificates src="system" />
</trust-anchors>
</base-config>
</network-security-config>
Can someone tell me what I'm doing wrong?