0

我知道我在日志猫中遇到的异常有一个非常直截了当的名字。我唯一的问题是我无法确定是什么导致了我的异常。我创建了一个 PC-Android 多客户端聊天。

PC 版可与服务器和客户端 100% 配合使用。我实现了从 PC 客户端到 android 客户端和聊天 WORKS 的相同技术。

我得到的唯一问题是,当我与 android 连接时,clientArea(跟踪所有连接的用户)不跟踪其他名称,而是跟踪 android 客户端用户名的倍数。IE。我只使用用户名:Jurko 在 android 上连接,clientArea 将有 2 个人称为 Jurko,而不是只有一个。

日志猫:

10-11 17:19:08.221: ERROR/AndroidRuntime(12379): FATAL EXCEPTION: main
        java.lang.ArrayIndexOutOfBoundsException: length=2; index=2
        at com.example.JurkoAndroidChat.MyActivity$ServerTask.onProgressUpdate(MyActivity.java:175)
        at com.example.JurkoAndroidChat.MyActivity$ServerTask.onProgressUpdate(MyActivity.java:130)
        at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:647)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4895)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:994)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:761)
        at dalvik.system.NativeStart.main(Native Method)

安卓客户端:

package com.example.JurkoAndroidChat;

import android.app.Activity;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.view.View;

import java.net.*;
import java.io.*;
import java.util.*;



public class MyActivity extends Activity {
    /**
     * Called when the activity is first created.
     */
    // Right here, we connecting the components of the main.xml form to code
    Button connectButton, disconnectButton, sendButton;
    TextView chatArea, clientArea;
    EditText messageField, usernameField, ipField;

    //Extra variables and sockets
    String username, serverIP;
    int Port = 5000;
    Socket sock;
    PrintWriter out;
    BufferedReader in;
    ArrayList<String> userList = new ArrayList();
    Boolean isConnected = false, exceptionCaught = false;

    ServerTask serverTask;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        System.out.println("Working?");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        connectButton = (Button)findViewById(R.id.button);
        sendButton = (Button)findViewById(R.id.button1);
        disconnectButton = (Button)findViewById(R.id.button2);

        chatArea = (TextView)findViewById(R.id.textView2);
        clientArea = (TextView)findViewById(R.id.textView3);

        messageField = (EditText)findViewById(R.id.editText2);
        usernameField = (EditText)findViewById(R.id.editText);
        ipField = (EditText)findViewById(R.id.editText1);



        connectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                if (isConnected == false) {
                    username = usernameField.getText().toString();
                    usernameField.setFocusable(false);
                    usernameField.setClickable(false);
                    serverIP = ipField.getText().toString();
                    ipField.setFocusable(false);
                    ipField.setClickable(false);
                    serverTask = new ServerTask();
                    serverTask.execute();


                } else if (isConnected == true) {
                    chatArea.append("You are already connected to the server.\n");
                }
            }
        });

        disconnectButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                String bye = (username + "µ µDisconnect");
                try {
                    out.print(bye);
                    out.flush();
                    chatArea.append("Disconnected.\n");
                    sock.close();

                } catch (Exception e) {  } // nothing caught so far.
                isConnected = false;
                usernameField.setFocusable(true);
                usernameField.setClickable(true);
                usernameField.setFocusableInTouchMode(true);
                ipField.setFocusable(true);
                ipField.setFocusableInTouchMode(true);
                ipField.setClickable(true);
                clientArea.setText("");

            }
        });

        sendButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //To change body of implemented methods use File | Settings | File Templates.
                String nothing = "";
                if ((messageField.getText().toString().equals(nothing))) {
                    messageField.setText("");
                    messageField.requestFocus();
                } else {
                    try {
                        out.println(username + "µ" + messageField.getText().toString() + "µ" + "Chat");
                        out.flush();


                    } catch (Exception e) {
                        Log.e("Error", e.toString());
                        chatArea.append("Message was not sent.\n" + e);
                    }
                    messageField.setText("");
                    messageField.requestFocus();
                }
            }
        });

    }


    public class ServerTask extends AsyncTask<Void, Void, Void> {

        String[] data;
        String stream, done = "Done", connect = "Connect", disconnect = "Disconnect", chat = "Chat";
        @Override
        protected Void doInBackground(Void... voids) {
            try {
                Log.i("Asynctask", "doInBackground");
                sock = new Socket(serverIP, Port);
                out = new PrintWriter(sock.getOutputStream());
                in = new BufferedReader(new InputStreamReader(sock.getInputStream()));
                out.println(username + "µ" + "has connected." + "µ" + "Connect");
                out.flush();
                isConnected = true;


            } catch (Exception ex) {
                    exceptionCaught = true;
                Log.e("Application", ex.toString());

            }
            try {
                while ((stream = in.readLine()) != null) {

                    publishProgress();
                }
            } catch (Exception e) {}

            return null;
        }

        public void writeUsers() {
            clientArea.setText("");
            Iterator<String> iterator = userList.iterator();
            while (iterator.hasNext()) {
                String token = iterator.next();
                clientArea.append(token + '\n');
            }
        }

        @Override
        protected void onProgressUpdate(Void... values) {

                    data = stream.split("µ");

                    if (data[2].equals(chat)) {
                        if (data[1].equals("has connected.") || data[1].equals("has disconnected."))
                            chatArea.append(data[0] + " " + data[1] + '\n');
                        else
                            chatArea.append(data[0] + ": " + data[1] + '\n');
                    } else if (data[2].equals(connect)) {
                        userList.add(data[0]);
                        writeUsers();
                    } else if (data[2].equals(disconnect)) {
                        userList.remove(data[0]);
                        writeUsers();
                    } else if (data[2].equals(done))
                        userList.clear();

           }

        @Override
        protected void onPostExecute(Void aVoid) {
            super.onPostExecute(aVoid);
            if (exceptionCaught == true) {
                chatArea.append("Unable to connect to " + serverIP + " at port " + Port + ".\n");
                usernameField.setFocusable(true);
                usernameField.setClickable(true);
                usernameField.setFocusableInTouchMode(true);
                ipField.setFocusableInTouchMode(true);
                ipField.setFocusable(true);
                ipField.setClickable(true);
                exceptionCaught = false;

            }
                //To change body of overridden methods use File | Settings | File Templates.
        }
    }












}

服务器(在 PC 上):

/*
 * To change this template, choose Tools : Templates
 * and open the template in the editor.
 */

/*
 * ServerWindow.java
 *
 * Created on Apr 23, 2011, 4:16:05 PM
 */


import java.io.*;
import java.net.*;
import java.util.*;
/**
 *
 * @author JurkoGuba
 */
public class ServerWindow extends javax.swing.JFrame {
    ArrayList clientOutputStreams;
    ArrayList<String> onlineUsers;

    public class ClientHandler implements Runnable  {
        BufferedReader reader;
        Socket sock;
        PrintWriter client;


        public ClientHandler(Socket clientSocket, PrintWriter user) {
            // new inputStreamReader and then add it to a BufferedReader
            client = user;
            try {
                sock = clientSocket;
                reader = new BufferedReader(new InputStreamReader(sock.getInputStream()));
            } // end try
            catch (Exception ex) {
                outputPane.append("Error beginning StreamReader. \n");
            } // end catch

        } // end ClientHandler()

        public void run() {
            String message, connect = "Connect", disconnect = "Disconnect", chat = "Chat" ;
            String[] data;

            try {
                while ((message = reader.readLine()) != null) {

                    outputPane.append("Received: " + message + "\n");
                    data = message.split("µ");

                    if (data[2].equals(connect)) {

                        tellEveryone((data[0] + "µ" + data[1] + "µ" + chat));
                        userAdd(data[0]);

                    } else if (data[2].equals(disconnect)) {

                        tellEveryone((data[0] + "µhas disconnected." + "µ" + chat));
                        userRemove(data[0]);

                    } else if (data[2].equals(chat)) {

                        tellEveryone(message);

                    } else {
                        outputPane.append("No Conditions were met. \n");
                    }


                } // end while
            } // end try
            catch (Exception ex) {
                outputPane.append("Lost a connection. \n");
                ex.printStackTrace();
                clientOutputStreams.remove(client);
            } // end catch
        } // end run()
    } // end class ClientHandler
    /** Creates new form ServerWindow */
    public ServerWindow() {
        initComponents();
    }



    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        outputPane = new javax.swing.JTextArea();
        startButton = new javax.swing.JButton();
        stopButton = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("House Server");

        outputPane.setColumns(20);
        outputPane.setEditable(false);
        outputPane.setLineWrap(true);
        outputPane.setRows(5);
        outputPane.setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
        jScrollPane1.setViewportView(outputPane);

        startButton.setText("Start");
        startButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                startButtonActionPerformed(evt);
            }
        });

        stopButton.setText("Stop");
        stopButton.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                stopButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                                        .addGroup(layout.createSequentialGroup()
                                                .addComponent(startButton, javax.swing.GroupLayout.PREFERRED_SIZE, 179, javax.swing.GroupLayout.PREFERRED_SIZE)
                                                .addGap(18, 18, 18)
                                                .addComponent(stopButton, javax.swing.GroupLayout.DEFAULT_SIZE, 183, Short.MAX_VALUE))
                                        .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 380, Short.MAX_VALUE))
                                .addContainerGap())
        );
        layout.setVerticalGroup(
                layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                        .addGroup(layout.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 229, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addGap(18, 18, 18)
                                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                                        .addComponent(startButton)
                                        .addComponent(stopButton))
                                .addContainerGap(19, Short.MAX_VALUE))
        );

        pack();
    }// </editor-fold>                        

    private void startButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:
        Thread starter = new Thread(new ServerStart());
        starter.start();

        outputPane.append("Server started. \n");
    }

    private void stopButtonActionPerformed(java.awt.event.ActionEvent evt) {
        // TODO add your handling code here:

        tellEveryone("Serverµis stopping and all users will be disconnected.\nµChat");
        outputPane.append("Server stopping... \n");

    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new ServerWindow().setVisible(true);
            }
        });
    }


    public class ServerStart implements Runnable {
        public void run() {
            clientOutputStreams = new ArrayList();
            onlineUsers = new ArrayList();

            try {
                ServerSocket serverSock = new ServerSocket(5000);

                while (true) {
                    // set up the server writer function and then begin at the same
                    // the listener using the Runnable and Thread
                    Socket clientSock = serverSock.accept();
                    PrintWriter writer = new PrintWriter(clientSock.getOutputStream());
                    clientOutputStreams.add(writer);

                    // use a Runnable to start a 'second main method that will run
                    // the listener
                    Thread listener = new Thread(new ClientHandler(clientSock, writer));
                    listener.start();
                    outputPane.append("Got a connection. \n");
                } // end while
            } // end try
            catch (Exception ex)
            {
                outputPane.append("Error making a connection. \n");
            } // end catch

        } // end go()
    }

    public void userAdd (String data) {
        String add = "µ µConnect", done = "Serverµ µDone", name = data;
        outputPane.append("Before " + name + " added. \n");
        onlineUsers.add(name);
        outputPane.append("After " + name + " added. \n");
        tellEveryone(done);

        Iterator<String> iterator = onlineUsers.iterator();
        while (iterator.hasNext()){
             String token = iterator.next();
             tellEveryone(token + add);
        }


    }

    public void userRemove (String user) {
        String add = "µ µDisconnect", done = "Serverµ µDone";
//        Iterator<String> remove = onlineUsers.iterator();
//        while (remove.hasNext()) {
//            String token = remove.next();
//            if (token.equals(user))
//                onlineUsers.remove(token);
//        }
        onlineUsers.remove(user);

        tellEveryone(user + add);
    }

    public void tellEveryone(String message) {
        // sends message to everyone connected to server
        Iterator it = clientOutputStreams.iterator();

        while (it.hasNext()) {
            try {
                PrintWriter writer = (PrintWriter) it.next();
                writer.println(message);
                outputPane.append("Sending: " + message + "\n");
                writer.flush();
                outputPane.setCaretPosition(outputPane.getDocument().getLength());

            } // end try
            catch (Exception ex) {
                outputPane.append("Error telling everyone. \n");
            } // end catch
        } // end while
    } // end tellEveryone()


    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextArea outputPane;
    private javax.swing.JButton startButton;
    private javax.swing.JButton stopButton;
    // End of variables declaration                   

}
4

4 回答 4

5

例外很明显。-

java.lang.ArrayIndexOutOfBoundsException: length=2; index=2

告诉您您正在尝试访问长度仅为(位置和)index 2的数组中的位置。201

我猜那条线MyActivity.java:175就是这条线。-

if (data[2].equals(chat)) {

所以你需要审查这个。-

data = stream.split("µ");

并检查它stream String是否具有预期值(它应该至少有两个µ字符才能产生 3+ 个项目的数组)。

于 2013-10-11T21:44:27.927 回答
1

让我们从错误消息开始:

java.lang.ArrayIndexOutOfBoundsException: length=2; index=2

我们知道在某处你有一个长度为 2 的数组,但你已经结束了它,因为在 Java 中数组索引的范围是从0length - 1

可能的解释:

data使用此调用初始化您的数组:

data = stream.split("µ");

但是,如果 中没有至少 2 个µ字符stream,则数组将小于 3,并且此行将引发异常:

if (data[2].equals(connect)) {

在输入这段代码之前检查data.length,确保它至少为 3,如果不是,则适当地处理错误。

于 2013-10-11T21:45:07.940 回答
1

stream没有 2 个µ字符,所以split返回一个少于 3 个项目的数组。当下面的代码尝试使用data[2]时,该元素超出了数组的范围并抛出异常。

让你的代码更具防御性,不要总是假设接收到的数据是好的。vg,拆分后,加上这段代码

 if (data.length < 3) {
     // Process error (log, user message, whatever)
     return;
 }
于 2013-10-11T21:46:33.973 回答
0

我得出一个结论,无论是否有人和我有同样的问题,一些回答我问题的专业人士可能想知道,以便将其添加到那里的知识中。

首先,我仔细检查了每条发送的消息是否包含 2 µs,因此 data[] 的大小不可能小于 3。

但是,我在 AsyncTask 中使用套接字(你必须或者你得到 NetworkTaskOnMainThread 异常),在我初始化套接字和读取器/写入器之后,我在连接套接字时调用 publishProgess。我意识到通过使用 whileLoop 可能会出现一些差异,然后根据可能会来回变化的东西调用进度,即。2 个用户同时发送消息。因此,我将 AsyncTask 的参数从<Void, Void, Void>to更改为<Void, String, Void>,然后当我在 doInBackground 中执行 publishProgress 时,我将流作为参数并改为使用它。

这似乎解决了问题。如果有人想触摸它,请这样做!

于 2013-10-12T05:16:36.690 回答