简体   繁体   English

如何与Netty异步发送多个http请求?

[英]How can I send multiple http requests asynchronous with Netty?

I am trying to send asynchronously a large amount a http posts requests to one server. 我试图异步发送大量的http发布请求到一个服务器。 My goals is to compare each response to its orginal request. 我的目标是将每个响应与其原始请求进行比较。

To do so I am following the Netty Snoop example . 为此,我将关注Netty Snoop示例

However, this example (and the other http examples) do not cover how to send multiple requests asynchrously, nor how to link them subsequently to the corresponding requests. 但是,此示例(以及其他http示例)不包括如何异步发送多个请求,也不包括如何将它们随后链接到相应的请求。

All similiar questions (such as this one , this one , or this one , implement the SimpleChannelUpstreamHandler class, which is from netty 3 and does not exists in 4.0 anymore ( documentation netty 4.0 ) 所有类似的问题(例如这一个这个或者这个问题 ,都实现了SimpleChannelUpstreamHandler类,它来自netty 3并且不再存在于4.0中( 文档netty 4.0

Anyone has an idea how to solve this in netty 4.0? 任何人都知道如何在netty 4.0中解决这个问题?

Edit: 编辑:

My problem is although I write lots of messages to the channel, I only receive very slowly the responses (1 response/sec, whereas a hope to receive few thousand / sec) . 我的问题是虽然我向频道写了很多消息,但我只收到非常慢的响应(1响应/秒,而希望接收几千/秒)。 To clarify this, let me post what I got so far. 为了澄清这一点,让我发布到目前为止我所得到的内容。 I am sure that the server I send the requests too can handle lots of traffic. 我确信我发送请求的服务器也可以处理大量流量。

What I got so far: 到目前为止我得到了什么:

import java.net.URI
import java.nio.charset.StandardCharsets
import java.io.File

import io.netty.bootstrap.Bootstrap
import io.netty.buffer.{Unpooled, ByteBuf}
import io.netty.channel.{ChannelHandlerContext, SimpleChannelInboundHandler, ChannelInitializer}
import io.netty.channel.socket.SocketChannel
import io.netty.channel.socket.nio.NioSocketChannel
import io.netty.handler.codec.http._
import io.netty.handler.timeout.IdleStateHandler
import io.netty.util.{ReferenceCountUtil, CharsetUtil}
import io.netty.channel.nio.NioEventLoopGroup

import scala.io.Source

object ClientTest {

  val URL = System.getProperty("url", MY_URL)     
  val configuration = new Configuration

  def main(args: Array[String]) {
    println("Starting client")
    start()
  }

  def start(): Unit = {

    val group = new NioEventLoopGroup()

    try {

      val uri: URI = new URI(URL)
      val host: String= {val h = uri.getHost(); if (h != null) h else "127.0.0.1"}
      val port: Int = {val p = uri.getPort; if (p != -1) p else 80}

      val b = new Bootstrap()

      b.group(group)
      .channel(classOf[NioSocketChannel])
      .handler(new HttpClientInitializer())

      val ch = b.connect(host, port).sync().channel()

      val logFolder: File = new File(configuration.LOG_FOLDER)
      val fileToProcess: Array[File] = logFolder.listFiles()

      for (file <- fileToProcess){
        val name: String = file.getName()
        val source = Source.fromFile(configuration.LOG_FOLDER + "/" + name)

        val lineIterator: Iterator[String] = source.getLines()

        while (lineIterator.hasNext) {
            val line = lineIterator.next()
            val jsonString = parseLine(line)
            val request = createRequest(jsonString, uri, host)
            ch.writeAndFlush(request)
        }
        println("closing")
        ch.closeFuture().sync()
      }
    } finally {
      group.shutdownGracefully()
    }
  }

  private def parseLine(line: String) = {
    //do some parsing to get the json string I want
  }

  def createRequest(jsonString: String, uri: URI, host: String): FullHttpRequest = {
    val bytebuf: ByteBuf = Unpooled.copiedBuffer(jsonString, StandardCharsets.UTF_8)

    val request: FullHttpRequest = new DefaultFullHttpRequest(
      HttpVersion.HTTP_1_1, HttpMethod.POST, uri.getRawPath())
    request.headers().set(HttpHeaders.Names.HOST, host)
    request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE)
    request.headers().set(HttpHeaders.Names.ACCEPT_ENCODING, HttpHeaders.Values.GZIP)
    request.headers().add(HttpHeaders.Names.CONTENT_TYPE, "application/json")

    request.headers().set(HttpHeaders.Names.CONTENT_LENGTH, bytebuf.readableBytes())
    request.content().clear().writeBytes(bytebuf)

    request
  }
}

class HttpClientInitializer() extends ChannelInitializer[SocketChannel] {

  override def initChannel(ch: SocketChannel) = {
  val pipeline = ch.pipeline()

  pipeline.addLast(new HttpClientCodec())

  //aggregates all http messages into one if content is chunked
  pipeline.addLast(new HttpObjectAggregator(1048576))

  pipeline.addLast(new IdleStateHandler(0, 0, 600))

  pipeline.addLast(new HttpClientHandler())
  }
}

class HttpClientHandler extends SimpleChannelInboundHandler[HttpObject] {

  override def channelRead0(ctx: ChannelHandlerContext, msg: HttpObject) {
    try {
      msg match {
        case res: FullHttpResponse =>
          println("response is: " + res.content().toString(CharsetUtil.US_ASCII))
          ReferenceCountUtil.retain(msg)
      }
    } finally {
      ReferenceCountUtil.release(msg)
    }
  }

  override def exceptionCaught(ctx: ChannelHandlerContext, e: Throwable) = {
    println("HttpHandler caught exception", e)
    ctx.close()
  }
}

ChannelFuture cf = channel.writeAndFlush(createRequest()); ChannelFuture cf = channel.writeAndFlush(createRequest());

nor how to link them subsequently to the corresponding requests. 以及如何将它们随后链接到相应的请求。

Can netty assign multiple IO threads to the same Channel? netty可以将多个IO线程分配给同一个Channel吗?

The worker thread once assigned for a channel does not change for the lifetime of the channel. 一旦为通道分配的工作线程在通道的生命周期内不会改变。 So we do not benefit from the threads. 所以我们不会受益于线程。 This is because you are keeping the connection alive and so is the channel kept alive. 这是因为您保持连接处于活动状态,因此通道保持活动状态。

To fix this problem, you might consider a pool of channels (say 30). 要解决此问题,您可以考虑一个频道池(比如30)。 Then use the channel pool to place your requests. 然后使用频道池发出请求。

      int concurrent = 30;

  // Start the client.
  ChannelFuture[] channels = new ChannelFuture[concurrent];
  for (int i = 0; i < channels.length; i++) {
    channels[i] = b.connect(host, port).sync();
  }

  for (int i = 0; i < 1000; i++) {
      ChannelFuture requestHandle = process(channels[(i+1)%concurrent]); 
      // do something with the request handle       
  }

  for (int i = 0; i < channels.length; i++) {
    channels[i].channel().closeFuture().sync();
  }

HTH HTH

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM