为什么套接字会抛出 IOException,如果我将其与主活动分开



我在Android上做了一个简单的程序,它使用Socket连接到服务器并接收一些数据。当我以这种方式编码时,它运行良好:

public class MainActivity extends Activity 
{
    EditText ip_box;
    Button login_button;
    TextView text;
    Handler handler;
    final int port = 12121;
    Socket socket;
    String ip;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();//omitted
        handler = new Handler()
        {
            public void handleMessage(Message msg)
            {
                String words = (String)msg.obj;
                text.setText((String)msg.obj);
            }
        };
        class GetThread implements Runnable
        {
            public void getMsg()
            {
                try 
                {
                    Scanner in = new Scanner(socket.getInputStream());
                    String gotmsg = in.nextLine();
                    Message msg = new Message();
                    msg.obj = gotmsg;
                    MainActivity.this.handler.sendMessage(msg);
                } catch (UnknownHostException e) 
                {
                    Message msg = new Message();
                    msg.obj = "net error";
                    MainActivity.this.handler.sendMessage(msg);
                } catch (IOException e) 
                {
                    Message msg = new Message();
                    msg.obj = "net error";
                    MainActivity.this.handler.sendMessage(msg);
                }
            }
            @Override
            public void run() 
            {
                try 
                {
                    socket = new Socket();
                    socket.connect(new InetSocketAddress(ip, port) , 5000);
                } catch (UnknownHostException e) 
                {
                    ...
                } catch (IOException e) {
                    ...
                }
                if( socket != null)
                    getMsg();
                else
                {
                    ...
                }
            }
        }
        login_button.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View arg0) 
            {
                // TODO Auto-generated method stub
                ip = ip_box.getText().toString();
                GetThread g = new GetThread();
                new Thread(g).start();
            }
        });
    }
}

我要做的是使套接字连接成为一个独立的类。我以这种方式制作了这门课:

public class ClientSocketManager
{
    String ip;
    int port;
    Socket socket;
    Handler handler; //use this to send messages
    /**
     * Thread to get message from server
     * @author Zero
     *
     */
    class GetThread implements Runnable
    {
        @Override
        public void run() 
        {
            try 
            {
                BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
                while(true)
                {
                    String input = in.readLine();
                    if(input!=null)
                    {
                        Message msg = new Message();
                        msg.obj = input;
                        handler.sendMessage(msg);
                    }
                } 
            }
            catch (IOException e) 
            {
                System.out.println("NetThreadIOException");
                Message msg = new Message();
                msg.obj = "net error";
                handler.sendMessage(msg);
            }
            catch (NullPointerException e)
            {
                //System.out.println("NetThreadIOException");
                Message msg = new Message();
                msg.obj = "net error";
                handler.sendMessage(msg);
            }
        }
    }
    /**
     * Thread to login to server
     * @author Zero
     *
     */
    class LoginThread implements Runnable
    {
        boolean ok;
        @Override
        public void run() 
        {
            try 
            {
                socket = new Socket();
                socket.connect(new InetSocketAddress(ip, port) , 5000);
            } catch (UnknownHostException e) 
            {
                System.out.println("UnknownHostException");
                Message msg = new Message();
                msg.obj = "did not login";
                handler.sendMessage(msg);
                ok=false;
            } catch (IOException e) {
                System.out.println("IOException");
                Message msg = new Message();
                msg.obj = "did not login";
                handler.sendMessage(msg);
                ok=false;
            }
        }
    }
    public ClientSocketManager(){}
    /**
     * Create a new ClientSocketManager
     * @param _ip
     * @param _port
     * @param _handler
     */
    public ClientSocketManager(String _ip, int _port, Handler _handler)
    {
        ip = _ip;
        port = _port;
        handler = _handler;
    }
    public boolean login()
    {
        LoginThread login_thread = new LoginThread();
        new Thread(login_thread).start();
        return login_thread.ok;
    }
    public void openGetThread()
    {
        GetThread getThread = new GetThread();
        new Thread(getThread).start();
    }
}

在主活动中,我像这样使用 ClientSocketManager:

        login_button.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View arg0) 
            {
                // TODO Auto-generated method stub
                ip = ip_box.getText().toString();
                client_socket_manager = new ClientSocketManager(ip, port, handler);
                boolean logged = client_socket_manager.login();
                //if(!logged)
                //  return;
                client_socket_manager.openGetThread();
            }
        })

现在它把IOException扔到String input = in.readLine();上。我很好奇。可能的原因是什么?

谢谢!

原因可能是: client_socket_manager.login()client_socket_manager.openGetThread()启动了两个线程同时运行以执行两个操作loginget。因此,当您尚未登录时,已执行操作get

我认为

问题是您的代码中无法保证 GetThread 将在登录线程之后执行。我看到您已经注释了代码检查登录状态。你需要把它放回去。

 boolean loggedIn = false;
 class LoginThread implements Runnable
    {
        boolean ok;
        @Override
        public void run() 
        {
            try 
            {
                socket = new Socket();
                socket.connect(new InetSocketAddress(ip, port) , 5000);
                loggedIn = true;
            } catch (UnknownHostException e) 
            {
                System.out.println("UnknownHostException");
                Message msg = new Message();
                msg.obj = "did not login";
                handler.sendMessage(msg);
                ok=false;
            } catch (IOException e) {
                System.out.println("IOException");
                Message msg = new Message();
                msg.obj = "did not login";
                handler.sendMessage(msg);
                ok=false;
            }
        }
    }

并在运行 GetThread 之前检查此 loggeddIn 标志

client_socket_manager = new ClientSocketManager(ip, port, handler);                
client_socket_manager.login();
while (true){
     if(loggedIn){
           client_socket_manager.openGetThread();
           break;
      }
      Thread.sleep(1000); //wait 1 sec before retrying
}

相关内容

最新更新