基于BS架构开发聊天室 采用while(true)方式接收消息,不关闭http请求



最近经常看到关于“如何基于BS架构开发聊天程序”的问题,这里把写的一个简要实例代码贴出来。


那么BS的聊天系统,一般两种技术(各有优劣):
1、基于Ajax或子页面刷新的拉模型;
2、基于HTTP长连接的推模型。

因为Ajax的“拉模型”,比较常见,这里给出基于HTTP长连接的“推模型”:


由三个页面组成:
chatmain.jsp 框架页面,引入两个Frame页面,并负责创建聊天室;
chatwnd.jsp 聊天信息窗口,负责用服务器推的方式显示所有人的聊天信息;

chatsender.jsp 聊天发送窗口,负责发送自己想说的话。

注意:本样例主要是为了说明 “基于长连接的推模型”,在聊天室完备性上完全不具有参考意义。


【chatmain.jsp 框架页面】

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>  
    <%@ page import="java.util.*"%>  
    <%  
        // 这三句话只是为了防止浏览器缓存  
        response.setHeader("Cache-Control", "no-cache, no-store"); //HTTP 1.1    
        response.setHeader("Pragma", "no-cache"); //HTTP 1.0    
        response.setDateHeader("Expires", 0); //prevents caching at the proxy server  
      
      
        // 检查并按需创建“聊天室”  
        ArrayList<String> lstMsg = (ArrayList<String>) application.getAttribute("room");  
        if (lstMsg == null) {  
            application.setAttribute("room", new ArrayList<String>());  
        }  
    %>  
    <html>  
    <frameset rows="80%, 20%">  
      <frame src="chatwnd.jsp"></frame>  
      <frame src="chatsender.jsp"></frame>  
    </frameset>  
    </html>  

【chatwnd.jsp 聊天信息窗口】

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>    
    <%@ page import="java.util.*"%>    
    <%@ page import="java.io.*"%>    
    <html>  
    <h2>Welcome to the ChatRoom!</h2>  
    <%  
        // 这三句话只是为了防止浏览器缓存  
        response.setHeader("Cache-Control", "no-cache, no-store"); //HTTP 1.1      
        response.setHeader("Pragma", "no-cache"); //HTTP 1.0      
        response.setDateHeader("Expires", 0); //prevents caching at the proxy server    
      
      
        Integer myMsgPos = 0; // 记录最后显示消息的位置  
        ArrayList<String> lstMsg = (ArrayList<String>) application.getAttribute("room");  
        out.flush(); // 把之前的HTML信息都刷出去  
        PrintWriter pw = response.getWriter(); // 用PrintWriter取代JspWriter以便于检查Socket异常  
        try {    
            synchronized (lstMsg) {    
                while (true) { // 死循环,也就意味着本次HTTP请求不会结束  
                    if (lstMsg.size() > myMsgPos) { // 检查有没有新的消息  
                        // 循环显示所有新消息  
                        System.out.println("Got new msg to push: "+(lstMsg.size()-myMsgPos));  
                        for (int i = myMsgPos; i < lstMsg.size(); i++) {    
                            String msg = lstMsg.get(i);  
                            pw.write("<p>"+msg+"</p>");  
                        }  
                        if (pw.checkError()) { // 强制将输出缓冲区内容发送出去,并检查异常  
                            System.out.println("IOException detected, JSP end.");  
                            break; // 说明已经发生IOException(一般是浏览器页面关掉了)  
                        }  
                        myMsgPos = lstMsg.size(); // 更新最后显示的消息位置  
                    }  
                    System.out.println("Waiting new msg..." + out.getRemaining());  
                    lstMsg.wait(); // 临时释放对lstMsg的独占(同步锁),等待新消息的到来  
                }  
            }  
        } catch (Exception ex) {    
            System.out.println(ex);    
        }  
    %>  
    </html>  

【chatsender.jsp 聊天发送窗口】

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>    
    <%@ page import="java.util.*" %>    
    <%@ page import="java.text.*" %>      
    <%  
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");  
        // 这三句话只是为了防止浏览器缓存  
        response.setHeader("Cache-Control", "no-cache, no-store"); //HTTP 1.1  
        response.setHeader("Pragma", "no-cache"); //HTTP 1.0      
        response.setDateHeader("Expires", 0); //prevents caching at the proxy server  
      
      
        // 获取POST的“发言”      
        String msg = request.getParameter("msg");    
        if (msg!=null && msg.length()>0) {    
            msg = "[" + sdf.format(new Date()) + "]" + session.getId() + ": " + msg;     
            System.out.println(msg); // 调试跟踪用的信息  
            ArrayList<String> lstMsg = (ArrayList<String>) application.getAttribute("room");    
            synchronized (lstMsg) {  
                lstMsg.add(msg); // 消息放入池中(消息太多会溢出的,这里并没有进行处理)  
                lstMsg.notifyAll(); // 通知chatwnd.jsp们,有新的消息来了,可以推给浏览器了  
            }  
        }  
    %>    
    <!DOCTYPE unspecified PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
    <html>    
    <form method="post">    
        My Speak: <input name="msg" type="text" size="40" /> <input type="submit" />    
    </form>    
    </html>  



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
部分代码如下:client: /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package client; /** * * @author Administrator */ import java.awt.*; import java.io.*; import java.net.*; import java.applet.*; import java.util.Hashtable; public class ClientChat extends Applet implements Runnable { Socket socket=null; DataInputStream in=null; DataOutputStream out=null; InputNameTextField 用户提交昵称界面=null; ChatArea 用户聊天界面=null; Hashtable listTable; Label 提示条; Panel north, center; Thread thread; public void init() { int width=getSize().width; int height=getSize().height; listTable=new Hashtable(); setLayout(new BorderLayout()); 用户提交昵称界面=new InputNameTextField(listTable); int h=用户提交昵称界面.getSize().height; 用户聊天界面=new ChatArea("",listTable,width,height-(h+5)); 用户聊天界面.setVisible(false); 提示条=new Label("正在连接到服务器,请稍等...",Label.CENTER); 提示条.setForeground(Color.red); north=new Panel(new FlowLayout(FlowLayout.LEFT)); center=new Panel(); north.add(用户提交昵称界面); north.add(提示条); center.add(用户聊天界面); add(north,BorderLayout.NORTH); add(center,BorderLayout.CENTER); validate(); } public void start() { if(socket!=null&&in!=null&&out!=null) { try { socket.close(); in.close(); out.close(); 用户聊天界面.setVisible(false); } catch(Exception ee) { } } try { socket = new Socket(this.getCodeBase().getHost(), 6666); in=new DataInputStream(socket.getInputStream()); out=new DataOutputStream(socket.getOutputStream()); } catch (IOException ee) { 提示条.setText("连接失败"); } if(socket!=null) { InetAddress address=socket.getInetAddress(); 提示条.setText("连接:"+address+"成功"); 用户提交昵称界面.setSocketConnection(socket,in,out); north.validate(); } if(thread==null) { thread=new Thread(this); thread.start(); } } public void stop() { try { socket.close(); thread=null; } catch(IOException e) { this.showStatus(e.toString()); } } public void run() { while(thread!=null) { if(用户提交昵称界面.get能否聊天()==true) { 用户聊天界面.setVisible(true); 用户聊天界面.setName(用户提交昵称界面.getName()); 用户聊天界面.setSocketConnection(socket,in,out); 提示条.setText("祝聊天愉快!"); center.validate(); break; } try { Thread.sleep(100); } catch(Exception e) { } } } }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值