@Override
  public List<ResponseInfo> sendAndPoll(List<RequestInfo> requestsToSend, Set<Integer> requestsToDrop,
      int pollTimeoutMs) {
    if (closed || !selector.isOpen()) {
      throw new IllegalStateException("The SocketNetworkClient is closed.");
    }
    long startTime = time.milliseconds();
    List<ResponseInfo> responseInfoList = new ArrayList<>();
    List<NetworkSend> sends = null;
    try {
      for (RequestInfo requestInfo : requestsToSend) {
        requestInfo.setRequestEnqueueTime(System.currentTimeMillis());
        pendingRequests.add(new RequestMetadata(requestInfo));
      }
      sends = prepareSends(requestsToDrop, responseInfoList);
      replenishConnections();
      for (Integer correlationId : requestsToDrop) {
        String connectionId = correlationIdInFlightToConnectionId.get(correlationId);
        if (connectionId != null) {
          // we do not need to mutate any of the bookkeeping data structures since that will be handled when dealing
          // with the disconnected list in handleSelectorEvents()
          selector.close(connectionId);
        }
      }
      selector.poll(pollTimeoutMs, sends);
      handleSelectorEvents(responseInfoList);
    } catch (Exception e) {
      logger.error("Received an unexpected error during sendAndPoll(): ", e);
      networkMetrics.networkClientException.inc();
    } finally {
      numPendingRequests.set(pendingRequests.size());
      networkMetrics.networkClientSendAndPollTime.update(time.milliseconds() - startTime, TimeUnit.MILLISECONDS);
    }
    return responseInfoList;
  }
Attempt to send the given requests and poll for responses from the network via the associated selector. Any
requests that could not be sent out will be added to a queue. Every time this method is called, it will first
attempt sending the requests in the queue (or time them out) and then attempt sending the newly added requests.
@param requestsToSend the list of {@link RequestInfo} representing the requests that need to be sent out. This
                    could be empty.
@param requestsToDrop the list of correlation IDs representing the requests that can be dropped by
                      closing the connection.
@param pollTimeoutMs the poll timeout.
@return a list of {@link ResponseInfo} representing the responses received for any requests that were sent out
so far.
@throws IllegalStateException if the SocketNetworkClient is closed.
ambry-network/src/main/java/com/github/ambry/network/SocketNetworkClient.java