【问题标题】:java.net.BindException: bind failed: EADDRINUSE (Address already in use)java.net.BindException:绑定失败:EADDRINUSE(地址已在使用中)
【发布时间】:2013-12-02 20:07:09
【问题描述】:

我有一个服务,它启动 Thread 以在套接字上执行一些操作。代码如下:

 public class ServerRunnable implements Runnable {
    @Override
    public void run() {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket();
            serverSocket.setReuseAddress(true);
            serverSocket.bind(new InetSocketAddress(ProtocolConstants.USB_SERVER_PORT));
        while (true) {
            Socket client = serverSocket.accept();
            // some code
        } catch (Exception e) {
            Log.e("Exception while listening on socket.", e);
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (IOException e) {
                    Log.e(e);
                }
            }
        }

当我第一次启动服务时,一切正常,但我必须使用stopService 方法停止它。当我再次启动它时,它返回以下异常:

java.net.BindException: bind failed: EADDRINUSE (Address already in use)

此外,我在onDestroy 服务方法中添加了ServerSocket 关闭,但它没有帮助。

setReuseAddressbind 之前执行,为什么它不起作用?

【问题讨论】:

  • 我建议您在ServerSocket 实际关闭时登录。要么是你重用了别人的端口,要么是重启时服务实际上并没有完全退出。

标签: android sockets networking port


【解决方案1】:

据我所知,它卡在serverSocket.accept() 上,等待连接进入。因此,即使关闭应用程序,Runnable 也永远不会完成。再次调用该应用程序会出现此错误(因为该端口仍被之前创建的 Runnable 阻塞)。有多种处理方法:

  • 你可以像这样调用和停止你的 Runnable:

    ThreadPoolExecutor threadPoolExecutor = Executors.newSingleThreadExecutor();
    Runnable longRunningTask = new Runnable();
    Future longRunningTaskFuture = threadPoolExecutor.submit(longRunningTask);
    longRunningTaskFuture.cancel(true); //this might not trigger right away
    
  • 你可以通过调用serversocket.close()来停止serverSocket.accept()(这会抛出一个需要处理的SocketException)

  • 我通过从我的 Activity 中的 onClose() 方法向我的 serverSocket 发送数据(字符串)解决了这个问题(可能不是处理这个问题的正确方法):

    Socket socket = new Socket();
    socket.setReuseAddress(true);
    socket.connect((new InetSocketAddress(YOURSETTINGS, HERE);
    OutputStream os = socket.getOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(os);
    oos.writeObject(new String("TIMEOUT"));
    oos.close();
    os.close();
    socket.close();
    

您可以选择在您的服务器中捕获它,如下所示:

ObjectInputStream objectInputStream = new objectInputStream(serverSocket.getInputStream());
Object object = objectInputStream.readObject();
if (object.getClass().equals(String.class) && ((String) object).equals("TIMEOUT"))
{
//Here you can do something with the Runnable before it is gone
}

【讨论】:

  • OP 中没有提到Executor。为什么你认为对等体应该序列化字符串“TIMEOUT”是另一个谜。 -1
  • 我找不到 socket.connect,您使用的实际 Socket 类是什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
  • 2013-02-18
  • 2018-04-01
相关资源
最近更新 更多