免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4435 | 回复: 8
打印 上一主题 下一主题

JSP图片验证码的一个令人匪夷所思的问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-06 15:24 |只看该作者 |倒序浏览
各位好:
    最近上线了一个bs的网页系统,前台通过网页查询后台oracle中的一些业务数据,运行过程中出了一个非常奇怪的问题,应该所有做bs系统中包含jsp验证码的大侠们都应该碰到过,希望大家帮帮忙,抽几分钟帮忙看看(可能您已经完成,正在上线的系统也存在该问题哦),拉兄弟一把,拉兄弟一把
问题描述:
    由于在该网页中提供了一些特殊的查询接口:struts中的一些method,为防止别人直接使用恶意程序批量查询,中间也就添加了一个jsp图片验证码的程序(我看网上的验证码程序似乎都是这个模样的),可是确出现了一个问题:平时系统运行都正常,验证码也能正常显示,验证逻辑也正常工作,可是经过长期的分析、测试发现在访问该验证码jsp页面在并发量特别大的时候,在正式的系统(linux 企业4+jdk1.4+weblogic812)的环境下 的 /tmp 目录中会生成一些 imageioxxxx.tmp的文件(xxxx为linux系统自己生成的数值编号),而使用 linux的lsof命令可以查询到这些文件句柄被linux系统占用,未释放,可是linux系统对文件句柄的个数有控制,由于系统访问量特别大,导致这个数值一直在涨,于是乎weblogic系统平均半个月要重新启动一次(已经确定不是什么jdbc连接池泄漏之类的问题了),导致客户意见非常大。
该现象有以下几个特点:
1、访问量特别大时候出现 linux的 /tmp 生成不释放文件句柄的 imageioxxx.tmp 临时文件。
2、在某些linux机器上,同样的程序导致CPU涨得比较快(比如,从IE中直接访问 该页面 http://网站url/bug.jsp ,在 linux的top 命令中,就立马可以看到cpu瞬间冲到99%让后又落下来),在有些机器又没有该现象。
3、具体在代码中,JPEG的图片方式比PNG的方式更容易发生 /tmp 目录生成不释放文件句柄的 imageioxxx.tmp 临时文件。
4、这些 imageioxxx.tmp 文件,从服务器ftp下载回来后,直接重新命名为 imageioxxx.jpg,即可看到,就是验证码的图片。

验证码的jsp代码如下:
<%@ page contentType="image/jpeg" import="java.awt.*,
java.awt.image.*,java.util.*,javax.imageio.ImageIO,javax.servlet.http.*,java.io.OutputStream" %>
<%!
      long serialVersionUID = -3938318741402322164L;
        Color getRandColor(int fc,int bc){
        Random random = new Random();
        if(fc>255) fc=255;
        if(bc>255) bc=255;
        int r=fc+random.nextInt(bc-fc);
        int g=fc+random.nextInt(bc-fc);
        int b=fc+random.nextInt(bc-fc);
        return new Color(r,g,b);
        }

        private final void drawNoise(Graphics graphics, int lineNumber) {
            graphics.setColor(getRandColor(20, 250));
            int pointX1, pointY1, pointX2, pointY2;
            for (int i = 0; i < lineNumber; i++) {
                pointX1 = 1 + (int) (Math.random() * 70);
                pointY1 = 1 + (int) (Math.random() * 20);
                pointX2 = 1 + (int) (Math.random() * 70);
                pointY2 = 1 + (int) (Math.random() * 20);
                graphics.drawLine(pointX1, pointY1, pointX2, pointY2);
            }
        }
%>
<%
     String charsLong = "23456789abcdefghjklmnpqrstuvwxyzABCDEFGHIJKLMNPQRSTUVWXYZ";
     String charsShort = "0123456789";
     String chars = charsShort;
      try {
        int charsLength = chars.length();

        response.setHeader("ragma", "No-cache";
        response.setHeader("Cache-Control", "no-cache";
        response.setDateHeader("Expires", 0);
                    out.clear();
        int width = 70, height = 20;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        Graphics g = image.getGraphics();
        Random random = new Random();
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);

        g.setFont(new Font("Times New Roman", Font.ITALIC, height));

        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 2; i++) {
          int x = random.nextInt(width);
          int y = random.nextInt(height);
          int xl = random.nextInt(12);
          int yl = random.nextInt(12);
          g.drawLine(x, y, x + xl, y + yl);
        }

        StringBuffer sRand = new StringBuffer();
        String[] fontNames = { "Times New Roman", "Arial", "Book antiqua", "" };

        for (int i = 0; i < 4; i++) {
          g.setFont(new Font(fontNames[random.nextInt(3)], Font.ITALIC, height));
          char rand = chars.charAt(random.nextInt(charsLength));
          sRand.append(rand);
          g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
          g.drawString(String.valueOf(rand), 16 * i + random.nextInt(6) + 3, height - random.nextInt(4));
        }

        g.setColor(getRandColor(160, 200));
        drawNoise(g,;
        for (int i = 0; i < 2; i++) {
          int x = random.nextInt(width);
          int y = random.nextInt(height);
          int xl = random.nextInt(width);
          int yl = random.nextInt(width);
          g.drawLine(x, y, x + xl, y + yl);
        }

        request.getSession().setAttribute("Login_Image_Code", sRand.toString());
        g.dispose();

        try {
          Thread.sleep(100);
        } catch (Exception ex) {
        }
        OutputStream os = response.getOutputStream();
        //这里修改为PNG,出现 imageioxxxx.tmp 文件的几率小了很多,JPEG则在并发访问的时候,非常容易生成。注视掉该句,图片自然无法在网页显示,并发时,生成imageioxxxx.tmp的现象也随之消失。
        ImageIO.write(image, "NG", os);

        os.flush();
        os.close();
        out.clear();
        out.close();
      } catch (Exception ex) {

      }
%>
附件中也传上了,各位大侠,在你们的linux系统下把这个 验证码的文件放到任何一个 web服务器的目录中,然后通过ie http://您的网络url地址/bug.jsp 就可以看到该验证码生成了,然后按住F5狂刷页面,看看 linux的CPU,看看linux /tmp目录中有没有生成 imageioxxx.tmp的临时文件。
拉兄弟一把,拉兄弟一把,已经被客户训斥得快不行了,网上的验证码几乎都是青一色的使用 ImageIO.write(....) 最后完成动态图片在网页上的显示,难道只有我碰到了该问题?。

bug.rar

1.31 KB, 下载次数: 90

jsp在该论坛中不能直接上传,rar了一下

论坛徽章:
26
处女座
日期:2016-04-18 14:00:4515-16赛季CBA联赛之深圳
日期:2020-06-02 10:10:5015-16赛季CBA联赛之广夏
日期:2019-07-23 16:59:452016科比退役纪念章
日期:2019-06-26 16:59:1315-16赛季CBA联赛之天津
日期:2019-05-28 14:25:1915-16赛季CBA联赛之青岛
日期:2019-05-16 10:14:082016科比退役纪念章
日期:2019-01-11 14:44:062016科比退役纪念章
日期:2018-07-18 16:17:4015-16赛季CBA联赛之上海
日期:2017-08-22 18:18:5515-16赛季CBA联赛之江苏
日期:2017-08-04 17:00:4715-16赛季CBA联赛之佛山
日期:2017-02-20 18:21:1315-16赛季CBA联赛之天津
日期:2016-12-12 10:44:23
2 [报告]
发表于 2008-11-07 10:43 |只看该作者
楼主也在 CSDN里发过吧?

论坛徽章:
0
3 [报告]
发表于 2008-11-07 13:18 |只看该作者
那些图片全在内存里捣鼓,负载大了当然不行了,干脆自己先写在临时文件里,然后再读出来。这样对文件的打开、关闭都可控。只要超过一定时间,就咔嚓掉那个临时文件。

论坛徽章:
0
4 [报告]
发表于 2008-11-07 14:15 |只看该作者
把cache 关了。这样对内存压力比较大
或者写到文件 按照时戳定期清理
这样做 稍微麻烦点

论坛徽章:
0
5 [报告]
发表于 2008-11-12 15:30 |只看该作者
主要是句柄未释放,临时文件空间倒不是问题,郁闷死了,应该大家的系统都有验证码啊,咋就我的这样呢?

论坛徽章:
0
6 [报告]
发表于 2008-11-12 21:04 |只看该作者
try {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(100);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (Exception ex) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
try {
   

写这个做什么?可能就是这个原因。具体访问量多大?

单独写一个类输出图片吧。JSP里写代码不流行了

[ 本帖最后由 ruknow 于 2008-11-12 21:06 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2008-11-28 14:18 |只看该作者
about the tmp file...

you can invoke

ImageIO.setUseCache(false);

to disable the tmp files generation

论坛徽章:
0
8 [报告]
发表于 2008-11-28 14:22 |只看该作者
btw: why "Thread.sleep"  ?  to improve your OS's load ?

no use, take it out

论坛徽章:
0
9 [报告]
发表于 2008-12-15 01:52 |只看该作者
为什么不考虑用一下开源DWR之类的东西呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP