@Override
 public void run() {
   threadCnt.incrementAndGet();
   try {
     while (running && !shutdown && sock != null) {
       /** Reads the first int to determine the length of the message */
       int length = din.readInt();
       if (length <= 0 || length > PACKETMAXSIZE) {
         throw new IOException("Received packet with invalid packet: " + length);
       }
       /** Allocates a new ByteBuffer to receive the message */
       byte[] msgArray = new byte[length];
       din.readFully(msgArray, 0, length);
       ByteBuffer message = ByteBuffer.wrap(msgArray);
       addToRecvQueue(new Message(message.duplicate(), sid));
     }
   } catch (Exception e) {
     LOG.warn("Connection broken for id " + sid + ", my id = " + self.getId() + ", error = ", e);
   } finally {
     LOG.warn("Interrupting SendWorker");
     sw.finish();
     if (sock != null) {
       closeSocket(sock);
     }
   }
 }
  /**
   * If this server has initiated the connection, then it gives up on the connection if it loses
   * challenge. Otherwise, it keeps the connection.
   */
  public boolean initiateConnection(Socket sock, Long sid) {
    DataOutputStream dout = null;
    try {
      // Sending id and challenge
      dout = new DataOutputStream(sock.getOutputStream());
      dout.writeLong(self.getId());
      dout.flush();
    } catch (IOException e) {
      LOG.warn("Ignoring exception reading or writing challenge: ", e);
      closeSocket(sock);
      return false;
    }

    // If lost the challenge, then drop the new connection
    if (sid > self.getId()) {
      LOG.info(
          "Have smaller server identifier, so dropping the "
              + "connection: ("
              + sid
              + ", "
              + self.getId()
              + ")");
      closeSocket(sock);
      // Otherwise proceed with the connection
    } else {
      SendWorker sw = new SendWorker(sock, sid);
      RecvWorker rw = new RecvWorker(sock, sid, sw);
      sw.setRecv(rw);

      SendWorker vsw = senderWorkerMap.get(sid);

      if (vsw != null) vsw.finish();

      senderWorkerMap.put(sid, sw);
      if (!queueSendMap.containsKey(sid)) {
        queueSendMap.put(sid, new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY));
      }

      sw.start();
      rw.start();

      return true;
    }
    return false;
  }
 /** A soft halt simply finishes workers. */
 public void softHalt() {
   for (SendWorker sw : senderWorkerMap.values()) {
     LOG.debug("Halting sender: " + sw);
     sw.finish();
   }
 }
  /**
   * If this server receives a connection request, then it gives up on the new connection if it
   * wins. Notice that it checks whether it has a connection to this server already or not. If it
   * does, then it sends the smallest possible long value to lose the challenge.
   */
  public boolean receiveConnection(Socket sock) {
    Long sid = null;

    try {
      // Read server id
      DataInputStream din = new DataInputStream(sock.getInputStream());
      sid = din.readLong();
      if (sid == QuorumPeer.OBSERVER_ID) {
        /*
         * Choose identifier at random. We need a value to identify
         * the connection.
         */

        sid = observerCounter--;
        LOG.info("Setting arbitrary identifier to observer: " + sid);
      }
    } catch (IOException e) {
      closeSocket(sock);
      LOG.warn("Exception reading or writing challenge: " + e.toString());
      return false;
    }

    // If wins the challenge, then close the new connection.
    if (sid < self.getId()) {
      /*
       * This replica might still believe that the connection to sid is
       * up, so we have to shut down the workers before trying to open a
       * new connection.
       */
      SendWorker sw = senderWorkerMap.get(sid);
      if (sw != null) {
        sw.finish();
      }

      /*
       * Now we start a new connection
       */
      LOG.debug("Create new connection to server: " + sid);
      closeSocket(sock);
      connectOne(sid);

      // Otherwise start worker threads to receive data.
    } else {
      SendWorker sw = new SendWorker(sock, sid);
      RecvWorker rw = new RecvWorker(sock, sid, sw);
      sw.setRecv(rw);

      SendWorker vsw = senderWorkerMap.get(sid);

      if (vsw != null) vsw.finish();

      senderWorkerMap.put(sid, sw);

      if (!queueSendMap.containsKey(sid)) {
        queueSendMap.put(sid, new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY));
      }

      sw.start();
      rw.start();

      return true;
    }
    return false;
  }
  /*
   * 读取对方的sid
   */
  public boolean receiveConnection(Socket sock) {
    Long sid = null;

    try {
      // Read server id
      DataInputStream din = new DataInputStream(sock.getInputStream());
      sid = din.readLong();
      if (sid < 0) { // this is not a server id but a protocol version
        // (see ZOOKEEPER-1633)
        sid = din.readLong();
        // next comes the #bytes in the remainder of the message
        int num_remaining_bytes = din.readInt();
        byte[] b = new byte[num_remaining_bytes];
        // remove the remainder of the message from din
        int num_read = din.read(b);
        if (num_read != num_remaining_bytes) {
          LOG.error(
              "Read only "
                  + num_read
                  + " bytes out of "
                  + num_remaining_bytes
                  + " sent by server "
                  + sid);
        }
      }
      if (sid == QuorumPeer.OBSERVER_ID) {
        /*
         * Choose identifier at random. We need a value to identify the
         * connection.
         */

        sid = observerCounter--;
        LOG.info("Setting arbitrary identifier to observer: " + sid);
      }
    } catch (IOException e) {
      closeSocket(sock);
      LOG.warn("Exception reading or writing challenge: " + e.toString());
      return false;
    }

    // If wins the challenge, then close the new connection.
    /*
     * 只允许sid大的连接小的
     */
    if (sid < self.getId()) {
      /*
       * This replica might still believe that the connection to sid is
       * up, so we have to shut down the workers be fore trying to open a
       * new connection.
       */
      SendWorker sw = senderWorkerMap.get(sid);
      if (sw != null) {
        sw.finish();
      }

      /*
       * Now we start a new connection
       */
      LOG.debug("Create new connection to server: " + sid);
      closeSocket(sock);
      connectOne(sid);

      // Otherwise start worker threads to receive data.
    } else {
      SendWorker sw = new SendWorker(sock, sid);
      RecvWorker rw = new RecvWorker(sock, sid, sw);
      sw.setRecv(rw);

      SendWorker vsw = senderWorkerMap.get(sid);

      if (vsw != null) vsw.finish();

      senderWorkerMap.put(sid, sw);

      if (!queueSendMap.containsKey(sid)) {
        queueSendMap.put(sid, new ArrayBlockingQueue<ByteBuffer>(SEND_CAPACITY));
      }

      sw.start();
      rw.start();

      return true;
    }
    return false;
  }