java - 在Tomcat中运行时, Atmosphere 广播无法到达客户端

标签 java tomcat jersey atmosphere

以下重大更新(2014年10月15日)

==========原始帖子===================

我有一个使用Atmosphere和Jersey的通知服务Webapp。我试图在Linux上的Tomcat中运行它,并且遇到了问题。 (请注意,当在Eclipse内的Tomcat嵌入式环境中运行时,此方法工作正常,因此很可能是Tomcat配置问题。)

问题在于广播消息似乎已排队或被缓冲,并且直到我关闭Tomcat才真正传递给客户端。到那时,所有这些都将被客户立即接收。

我尝试了各种在各种帖子中找到的方法来尝试解决此问题,但是我的努力分散了,因为我不知道是什么导致了该问题:

  • 我已经尝试过使用Tomcat的NIO协议(protocol)进行显式尝试。
  • 我尝试显式禁用文本和二进制缓冲,如果缓冲是原因,我还排队了足够的响应以触发刷新。
  • 我尝试在Tomcat 8中运行(但是有不同的不相关问题。)
  • 我添加了atmote-runtime-native,atmote-compat-jbossweb和atmote-compat-tomcat依赖项。

  • 这些都没有改变服务的行为。同样,在Eclipse中运行时,它似乎可以正常工作。

    环境:Ubuntu 14.04 LTS。 Tomcat 7.0.54。气氛2.1.5。对于一个客户,我现在只是在使用telnet。

    (此代码比示例要复杂一些,因为我要支持许多不同的路由,并且我使用的是this答案提出的方法,这似乎很好用。另外,我正在返回通知对象而不是字符串。这似乎也很好用。为了清楚起见,我已经删除了大部分身份验证内容。)

    pom.xml:
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.clearcaptial</groupId>
      <artifactId>notifications</artifactId>
      <packaging>war</packaging>
      <version>0.0.1-SNAPSHOT</version>
      <name>notifications Maven Webapp</name>
      <url>http://maven.apache.org</url>
      <dependencies>
        <dependency>
          <groupId>org.atmosphere</groupId>
          <artifactId>atmosphere-jersey</artifactId>
          <version>2.1.5</version>
        </dependency>
        <dependency>
          <groupId>com.sun.jersey</groupId>
          <artifactId>jersey-json</artifactId>
          <version>1.17.1</version>
        </dependency>
        <dependency>
          <groupId>org.atmosphere</groupId>
          <artifactId>atmosphere-runtime-native</artifactId>
          <version>2.1.5</version>
        </dependency>
        <dependency>
          <groupId>org.atmosphere</groupId>
          <artifactId>atmosphere-compat-jbossweb</artifactId>
          <version>2.0.1</version>
        </dependency>
        <dependency>
          <groupId>org.atmosphere</groupId>
          <artifactId>atmosphere-compat-tomcat</artifactId>
          <version>2.0.1</version>
        </dependency>
      </dependencies>
      <build>
        <finalName>notifications</finalName>
        <plugins>
          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
              <source>1.7</source>
              <target>1.7</target>
            </configuration>
          </plugin>
        </plugins>
      </build>
    </project>
    

    web.xml:
    <?xml version="1.0" encoding="UTF-8"?>
    <!-- This web.xml file is not required when using Servlet 3.0 container, 
        see implementation details http://jersey.java.net/nonav/documentation/latest/jax-rs.html -->
    <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:j2ee="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_3.0.xsd">
    
        <servlet>
        <servlet-name>AtmosphereServlet</servlet-name>
        <servlet-class>org.atmosphere.cpr.AtmosphereServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
        <init-param>
          <param-name>com.sun.jersey.config.property.packages</param-name>
          <param-value>com.clearcapital.notifications</param-value>
        </init-param>
        <init-param>
          <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
          <param-value>true</param-value>
        </init-param>
        <init-param>
          <param-name>org.atmosphere.useWebSocketAndServlet3</param-name>
          <param-value>true</param-value>
        </init-param>
      </servlet>
      <servlet-mapping>
        <servlet-name>AtmosphereServlet</servlet-name>
        <url-pattern>/*</url-pattern>
      </servlet-mapping>
    </web-app>
    

    来自ValidationsRouter.java:
    @Path("/validations")
    public class ValidationsRouter {
    
      @Context
      private AtmosphereResource atmosphereResource;
    
      @GET
      public SuspendResponse<ValidationNotification> subscribe(@Context UriInfo uri) throws URISyntaxException, NamingException, IOException {
        return new ValidationsResource().subscribe(uri, atmosphereResource);
      }
    
      @Broadcast
      @POST
      @Consumes(MediaType.APPLICATION_JSON)
      @Produces(MediaType.APPLICATION_JSON)
      public Broadcastable broadcast(ValidationNotification message, @Context UriInfo uri) {
        return new ValidationsResource().broadcast(message, uri);
      }
    }
    

    来自ValidationsResource.java:
    public class ValidationsResource extends ResourceBase<ValidationNotification>  {
      // a bunch of authentication stuff omitted for clarity.
    }
    

    从ResourceBase.java:
    public abstract class ResourceBase<T> {
    
      public SuspendResponse<T> subscribe(UriInfo uri, AtmosphereResource atmosphereResource) throws URISyntaxException, NamingException, IOException {
    
        Broadcaster myBroadcaster = BroadcasterFactory.getDefault().lookup(uri.getPath(), true);
        return new SuspendResponse.SuspendResponseBuilder<T>().broadcaster(myBroadcaster).outputComments(true)
                    .addListener(new EventsLogger()).type(MediaType.APPLICATION_JSON_TYPE).build();
      }
    
      public Broadcastable broadcast(T message, UriInfo uri) {
        Broadcaster myBroadcaster = BroadcasterFactory.getDefault().lookup(uri.getPath(), true);
        return new Broadcastable(message, "", myBroadcaster);
      }
    }
    

    ============原始帖子的结尾======================

    2014年10月15日更新:

    经过一段时间在另一个项目上,我又回到了这个问题。在使用新版本的Atmosphere(2.2.3)更新项目后,我发现行为没有差异。仍然存在这样的情况,即,在与运行客户端的计算机不同的计算机上运行服务时,直到Tomcat关闭,客户端才会接收到大气广播。在同一台计算机上运行客户端和服务时,一切都会按预期工作。

    因此,为了确定问题出在哪里,我仅在测试中开始使用其中一个Atmosphere示例应用程序。我正在使用jersey-pubsub示例应用程序(进行了较小的更新以使其能够编译),因为那是最接近我想要执行的操作的应用程序。我创建了一个全新的服务器环境来运行示例应用程序,以最小化基于Linux配置的任何变量。这是新的步骤-也许有人可以复制行为。

    要获得安装了Tomcat7的新服务器(我将Vagrant和VirtualBox用于这些测试):
    host$ vagrant init ubuntu/trusty64
    host$ nano Vagrantfile
    

    将网络配置更改为已知IP:config.vm.network :private_network, ip: "10.1.1.2"
    host$ vagrant box add https://vagrantcloud.com/ubuntu/boxes/trusty64/versions/1/providers/virtualbox.box
    host$ vagrant up
    ------------------
    vagrant$ sudo apt-get update
    vagrant$ sudo apt-get upgrade
    vagrant$ sudo apt-get install tomcat7
    

    按照这些步骤,我最终得到了Tomcat 7.0.52和Ubuntu 14.04

    我只有我使用的jersey-pubsub项目(没有父项目等)的副本
    host$ mvn clean install
    

    然后部署
    host$ cp target/jersey-pubsub.war ../../vagrants/trusty64/
    vagrant$ sudo cp /vagrant/jersey-pubsub.war /var/lib/tomcat7/webapps
    

    然后,我可以使用telnet进行测试,例如:
    host$ telnet 10.1.1.2 8080 <return>
    GET /jersey-pubsub/pubsub/foo HTTP/1.0 <return>
    <return>
    

    此时,telnet继续等待数据。在tomcat服务器日志中,我可以看到一个条目:
    20:33:55.805 [http-bio-8080-exec-1] INFO  o.a.samples.pubsub.EventsLogger - onSuspend(): 10.1.1.1:59357
    

    然后,我将POST请求发送到服务器。我为此使用POSTman,但我认为这并不重要。
    POST http://10.1.1.2:8080/jersey-pubsub/pubsub/foo
    Accept: text/html
    Content-Type: application/x-www-form-urlencoded
    message: <html><body><p>This is a test!</p></body></html>
    

    在服务器日志中,我可以看到服务器认为它广播了该消息:
    20:34:06.990 [Atmosphere-Shared-AsyncOp-0] INFO  o.a.samples.pubsub.EventsLogger - onBroadcast(): <html><body><p>This is a test!</p></body></html>
    

    但telnet客户端中没有任何显示。我可以无限重复进行操作,直到关闭Tomcat为止,都看不到任何结果,这时所有广播消息都会立即被Telnet接收。

    相反,如果我将服务部署在主机上运行的tomcat实例上,或者如果我在无所事事的实例中运行telnet,则一切都会按预期进行:
    vagrant$ telnet localhost 8080 <return>
    GET /jersey-pubsub/pubsub/foo HTTP/1.0 <return>
    <return>
    

    如果再发送相同的POST请求,我将立即在telnet中收到广播消息。行为似乎是,如果服务和客户端不在同一台计算机上,则在Tomcat运行时将阻止网络通信。

    这是我的jersey-pubsub示例副本的源代码,只需进行足够的更改即可使其作为独立项目进行编译和构建。

    EventsLogger.java:
    (除了在2个地方删除@Override以使Eclipse停止提示以外,其他均未更改)

    FileResource.java:
    (不变)

    JerseyPubSub.java:
    (不变)

    web.xml:
    (不变)

    pom.xml(修改为独立构建,不引用父pom):
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>org.atmosphere.samples</groupId>
        <artifactId>atmosphere-jersey-pubsub</artifactId>
        <packaging>war</packaging>
        <version>0.0.1-SNAPSHOT</version>
        <name>atmosphere-jersey-pubsub</name>
        <url>http://maven.apache.org</url>
        <properties>
            <atmosphere-version>2.2.3</atmosphere-version>
            <client-version>2.2.3</client-version>
            <logback-version>1.0.13</logback-version>
        </properties>
        <repositories>
            <repository>
                <id>oss.sonatype.org</id>
                <url>http://oss.sonatype.org/content/repositories/releases</url>
            </repository>
            <repository>
                <id>oss.sonatype.org-snapshot</id>
                <url>http://oss.sonatype.org/content/repositories/snapshots</url>
            </repository>
            <!-- <repository> <id>scala-tools.org</id> <name>Scala-Tools Maven2 Repository</name> 
                <url>http://scala-tools.org/repo-releases</url> </repository> -->
            <repository>
                <id>jboss</id>
                <url>https://repository.jboss.org/nexus/content/groups/public/</url>
            </repository>
            <repository>
                <id>codehaus</id>
                <name>repository.codehaus.org</name>
                <url>http://repository.codehaus.org</url>
            </repository>
            <repository>
                <id>codehaus-snapshots</id>
                <url>http://snapshots.repository.codehaus.org</url>
            </repository>
            <repository>
                <id>maven.java.net</id>
                <url>https://maven.java.net/content/groups/public/</url>
            </repository>
        </repositories>
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>org.atmosphere</groupId>
                    <artifactId>atmosphere-runtime</artifactId>
                    <version>${atmosphere-version}</version>
                </dependency>
                <dependency>
                    <groupId>org.apache.geronimo.specs</groupId>
                    <artifactId>geronimo-servlet_3.0_spec</artifactId>
                    <version>1.0</version>
                    <scope>provided</scope>
                </dependency>
                <dependency>
                    <groupId>ch.qos.logback</groupId>
                    <artifactId>logback-classic</artifactId>
                    <version>${logback-version}</version>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>org.atmosphere.client</groupId>
                <artifactId>javascript</artifactId>
                <version>${client-version}</version>
                <type>war</type>
            </dependency>
            <dependency>
                <groupId>org.atmosphere</groupId>
                <artifactId>atmosphere-jersey</artifactId>
                <version>${atmosphere-version}</version>
            </dependency>
            <dependency>
                <groupId>org.apache.geronimo.specs</groupId>
                <artifactId>geronimo-servlet_3.0_spec</artifactId>
            </dependency>
    
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-classic</artifactId>
            </dependency>
    
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>${logback-version}</version>
            </dependency>
        </dependencies>
        <build>
            <finalName>jersey-pubsub</finalName>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.7</source>
                        <target>1.7</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    最佳答案

  • 您是否在apache代理后面运行tomcat?
  • apache是​​否运行HTTP 1.1?
  • 可以尝试一些更多的Apache事情here
  • 关于java - 在Tomcat中运行时, Atmosphere 广播无法到达客户端,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24312224/

    相关文章:

    java - 将 'bits' 写入 C++ 文件流

    tomcat - 坚持tomcat jndi设置

    java - Tomcat 启动通过跳过扫描 jar 来加速,如果我跳过所有 jar,为什么没有抛出 ClassNotFound 异常?

    java - jUnit + jMock 和 log4j

    java - 如何从另一个类访问一个变量?

    java - 带有 setRollbackOnly 的 JMS 和 MDB

    tomcat - java.lang.IllegalArgumentException : Invalid character found in the request target. 有效字符在 RFC 7230 和 RFC 3986 中定义

    rest - JerseyTest 缺少依赖项 com.google.common.collect.Sets

    java - 如何为@PathParam 使用自定义类型?

    java - 从 GET 请求返回 pojo 时 Jersey Web 服务挂起