Java

Netty Websocket服务端出现unsupported message type: TextWebSocketFrame

Netty Websocket服务器如果在一定程度的并发下出现下列异常并导致channel关闭: java.lang.IllegalArgumentException: unsupported message type: class org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame 发生这种情况,是因为Netty Server仍处于握手状态; 在握手状态下,channel只能发送http报文,不能发送websocket帧; 如果强行发生,就会在SocketSendBufferPool.acquire()方法内抛出上述异常。 解决办法有两种: 1. 修改你的代码,确保handshake response发送完后才发出text frame 2. 回送handshake response前把websocket encoder加入到channel pipeline中,即使这时有websocket frame发出,也不会报错。– 这是作者的观点,并且他已经实现到了新版的Netty里: https://github.com/netty/netty/commit/3b324e9515831f658fe8777df513a3a381822b34

Netty的写:异步,但是可以保证顺序

Netty的写是异步的,但可以保证两个消息写出的顺序与它们在代码中被写出的先后顺序相同。 handshaker.handshake(…); channel.write(myFirstTextWebSocketFrame); 会不会因为异步,导致上面代码中 text frame比handshake response更先到达客户端?  答案是不会:(这人是netty开发者之一)

servlet mvc框架中防止静态资源被mvc框架拦截

要配一个default servlet, 以免静态资源被其他servlet处理; 还要再配一个default filter,以免静态资源被其他filter处理 <filter> <filter-name>defaultFilter</filter-name> <filter-class>somepackage.DefaultFilter</filter-class> </filter> <filter-mapping> <filter-name>defaultFilter</filter-name> <url-pattern>favicon.ico</url-pattern> <url-pattern>/js/*</url-pattern> </filter-mapping> <!–其他filter mapping–> <servlet-mapping> <servlet-name>default</servlet-name> <url-pattern>favicon.ico</url-pattern> <url-pattern>/js/*</url-pattern> </servlet-mapping> <!–……–> <servlet-mapping> <servlet-name>mvcDispatch</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> public class DefaultFilter implements Filter { private RequestDispatcher defaultRequestDispatcher; @Override public void destroy() { } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { defaultRequestDispatcher.forward(request, …

servlet mvc框架中防止静态资源被mvc框架拦截 Read More »

最近踩的一个线程池的坑: coreSize = 0 & queueCapacity > 1

最近踩了一个线程池的坑: coreSize = 0, maxSize =4,  queueCapacity =1000  导致线程池并发为1,退化为单线程池。 提交第一个任务时,线程池发现当前poolSize不小于coreSize (都是0), 觉得没必要新建线程,就把任务置入队列;然后又发现当前池大小是0,于是新建一个线程,这个线程会来处理第一个任务。 在第一个任务执行完之前,提交第二个任务,线程池发现当前poolSize仍然不于小coreSize(1>=0),觉得没必要新建线程,也是于把任务置入队列;然后发现当前池大小不是0(是1),觉得没必要再新建线程了,于是结束submit()方法。 所以第一个任务不会马上执行,等池里唯一的线程执行完第一个任务后,才会来执行第二个任务。 就这样,多线程程序变成了单线程。 在队列被塞满之前,线程池都不会生成第二个线程,maxSize()设再高都没用。 从上也可以看出线程池中队列的作用: 当前有什么任务来不及处理,就“暂时”丢到队列里,等忙完手头上的事再去队列里捞出来处理;如果队列塞满了,才意识到自己人手不够,这时才要扩容线程(上限为maxSize)。 问题就在这里:“队列塞满才算人手不够”。 如果你的队列容量很大,虽然你只有一个线程,那你也不会觉得自己人手不够,因为队列总是塞不满。 所以,解决办法是,使用有界队列,让它能及时塞满, 然后提醒线程池扩容线程;或者也可以用SynchronousQueue,它是一种特殊的、容量为0的有界队列,或者严格地说,它根本不是队列,使用它,意味着不再“暂时”丢到队列里,而是直接交给空闲的线程,如果没有空闲线程就立即扩容。 回头一开始说的场景。如果poolSize改成2, 会怎么样? 显然,在queue被塞满之前,你只有两个线程干活,maxSize再大也没用。

Netty: 注意不要为java.nio.channels.ClosedChannelException浪费时间

服务端Netty在测试时遇到大量java.nio.channels.ClosedChannelException异常。有可能是你的代码有问题,也有可能仅是客户端主动关闭了连接,导致服务端的写失败。 比如,你如果在浏览器里按住F5不停刷新,就会出现大量这样的错误;但用curl/wget高并发地做压测,却并没有这种问题。 如果无聊的用户拼命刷你导致服务端出现大量这种异常怎么办? 一是限流,二是让服务端在写数据之前判断一下channel是否已关闭。 if (!channel.isConnected()) { if (logger.isWarnEnabled()) { logger.warn("Failed to write any response because the channel is not connected any more. Maybe the client has closed the connection? "); } return; }

jstack和kill -3的一个区别

jstack打印出的栈直接显示在当前shell窗口,可以通过管道放到某个文件里 而kill -3只会把栈打印到目标进程所在的shell窗口控制台