我正在尝试使用Android平台上的Java Socket和Wifi P2P连接来创建服务器-客户端聊天应用程序,以用于我的大学论文。该应用程序将允许服务器创建新的聊天室,而客户端将加入聊天室。
但是,当服务器和客户端第一次在聊天室中时,它始终无法发送和接收消息。服务器和客户端离开聊天室并创建新的聊天室后,它将成功发送和接收消息。
我有用于发送和接收消息的源代码:
SendMessageServer.java
public class SendMessageServer extends AsyncTask<Message, Message, Message> {
private static final String TAG = "SendMessageServer";
private Context mContext;
private static final int serverPort = 4446;
private boolean isMine;
public SendMessageServer(Context context, boolean mine){
mContext = context;
isMine = mine;
}
@Override
protected Message doInBackground(Message... messages) {
// Display Message Before Sending
publishProgress(messages);
// Send Message to Client
try {
ArrayList<InetAddress> listClients = ServerThread.clients;
for(InetAddress addr : listClients) {
if(messages[0].getSenderAddress()!=null && addr.getHostAddress().equals(messages[0].getSenderAddress().getHostAddress())) {
return messages[0];
}
Socket socket = new Socket();
socket.setReuseAddress(true);
socket.bind(null);
Log.v(TAG,"Connect to Client: " + addr.getHostAddress());
socket.connect(new InetSocketAddress(addr, serverPort));
Log.v(TAG,"Connect to " + addr.getHostAddress() + " Success");
OutputStream outputStream = socket.getOutputStream();
new ObjectOutputStream(outputStream).writeObject(messages[0]);
Log.v(TAG, "Write to "+ addr.getHostAddress() + " Success");
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Send Message Server Error");
}
return messages[0];
}
@Override
protected void onProgressUpdate(Message... values) {
super.onProgressUpdate(values);
if(isActivityRunning(MainMenu.class)) {
ChatActivity.refreshList(values[0], isMine);
}
}
@Override
protected void onPostExecute(Message result) {
super.onPostExecute(result);
}
@SuppressWarnings("rawtypes")
public Boolean isActivityRunning(Class activityClass) {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (ActivityManager.RunningTaskInfo task : tasks) {
if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName())) {
return true;
}
}
return false;
}
}
SendMessageClient.java
public class SendMessageClient extends AsyncTask<Message, Message, Message> {
private static final String TAG = "SendMessageClient";
private Context mContext;
private static final int serverPort = 4445;
private InetAddress mServerAddress;
public SendMessageClient(Context context, InetAddress serverAddress){
mContext = context;
mServerAddress = serverAddress;
}
@Override
protected Message doInBackground(Message... messages) {
// Display Message Before Sending
publishProgress(messages);
// Send the message
Socket socket = new Socket();
try {
socket.setReuseAddress(true);
socket.bind(null);
socket.connect(new InetSocketAddress(mServerAddress, serverPort));
Log.v(TAG, "Connect to Server : " + mServerAddress.getHostAddress() + " Success");
OutputStream outputStream = socket.getOutputStream();
new ObjectOutputStream(outputStream).writeObject(messages[0]);
Log.v(TAG, "Send Message Client Success");
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Send Message Client Error");
} finally{
if (socket != null) {
if (socket.isConnected()) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Send Message Client Error");
}
}
}
}
return messages[0];
}
@Override
protected void onProgressUpdate(Message... messages) {
super.onProgressUpdate(messages);
if(isActivityRunning(MainMenu.class)){
ChatActivity.refreshList(messages[0], true);
}
}
@Override
protected void onPostExecute(Message result) {
super.onPostExecute(result);
}
@SuppressWarnings("rawtypes")
public Boolean isActivityRunning(Class activityClass) {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (ActivityManager.RunningTaskInfo task : tasks) {
if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName())) {
return true;
}
}
return false;
}
}
ReceiveMessageServer.java
public class ReceiveMessageServer extends AbstractReceiver {
private static final String TAG = "ReceiveMessageServer";
private static final int serverPort = 4445;
private Context mContext;
private ServerSocket serverSocket;
public ReceiveMessageServer(Context context){
mContext = context;
}
@Override
protected Void doInBackground(Void... params) {
try {
serverSocket = new ServerSocket(serverPort);
while(true) {
Socket clientSocket = serverSocket.accept();
InputStream inputStream = clientSocket.getInputStream();
ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
Message message = (Message) objectInputStream.readObject();
// Add Sender InetAddress to Message
InetAddress senderAddress = clientSocket.getInetAddress();
message.setSenderAddress(senderAddress);
clientSocket.close();
publishProgress(message);
}
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Receive Message Failed : IOException");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "Receive Message Failed : ClassNotFoundException");
}
return null;
}
@Override
protected void onCancelled() {
try {
serverSocket.close();
Log.v(TAG, "Server Socket Close Success");
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Server Socket Close Failed");
}
super.onCancelled();
}
@Override
protected void onProgressUpdate(Message... values) {
super.onProgressUpdate(values);
playNotification(mContext, values[0]);
// Check Message Type exclude Text Message
int type = values[0].getmType();
if(type == Message.audioMessage || type == Message.fileMessage) {
values[0].saveByteArrayToFile(mContext);
}
new SendMessageServer(mContext, false).executeOnExecutor(THREAD_POOL_EXECUTOR, values);
}
}
ReceiveMessageClient.java
public class ReceiveMessageClient extends AbstractReceiver {
private static final String TAG = "ReceiveMessageClient";
private static final int serverPort = 4446;
private Context mContext;
private ServerSocket socket;
public ReceiveMessageClient(Context mContext) {
this.mContext = mContext;
}
@Override
protected Void doInBackground(Void... params) {
try {
socket = new ServerSocket(serverPort);
socket.setReuseAddress(true);
while (true) {
Socket destinationSocket = socket.accept();
InputStream inputStream = destinationSocket.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
ObjectInputStream objectInputStream = new ObjectInputStream(bufferedInputStream);
Message message = (Message) objectInputStream.readObject();
destinationSocket.close();
publishProgress(message);
}
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "Receive Message Client Failed : IOException");
} catch (ClassNotFoundException e) {
e.printStackTrace();
Log.v(TAG, "Receive Message Client Failed : ClassNotFoundException");
}
return null;
}
@Override
protected void onCancelled() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
super.onCancelled();
}
@Override
protected void onProgressUpdate(Message... values) {
super.onProgressUpdate(values);
playNotification(mContext, values[0]);
/* Check if the Message Contains Audio/Video/File
* If true, Save to External Storage
*/
int type = values[0].getmType();
if (type == Message.audioMessage || type == Message.fileMessage){
values[0].saveByteArrayToFile(mContext);
}
if (isActivityRunning(MainMenu.class)){
ChatActivity.refreshList(values[0], false);
}
}
public Boolean isActivityRunning(Class activityClass) {
ActivityManager activityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningTaskInfo> tasks = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (ActivityManager.RunningTaskInfo task : tasks) {
if (activityClass.getCanonicalName().equalsIgnoreCase(task.baseActivity.getClassName()))
return true;
}
return false;
}
}
AbstractReceiver类仅用于通知,因此我认为问题仅来自于这四个类。
这是发生错误时的Logcat
07-18 21:06:31.952 12064-12426/com.archenians.inlesschat W/System.err: java.net.ConnectException: failed to connect to /192.168.49.220 (port 4446): connect failed: ECONNREFUSED (Connection refused)
07-18 21:06:31.955 12064-12426/com.archenians.inlesschat W/System.err: at libcore.io.IoBridge.connect(IoBridge.java:129)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:188)
at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:457)
at java.net.Socket.connect(Socket.java:927)
07-18 21:06:31.955 12064-12426/com.archenians.inlesschat W/System.err: at java.net.Socket.connect(Socket.java:853)
07-18 21:06:31.955 12064-12426/com.archenians.inlesschat W/System.err: at com.archenians.inlesschat.Asynctasks.SendMessageServer.doInBackground(SendMessageServer.java:53)
07-18 21:06:31.956 12064-12426/com.archenians.inlesschat W/System.err: at com.archenians.inlesschat.Asynctasks.SendMessageServer.doInBackground(SendMessageServer.java:22)
at android.os.AsyncTask$2.call(AsyncTask.java:295)
at java.util.concurrent.FutureTask.run(FutureTask.java:237)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
at java.lang.Thread.run(Thread.java:818)
07-18 21:06:31.956 12064-12426/com.archenians.inlesschat W/System.err: Caused by: android.system.ErrnoException: connect failed: ECONNREFUSED (Connection refused)
07-18 21:06:31.956 12064-12426/com.archenians.inlesschat W/System.err: at libcore.io.Posix.connect(Native Method)
07-18 21:06:31.957 12064-12426/com.archenians.inlesschat W/System.err: at libcore.io.BlockGuardOs.connect(BlockGuardOs.java:111)
at libcore.io.IoBridge.connectErrno(IoBridge.java:144)
at libcore.io.IoBridge.connect(IoBridge.java:127)
... 11 more
07-18 21:06:31.957 12064-12426/com.archenians.inlesschat V/SendMessageServer: Send Message Server Error
07-18 21:06:31.974 12064-12177/com.archenians.inlesschat D/OpenGLRenderer: CacheTexture 3 upload: x, y, width height = 0, 28, 394, 382
它表示类SendMessageServer.java第53行
socket.connect(new InetSocketAddress(addr, serverPort));
它在客户端显示相同的错误。
编辑:
如果服务器和客户端离开聊天室并创建一个新的聊天室,则发送和接收消息将成功。但是,一旦成功,ServerThread就会出现一个新问题。
有我的ServerThread.java和ClientThread.java代码
ServerThread.java
public class ServerThread extends Thread {
private static final String TAG = "ServerThread";
private static final int SERVER_PORT = 4444;
public static ArrayList<InetAddress> clients;
private ServerSocket serverSocket;
public ServerThread(){
clients = new ArrayList<InetAddress>();
}
@Override
public void run() {
clients.clear();
try {
serverSocket = new ServerSocket(SERVER_PORT);
// Collect IP Client
while(true) {
Socket clientSocket = serverSocket.accept();
if(!clients.contains(clientSocket.getInetAddress())){
clients.add(clientSocket.getInetAddress());
Log.v(TAG, "New client: " + clientSocket.getInetAddress().getHostAddress());
}
clientSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void interrupt() {
super.interrupt();
try {
serverSocket.close();
Log.v(TAG, "Server init process interrupted");
} catch (IOException e) {
e.printStackTrace();
}
}
}
ClientThread.java
public class ClientThread extends Thread {
public static final String TAG = "ClientThread";
private static final int SERVER_PORT = 4444;
private InetAddress mServerAddr;
public ClientThread(InetAddress serverAddr){
mServerAddr = serverAddr;
}
@Override
public void run() {
Socket socket = new Socket();
try {
socket.bind(null);
socket.connect(new InetSocketAddress(mServerAddr, SERVER_PORT));
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
从服务器端,错误显示在行上:
serverSocket = new ServerSocket(SERVER_PORT);
这是Logcat的绑定异常
07-20 07:57:20.531 6417-6616/com.archenians.inlesschat W/System.err: java.net.BindException: bind failed: EADDRINUSE (Address already in use)
at libcore.io.IoBridge.bind(IoBridge.java:104)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:137)
07-20 07:57:20.532 6417-6616/com.archenians.inlesschat W/System.err: at java.net.ServerSocket.<init>(ServerSocket.java:106)
at java.net.ServerSocket.<init>(ServerSocket.java:75)
at com.archenians.inlesschat.Threads.ServerThread.run(ServerThread.java:28)
Caused by: android.system.ErrnoException: bind failed: EADDRINUSE (Address already in use)
at libcore.io.Posix.bind(Native Method)
07-20 07:57:20.533 6417-6616/com.archenians.inlesschat W/System.err: at libcore.io.ForwardingOs.bind(ForwardingOs.java:56)
at libcore.io.IoBridge.bind(IoBridge.java:102)
... 4 more
我一直尝试添加
setReuseAddress(true);
但是,即使服务器和客户端关闭聊天室并再次创建一个新的聊天室,发送消息也永远不会成功。
有人可以帮助我吗?
告诉我这些代码在哪里以及如何解决。