当前位置:编程学习 > JAVA >>

求高人解决DWR监听SOCKET的问题

现在有个需求,用户登录系统后需要实时监听服务器端有没有推送的信息,推送的方式是socket方式。想了一个方案,就是用户登录系统后,触发一个DWR请求,生成socket连接到服务器端,如果有消息就返回,然后继续循环(死循环),但是现在出现如下错误:
<2013-11-7 下午12时04分42秒 CST> <Error> <WebLogicServer> <BEA-000337> <[STUCK] ExecuteThread: '2' for queue: 'weblogic.kernel.Default (self-tuning)' has been busy for "708" seconds working on the request "weblogic.servlet.internal.ServletRequestImpl@f29cff[
POST /dwr/call/plaincall/CTIListener.TelListener.dwr HTTP/1.1
Accept: */*
Accept-Language: zh-cn
Referer: http://127.0.0.1:7001/grstemp/indexes/desktop/crmIndexLeft.jsp?ah=716
Content-Type: text/plain
UA-CPU: AMD64
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; Win64; x64; Trident/4.0; WebSaver; .NET CLR 2.0.50727; SLCC2; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E; Tablet PC 2.0)
Content-Length: 236
Connection: Keep-Alive
Cache-Control: no-cache
Cookie: JSESSIONID=1h3HS7CWMmdNyy1dTbzf1bjpnRJ4z9MFNX6FsTBNTjRlHQ1wjjSy!-293297698; DWRSESSIONID=Rck97Cd38q8ZVGa6$rS2daKeM9k

]", which is more than the configured time (StuckThreadMaxTime) of "600" seconds. Stack trace:
java.net.SocketInputStream.socketRead0(Native Method)
java.net.SocketInputStream.read(SocketInputStream.java:129)
sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:264)
sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:306)
sun.nio.cs.StreamDecoder.read(StreamDecoder.java:158)
java.io.InputStreamReader.read(InputStreamReader.java:167)
java.io.BufferedReader.fill(BufferedReader.java:136)
java.io.BufferedReader.readLine(BufferedReader.java:299)
java.io.BufferedReader.readLine(BufferedReader.java:362)
com.grs.basicModule.ctidwr.CTIClient.getCTIMsg(CTIClient.java:52)
com.grs.basicModule.ctidwr.CTIListenerAjax.TelListener(CTIListenerAjax.java:59)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
java.lang.reflect.Method.invoke(Method.java:597)
org.directwebremoting.impl.CreatorModule$1.doFilter(CreatorModule.java:229)
org.directwebremoting.impl.CreatorModule.executeMethod(CreatorModule.java:241)
org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:379)
org.directwebremoting.impl.DefaultRemoter.execute(DefaultRemoter.java:332)
org.directwebremoting.dwrp.BaseCallHandler.handle(BaseCallHandler.java:104)
org.directwebremoting.servlet.UrlProcessor.handle(UrlProcessor.java:120)
org.directwebremoting.servlet.DwrServlet.doPost(DwrServlet.java:141)
javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:227)
weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:125)
weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:292)
weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:26)
weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
com.grs.Filter.BaseFilter.doFilter(BaseFilter.java:39)
weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
weblogic.servlet.internal.RequestEventsFilter.doFilter(RequestEventsFilter.java:27)
weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:42)
weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3496)
weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:321)
weblogic.security.service.SecurityManager.runAs(Unknown Source)
weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2180)
weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2086)
weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1406)
weblogic.work.ExecuteThread.execute(ExecuteThread.java:201)
weblogic.work.ExecuteThread.run(ExecuteThread.java:173)

问题的原因是服务器端SOCKET推送信息的时间不确定,有的时候几分钟,有的时候好几个小时,请问如何解决这个问题。如果不用DWR ,有没有其他的方式,之前看到过websocket,但是需要HTML5支持,请问有没有类似WEBSOCKET的实现框架解决这种需求 --------------------编程问答-------------------- 系统做的话可以用comet框架,自己查查吧.
简单点的话可以用客户端固定5秒Ajax请求下服务器获取是否有信息.
服务端对应各个用户做消息队列.一遍在客户端请求是可以定位到指定客户端的消息列表.
--------------------编程问答-------------------- DWR的反向链接不需要循环链接一次即可,但是ScriptSession存在失效,并且其生命周期并不是同HttpSession一致,每次页面刷新,都会生成一个新的ScriptSession,需要一个额外的绑定的代码来保证每次用户请求新的链接都把旧的关闭掉。

可以看我的很早写的DWR的Session管理,版本很旧不一定能解决你的问题 --------------------编程问答-------------------- http://etfired.iteye.com/blog/457382
忘了贴链接了 --------------------编程问答--------------------
引用 2 楼 etfired 的回复:
DWR的反向链接不需要循环链接一次即可,但是ScriptSession存在失效,并且其生命周期并不是同HttpSession一致,每次页面刷新,都会生成一个新的ScriptSession,需要一个额外的绑定的代码来保证每次用户请求新的链接都把旧的关闭掉。

可以看我的很早写的DWR的Session管理,版本很旧不一定能解决你的问题

DWR push 如何 指定,比如说有的用户推送,有的用户不推送?
类CTIListenerAjax 是DWR的实现类

public void ctiListener(){
String empCode =(String)this.getSession().getAttribute("EMPCODE");
ServerUserThread sut = new ServerUserThread();
sut.setSc(this.getServletContext());
sut.setEmpCode(empCode);
sut.setWc(this.getWebContext());
Thread thread = new Thread(sut);
thread.start();
}

ServerUserThread 是个线程类,每个用户登录后会触发ctiListener() 并且根据session中存放的ID 创建相关的线程 ,改线程监听指定的socket端口 ,那个用户监听的socket有数据就往指定的用户页面推送信息
ServerUserThread类的代码片段

public void run() {

try {

while(tStatus){
    CTIManager ctiM = new CTIManager(sc);
    CTIUserInfo ctiUser = ctiM.getCTIUserInfo(empCode);
    CTIClient ctiClient = new CTIClient();
    ctiClient.setCtiUser(ctiUser);
    String result = ctiClient.getCTIMsg(empCode);
                            
                            代码实现 
          

}

} catch (Exception e) {
e.printStackTrace();
}
}

ctiClient.getCTIMsg(empCode) 就是到指定的socket根据用户ID 获取指定信息,代码实现位置如何推送到指定的客户端去 ,改线程已经把DWR WebContext 封装进来  --------------------编程问答--------------------
引用 4 楼 whb851423 的回复:
Quote: 引用 2 楼 etfired 的回复:

DWR的反向链接不需要循环链接一次即可,但是ScriptSession存在失效,并且其生命周期并不是同HttpSession一致,每次页面刷新,都会生成一个新的ScriptSession,需要一个额外的绑定的代码来保证每次用户请求新的链接都把旧的关闭掉。

可以看我的很早写的DWR的Session管理,版本很旧不一定能解决你的问题

DWR push 如何 指定,比如说有的用户推送,有的用户不推送?
类CTIListenerAjax 是DWR的实现类

public void ctiListener(){
String empCode =(String)this.getSession().getAttribute("EMPCODE");
ServerUserThread sut = new ServerUserThread();
sut.setSc(this.getServletContext());
sut.setEmpCode(empCode);
sut.setWc(this.getWebContext());
Thread thread = new Thread(sut);
thread.start();
}

ServerUserThread 是个线程类,每个用户登录后会触发ctiListener() 并且根据session中存放的ID 创建相关的线程 ,改线程监听指定的socket端口 ,那个用户监听的socket有数据就往指定的用户页面推送信息
ServerUserThread类的代码片段

public void run() {

try {

while(tStatus){
    CTIManager ctiM = new CTIManager(sc);
    CTIUserInfo ctiUser = ctiM.getCTIUserInfo(empCode);
    CTIClient ctiClient = new CTIClient();
    ctiClient.setCtiUser(ctiUser);
    String result = ctiClient.getCTIMsg(empCode);
                            
                            代码实现 
          

}

} catch (Exception e) {
e.printStackTrace();
}
}

ctiClient.getCTIMsg(empCode) 就是到指定的socket根据用户ID 获取指定信息,代码实现位置如何推送到指定的客户端去 ,改线程已经把DWR WebContext 封装进来 

太久没有使用DWR了,具体实现代码可能无法贴出来,实现思路还有有的。

DWR在Context中可以根据申请长链接的URL获取到这个页面的ScriptSession,也可以获取到所有的ScriptSession而不区分页面,这个特性可以划分一个大的推送范围,但是还需要做一些辅助工作
1: 拦截用户创建ScriptSession(这个需要重新定义DWR中的Listener,类似于Servlet的SessionListener)
2: 绑定ScriptSession到HpptSession,使得可以从HttpSession中获取ScriptSession,可以从ScriptSession取出HttpSession(也可以绑定用户id)
3: 使用DWR的过滤器,过滤所有符合条件的(用户ID一致)ScriptSession,推送Javascript到前端网页
补充:Java ,  Java相关
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,