E81086713E446D36F62B2AA2A3502B5EB155

Java杂家

杂七杂八。。。一家之言

BlogJava 首页 新随笔 联系 聚合 管理
  141 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks

#

一直以来,整合Apache HTTP Server和其他Java容器时,可能你最好的选择就是mod_jk,但是mod_jk在Apache和外部Java服务器之间使用socket来进行协议转换,性能不能尽如人意。
正如我上一篇博客里说的,mod_java通过在apache嵌入的JVM中直接执行Java来响应HTTP请求,当然是要快于mod_jk的。

但是缺点是,不是Servlet API(虽然实现Servlet API不是很难,但是工作量肯定很大的),优点是,接口很清晰,很灵活,可以做到的事情也就很多。


那么如何开发一个基于mod_java的java handler呢?OK,假设你要在Apache里响应所有/test/*上的请求.
你要做的是:
1)配置Apache启用mod_java
LoadModule java_module modules/mod_java.so

<mod_java your_main_class>
JVMLibrary D:\jdk6\jre\bin\server\jvm.dll
CurDir D:\apache-tomcat-6.0.14
ADDJVMOpt -Djava.class.path=D:\apache-tomcat-6.0.14\bin\bootstrap.jar;D:\dev\vccode\mod_java\mod_java.jar
ADDJVMOpt -Djava.library.path=D:\apache-tomcat-6.0.14\bin
ADDJVMOpt -Dcatalina.home=D:\apache-tomcat-6.0.14
ADDJVMOpt -Duser.dir=D:\apache-tomcat-6.0.14
ADDJVMParam start
ADDJVMStopParam stop
ADDJavaHandler javatest com.yovn.apache.modj.HelloWorld
</mod_java>
这里main_class是可选的,如果有,那么JVM启动时自动调用main方法。

2)在配置文件里加入你将要开发的Java Handler
想上面文件中的
ADDJavaHandler javatest com.yovn.apache.modj.HelloWorld
这里 javatest是handler名字,后面是你的实现的class
3)在配置文件里告诉Apache 你的handler名字对应的路径
<Location /test>
    SetHandler javatest
</Location>

完成这些配置动作后,apache在收到到/test/*的请求后mod_java会call你的handler class的processRequest方法了。

RequestHandler接口如下定义,你的Handler都需要实现该接口:
package com.yovn.apache.modj;

import java.io.IOException;

/**
 * 
@author yovn
 * 
 
*/
public  interface RequestHandler {

    
public abstract void processRequest(ModJRequest request) throws IOException,
            ModJavaException;

}

正如你看到的很简单的接口,但是ModJRequest就不简单了,该接口代表你跟Apache通行的直接的接口,目前定义如下:

package com.yovn.apache.modj;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.ByteBuffer;

/**
 * 
@author yovn
 *
 
*/
public interface ModJRequest {
    
    
/**
     * 
     * 
@param name
     * 
@return the request header value of that name
     
*/
    String getRequestHeader(String name);
    
    
/**
     * 
     * 
@return similar as HttpServletRequest.getRequestURI()
     
*/
    String getRequestURI();
    
/**
     * 
     * 
@param name header name
     * 
@param value header value
     
*/
    
void setResponseHeader(String name,String value);
    
    
/**
     * 
     * 
@param type 'text/html' etc.. 
     
*/
    
void setContentType(String type);
    
    
/**
     * 
     * 
@param code response code
     
*/
    
void setResponseCode(int code);
    
    
/**
     * 
     * 
@return HTTP method
     
*/
    String getMethod();
    
    
    
/**
     * Give you the  chance when you need push datas to client
     * Also,you can use it to close a connection 
     * Note:
     * HTTP Server may close the connection when it timeout automatically.
     * When you pass use an invalid connection id to call some function , it will failed.
     * 
@see com.yovn.apache.modj.ApacheModule#flushConnection(long, byte[], int, int)
     * 
@see com.yovn.apache.modj.ApacheModule#closeConnection(long)
     * 
@return the connection id for this request.
     
*/
    
long getConnectionId();
    
    
/**
     * same as HttpServletRequest.getServletInputStream
     * 
@return 
     
*/
    InputStream getRequestInputStream();
    
    
/**
     * same as HttpServletResponse.getServletOutputStream
     * 
@return
     
*/
    OutputStream getResponseOutputStream();
    
    
    
/**
     * You should not call the {
@link #getRequestInputStream()} before you call this method this method.
     * In other words, You should either use this method or {
@link #getRequestInputStream()}  to do read data from clients
     * 
@return the direct byte buffer from native side
     * 
@throws IOException
     
*/
    ByteBuffer readTotalRequestBody()
throws IOException;
    
    
    
/**
     * Use apache's apr_send_fd to send a file.
     * Before send file, you may need setup proper HTTP headers, such as 'Content-Disposition' 
     * 
@param fileName
     * 
@return 
     * 
@throws IOException
     
*/
    
boolean sendFile(String fileName)throws IOException;

}
如你所看,基本可以做任何事情(如果还有你想要而没有请一定要告诉我哦)!

下面给个发送文件的例子:

/**
 * 
 
*/
package com.yovn.apache.modj;

import java.io.File;
import java.io.IOException;

/**
 * 
@author yovn
 *
 
*/
public class HelloWorld implements RequestHandler {

    
/**
     * 
     
*/
    
public HelloWorld() {
        
// TODO Auto-generated constructor stub
    }

    
/*
     * (non-Javadoc)
     * 
     * @see com.yovn.apache.modj.RequestHandler#processRequest(ModJRequest request)
     
*/

    
public void processRequest(ModJRequest request) throws IOException,
            ModJavaException {

        request.setContentType(
"APPLICATION/OCTET-STREAM");
    

        File f
=new File("D:\\cspace\\mod_java\\release\\ddd.bin");
        request.setResponseHeader(
"Content-Disposition""attachment;filename=\"ddd.bin\"");
        request.setResponseHeader(
"Content-Length",f.length()+"");
        
        request.sendFile(f.getCanonicalPath());
        

    }

}

下载:
mod_java_0.1

posted @ 2008-06-19 15:38 DoubleH 阅读(4697) | 评论 (5)编辑 收藏

一 。Apache Java Module是什么?

Apache Java Module是一个Apache2.2 Server下的一个模块,这个模块可以嵌入一个JVM,可以无缝地跟Apache整合在一块,从而便于发布高性能的基于Java的HTTP解决方案。

二。为什么要这么做
1)首先,Apache是HTTP服务器市场的领头羊
2)处于性能的考量。
3)Servlet API有它本身的局限性,例如连接相关的信息基本是被隐藏起来了,这样当你想要异步推数据给客户端时,只能去求助Comet了。
4)只要愿意,我可以同时跑Apache和Tomcat,并在一个进程内同时为两个端口服务。
三。示例

目前初步实现了基本框架,一个Hellow,world的例子见下:
首先配置Apache,在conf文件里加上:
LoadModule java_module modules/mod_java.so

<mod_java org.apache.catalina.startup.Bootstrap>
JVMLibrary D:\jdk1
.6\jre\bin\server\jvm.dll
CurDir D:\apache-tomcat-
6.0.10
ADDJVMOpt -Djava.class.path
=D:\apache-tomcat-6.0.10\bin\bootstrap.jar;D:\cspace\mod_java\mod_java.jar
ADDJVMOpt -Djava.library.path=D:\apache-tomcat-6.0.10\bin
ADDJVMOpt -Dcatalina.home
=D:\apache-tomcat-6.0.10
ADDJVMOpt -Duser.dir
=D:\apache-tomcat-6.0.10
ADDJVMParam start
ADDJVMStopParam stop
ADDJavaHandler javatest com.yovn.apache.modj.HelloWorld
</mod_java>
<Location /javatest>
    SetHandler javatest
</Location>

这段配置脚本,同时会启动一个Tomcat在一个新的线程。
并且,当你请求/javatest/*时,自动会执行com.yovn.apache.modj.HelloWorld来满足这个请求,下面看
这个示例程序:

/**
 * 
 
*/
package com.yovn.apache.modj;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;

/**
 * 
@author yovn
 *
 
*/
public class HelloWorld implements RequestHandler {

    
/**
     * 
     
*/
    
public HelloWorld() {
        
// TODO Auto-generated constructor stub
    }

    
/* (non-Javadoc)
     * @see com.yovn.apache.modj.RequestHandler#processRequest(java.lang.String, int, long, long, java.io.InputStream, java.io.OutputStream)
     
*/
    @Override
    
public void processRequest(String url, int method, long req, long conn,
            InputStream in, OutputStream out) 
throws IOException,
            ModJavaException {
    

        //ApacheModule.setHeader(req, "X-Server", "mod_java");
        out.write("<html><head><title>Hello,World</title></head><body><h1>Hello,World</h1></body></html>".getBytes());
        out.close();

        

    }

}
这是个很简单的程序,当你在浏览器输入http://host:apache_port/javatest/时,显示Hello,World.

目前读取输入数据尚未实现,等完善了我再提供下载文件。


posted @ 2008-06-18 00:05 DoubleH 阅读(2064) | 评论 (1)编辑 收藏

问题背景
面对艰巨复杂的技术挑战,百度所崇尚的系统设计哲学是“简单可依赖”,而百度的工程师们正在互联网世界中实践着这种理念。这里正好有一个挑战,让作为百度之星的你小试牛刀:

在处理数以百亿计的网络信息的过程中,有一个很常见的问题: 
怎么样将一个集群上的信息以最低的成本传输到另外一个集群上?


数据源集群A有n台服务器,编号为 1, 2, ..., n,i号服务器上待传输的数据量为Ai ,单位是GB。 
目的地集群B有m台服务器,编号为 1, 2, ..., m,j号服务器上的空闲容量为 Bj,单位为 GB。 
A集群的i号服务器上的每GB数据对于B的集群的j号服务器收益为Vi,j,从 A 集群的 i 号服务器向 B 集群的 j 号服务器传输 1GB数据的开销为Ci,j。 
你的任务是在保证A中的所有数据传输完毕的前提下,性价比V/C尽量高。其中V为所有数据在B集群上的价值之和,C为总开销。换句话说,若A集群的i号服务器向B集群的j号服务器发送了Ti,j个GB的数据(Ti,j不一定是整数),则性价比定义为:





输入格式
第1行两个整数n, m(1<=n,m<=50),即集群A和B各自的服务器台数。
第2行包含n个不超过100的正整数A1,A2,…,An,即集群A中每台服务器的待传输数据量(单位:GB)。
第3行包含m个不超过100的正整数B1,B2,…,Bm,即集群B中每台服务器所能接受的最大数据量(单位:GB)。
第 4 ~ n+3 行每行包含m个不超过100的非负整数Vi,j,表示集群A的i号服务器中每GB数据对于集群B中的j号服务器的价值。
第 n+4 ~ 2n+3 行每行包含m个不超过100的正整数Ci,j,表示集群A的i号服务器中每GB数据传输到集群B中的j号服务器所需要的开销。 

输出格式
仅一行,为最大性价比。输出保留三位小数(四舍五入)。如果A的数据无法传输完毕,输出字符串 “-1”(无引号)。 

样例输入
2 2
1 2
2 1
11 0
7 5
6 1
3 2 

样例输出
2.091 

样例解释
一个方案是:
集群A的1号服务器把所有数据传输到集群B的1号服务器,价值11,开销6。
集群A的2号服务器把1GB数据传输到集群B的1号服务器,价值7,开销3,然后把剩下的1GB数据传输到集群B的2号服务器,价值5,开销2。
性价比:(11+7+5)/(6+3+2)=2.091

另一个方案是:
集群A的1号服务器把所有数据传输到集群B的2号服务器,价值0,开销1。
集群A的2号服务器把所有数据传输到集群B的1号服务器,价值14,开销6。
性价比:(0+14)/(1+6)=2。

第一种方案更优

我的解答:
该题应该是贪心法可解,每次求性价比最高的,跟部分背包问题很像。
可惜不是,子问题不是独立的,我的解法肯定不是最优解。sign~~~,据说是最大流的问题,改天研究研究。
我的解法用了N+1个最大值堆,一个是全局所有为传输完的源站点的最高性价比方案,
其余每个源站点一个最大值堆含该站点所有传输方案。

//============================================================================
// Name        : TransportOpt.cpp
// Author      : Yovn
// Version     :
// Copyright   : yovnchine@gmail.com
//============================================================================

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>

using namespace std;



int numA;
int numB;
int* valuesA;
int* valuesB;
int** values=NULL;
int** costs=NULL;


typedef struct _HeapNode
{
    int a;
    int b;
    float vPerC;
   
}HeapNode;
class MaxHeap
{
public:
    MaxHeap(int n):nodes(new HeapNode[n]),total(n),len(0){
       
    }
    MaxHeap():nodes(NULL),total(0),len(0){
           
    }
    ~MaxHeap()
    {
        delete[] nodes;
    }
    bool isEmpty()
    {
        return len<=0;
    }
    void setSize(int n)
    {
        nodes=new HeapNode[n];
        total=n;
        len=0;
    }
    HeapNode removeMax()
    {
       
        HeapNode ret=nodes[0];
        nodes[0]=nodes[--len];
        shift_down(0);
        return ret;
    }
    void insert(HeapNode val)
    {
       
        nodes[len++]=val;
        shift_up(len-1);
    }
   
private :
   
   
    void shift_up(int pos) {

        HeapNode tmp=nodes[pos];
        int index=(pos-1)/2;
   
        while (index>=0) {
            if (tmp.vPerC>nodes[index].vPerC) {
                nodes[pos]=nodes[index];
                pos=index;
                if (pos==0)
                    break;
                index=(pos-1)/2;
            } else
                break;
        }
        nodes[pos]=tmp;
    }
    void shift_down(int pos) {

        HeapNode tmp=nodes[pos];
        int index=pos*2+1;//use left child
        while (index<len)//until no child
        {
            if (index+1<len&&nodes[index+1].vPerC>nodes[index].vPerC)//right child is smaller
            {
                index+=1;//switch to right child
            }
            if (tmp.vPerC<nodes[index].vPerC) {
                nodes[pos]=nodes[index];
                pos=index;
                index=pos*2+1;

            } else {
                break;
            }

        }
        nodes[pos]=tmp;
       
    }
    HeapNode* nodes;
    int total;
    int len;


   
};

void parseToInts(string& line, int* arr, int num) {
    int pos=0;
    for (int i=0; i<line.length(); i++) {
        if (line[i]>='0'&&line[i]<='9') {
            if (line[i+1]>='0'&&line[i+1]<='9') {
                int a=(line[i]-'0')*10+(line[i+1]-'0');
                arr[pos++]=a;
                i++;
            } else {
                int a=(line[i]-'0');
                arr[pos++]=a;
               
            }
           
        }
    }
}
void input()
{
    string line;
    getline(cin,line);
   
    sscanf(line.c_str(),"%d %d",&numA,&numB);
    valuesA=new int[numA];
    valuesB=new int[numB];
    line.clear();
    getline(cin,line);
    parseToInts(line,valuesA,numA);
   
    line.clear();
    getline(cin,line);
    parseToInts(line,valuesB,numB);
   
  
    values=new int*[numA];
    costs=new int*[numA];
    for (int i=0; i<numA; i++) {
        values[i]=new int[numB];
        line.clear();
        getline(cin, line);
        parseToInts(line, values[i], numB);
    }
   
    for (int i=0; i<numA; i++) {
        costs[i]=new int[numB];
        line.clear();
        getline(cin, line);
        parseToInts(line, costs[i], numB);
    }
   
   
   
}
bool validate() {
    int sumA=0, sumB=0;
    for (int i=0; i<numA; i++) {
        sumA+=valuesA[i];
    }
    for (int i=0; i<numB; i++) {
        sumB+=valuesB[i];
    }
    return sumA<=sumB;
}
void calc() {
    MaxHeap totalHeap(numA);
    MaxHeap* aHeaps=new MaxHeap[numA];
    int totalC=0;
    int totalV=0;

    if(!validate())
    {
        printf("-1\n");
        return;
    }
    for (int i=0; i<numA; i++) {

        aHeaps[i].setSize(numB);
        for(int j=0;j<numB;j++)
        {
            HeapNode node;
            node.a=i;
            node.b=j;
            node.vPerC=(float)values[i][j]/(float)costs[i][j];
            aHeaps[i].insert(node);
        }
        totalHeap.insert(aHeaps[i].removeMax());
    }
    while(!totalHeap.isEmpty())
    {
        HeapNode node=totalHeap.removeMax();
   
        if(valuesA[node.a]==valuesB[node.b])
        {
            totalV+=values[node.a][node.b]*valuesA[node.a];
            totalC+=costs[node.a][node.b]*valuesA[node.a];
            valuesB[node.b]=0;
            valuesA[node.a]=0;
           
        }
        else if(valuesA[node.a]>valuesB[node.b])
        {
            totalV+=values[node.a][node.b]*valuesB[node.b];
            totalC+=costs[node.a][node.b]*valuesB[node.b];
            valuesA[node.a]-=valuesB[node.b];
            valuesB[node.b]=0;
           
        }
        else
        {
            totalV+=values[node.a][node.b]*valuesA[node.a];
            totalC+=costs[node.a][node.b]*valuesA[node.a];
            valuesB[node.b]-=valuesA[node.a];
           
            valuesA[node.a]=0;
       
        }
        while(!aHeaps[node.a].isEmpty())
        {
            HeapNode todo=aHeaps[node.a].removeMax();
            if(valuesA[todo.a]>0&&valuesB[todo.b]>0)
            {
                totalHeap.insert(todo);
                break;
            }
        }
    }
    printf("%lf\n",(float)totalV/totalC);
}
int main() {
   
    input();
    calc();
   
    return 0;
}




posted @ 2008-06-01 18:53 DoubleH 阅读(2433) | 评论 (0)编辑 收藏

问题背景

有一种简单的网页判重的方法,通过求两个网页内容的最长公共子序列(LCS)长度来判定两个网页的相似程度。如:
(网页A)老师:请用“果然”造句。
(网页B)学生:先吃水果,然后喝汽水……
它们的最长公共子序列为“果然”,长度为2。注意这里的“子序列”并不要求连续。

类似的,下面两个网页:
(网页A)老师:请用“果然”造句。
(网页B)学生:先吃水果,然后喝汽水,果然拉肚子……

最长公共子序列还是“果然”,长度为2。但不难看出,由于“果然”两个字在网页B中也曾连续出现,第二组网页比第一组更加“相似”。为了区分开这两种情况的区分度,我们改用一种称为LZW的理论。为了严格的叙述相似度的计算方法,我们首先定义“文本单元”。

假定网页用一个不包含空白字符(空格、回车换行、水平制表符)的字符串来表示。它只包含纯文本,没有标签。在计算相似度之前,你应该首先对该字符串进行处理,划分成一个个“文本单元”。每个文本单位可以是一个中文字、英文单词(由一个或多个连续的半角英文字母和数字组成,正规表达式为[a-zA-Z0- 9]+)、或者一个标点符号。

根据上述定义,同一个标点符号的全角和半角应该被作为不同的文本单元,尽管他们看起来可能很相近;每个单独全角英文和全角数字都应该被看成一个单独的文本单元,而连续的半角英文字母和数字应被看成一个整体。总之,全角的字符可以与中文字同等对待。

这样,网页被看成文本单元序列。例如,网页“内容?123456??web2.00#”切分出的文本单元序列为(为了显示方便,用下划线分隔各文本单元):
内_容_?_1_2_345_6_?_?_web2_._00_#

而网页“why内容相似??1234567890,web#00”的切分结果为:
why_内_容_相_似_?_?_1234567890_,_web_#_00

黑体部分给出了两个网页的一个公共子序列。注意“内容”、“??”分别在两个网页中都是连续出现的文本单元。为了奖励这种情况,LZW规定一段由连续k个文本单元组成的字符串权值为k^2。在刚才的例子中,“内容”、“??”的权值均为4。但“00”是一个数字串,应当被看成一个单独的文本单元。所以权值仅为1。

根据上述规则,公共子序列“内容 ?? 00”的权值为2^2+2^2+1=9。在所有可能的子序列中,这个权值是最大的。

给定两个网页,求他们的LZW相似度,即所有可能的公共子序列中的最大权值。

注意

1) 输入的网页内容以GBK编码(参见FAQ)
2) 除了大小写英文字母和数字之外的其他半角字符均视为标点符号。
输入格式

包含两行,分别是网页A和B对应的字符串(不包含空白字符)。每行至少包含5个字节,最多包含200个字节。
输出格式

输出仅一行,包含一个整数,为两个网页的LZW相似度。
样例输入

内容?123456??web2.00#
why内容相似??1234567890,web#00
样例输出
9


解答:
该题主要分两部分,一部分就是解析成文本单元,另一部分就是LZW的实现,LZW其实是最长公共子序列算法的一个变形。

//============================================================================
// Name        : LZW.cpp
// Author      : Yovn
// Version     :
// Copyright   : yovnchine@gmail.com
//============================================================================

#include 
<iostream>
#include 
<string>
#include 
<cstring>
using namespace std;

void parseToLZWLine(const char* in, int inLen, char**& out, int& actualLen) {
    
int mark=0;
    actualLen
=0;
    out
=new char*[inLen];

    
for (int i=0; i<inLen; i++) {
        
char ch=in[i];
        
if (ch<0) {
            
if (mark<i) {
                out[actualLen]
=new char[i-mark+1];
                strncpy(out[actualLen], in
+mark, i-mark);
                out[actualLen][i
-mark]='\0';
                actualLen
++;
            }
            out[actualLen]
=new char[3];
            out[actualLen][
0]=ch;
            out[actualLen][
1]=in[++i];
            out[actualLen][
2]='\0';
            actualLen
++;

            mark
=i+1;
        } 
else if ((ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9')) {
            
continue;
        } 
else//only one case left
        {
            
if (mark<i) {
                out[actualLen]
=new char[i-mark+1];
                strncpy(out[actualLen], in
+mark, i-mark);
                out[actualLen][i
-mark]='\0';
                actualLen
++;

            }
            out[actualLen]
=new char[2];
            out[actualLen][
0]=ch;
            out[actualLen][
1]='\0';
            actualLen
++;
            mark
=i+1;
        }
    }
    
if (mark<inLen) {
        out[actualLen]
=new char[inLen-mark+1];
        strncpy(out[actualLen], in
+mark, inLen-mark);
        out[actualLen][inLen
-mark]='\0';
        actualLen
++;

    }
}
void printLZWStr(char** lzwStr, int lzwLen) {
    
for (int i=0; i<lzwLen; i++) {
        printf(
"%s", lzwStr[i]);
        
if (i<lzwLen-1) {
            printf(
"_");
        }
    }
    printf(
"\n");
}
void freeLZWStr(char** lzwStr, int lzwLen) {
    
for (int i=0; i<lzwLen; i++) {
        delete[] lzwStr[i];
    }
    delete[] lzwStr;
}

int calcLZW(char** left, int leftLen, char** right, int rightLen) {
    
//printLZWStr(left, leftLen);
    
//printLZWStr(right, rightLen);
    int** result=new int*[leftLen+1];
    
int** len=new int*[leftLen+1];
    
for (int i=0; i<=leftLen; i++) {
        result[i]
=new int[rightLen+1];
        len[i]
=new int[rightLen+1];
        result[i][
0]=0;
        len[i][
0]=0;
    }
    memset(result[
0], 0, sizeof(int)*(rightLen+1));
    memset(len[
0], 0, sizeof(int)*(rightLen+1));
    
for (int i=1; i<=leftLen; i++) {
        
for (int j=1; j<=rightLen; j++) {
            
if (strcmp(left[i-1], right[j-1])==0) {
                
//back trace one

                len[i][j]
=len[i-1][j-1]+1;
                result[i][j]
=result[i-1][j-1]-(len[i-1][j-1]*len[i-1][j-1])
                        
+(len[i][j]*len[i][j]);

            } 
else if (result[i-1][j]>=result[i][j-1]) {
                result[i][j]
=result[i-1][j];
            } 
else {
                result[i][j]
=result[i][j-1];
            }

        }
    }

    
int ret= result[leftLen][rightLen];
    
for (int i=0; i<=leftLen; i++) {
        delete[] result[i];
        delete[] len[i];

    }
    delete[] result;
    delete[] len;
    
return ret;

}

int main() {
    
char** lzwStr1=NULL;
    
char** lzwStr2=NULL;
    string str1;
    string str2;
    
int lzwLen1=0;
    
int lzwLen2=0;
    getline(cin,str1);
    getline(cin,str2);
    
    parseToLZWLine(str1.c_str(), strlen(str1.c_str()), lzwStr1, lzwLen1);
    parseToLZWLine(str2.c_str(), strlen(str2.c_str()), lzwStr2, lzwLen2);

    cout
<<calcLZW(lzwStr1, lzwLen1, lzwStr2, lzwLen2)<<endl;

    freeLZWStr(lzwStr1, lzwLen1);
    freeLZWStr(lzwStr2, lzwLen2);

    
return 0;
}



posted @ 2008-05-31 23:20 DoubleH 阅读(2419) | 评论 (3)编辑 收藏

如果Web服务器需要频繁传送文件给客户端时,大多数web容器会提供异步发送的支持,像IIS中的通过ServerSupportFunction(),Apache里面apr_sendfile(),Tomcat6.X通过设置Servlet Request的请求属性等等。。。都可以做到异步发送文件,从而提高服务器性能。

Jetty6.X默认也不提供相关支持,本文提供一种hack方法,仅供参考:

先看测试Servlet:
package com.yovn.labs.testweb;

import java.io.File;
import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.yovn.labs.sendfile.JettySendFile;
import com.yovn.labs.sendfile.NormalSendFile;
import com.yovn.labs.sendfile.SendFile;

/**
 * 
@author yovn
 *
 
*/
public class SendFileServlet extends HttpServlet {

    
protected void doGet(HttpServletRequest req, HttpServletResponse res)
            
throws ServletException, IOException {
    
        
        
try {
            
            File f
=new File("D:\\workspace\\TEST.rar");//about 45M
            String action
=req.getParameter("action");
            SendFile sf
=null;
            
if("1".equals(action))
            {
                sf
=new JettySendFile();
            }
            
else
            {
                sf
=new NormalSendFile();
            }
            
long start=System.currentTimeMillis();
            sf.doSend(req, res, f, 
null);
            System.out.println(
" service ok, action="+action+",use:"+(System.currentTimeMillis()-start)+"!!!");
        } 
catch (Exception e) {
            
throw new ServletException(e);
        }
      
    }
    
    

}
代码很简单明了,action=1时使用Jetty的异步发送,action=2时使用正常方式。

下面是通过firefox直输入地址回车后,下载文件,后台的程序运行结果:
 service ok, action=1,use:62!!!
 service ok, action
=2,use:10688!!!
 service ok, action
=2,use:9063!!!
 service ok, action
=1,use:47!!!
当运行1时,实际上客户端还没有下完文件,但是该段代码已经执行完了,IO的操作是异步的。
当运行2时,客户端下完代码才执行完。

以下是Jetty异步发送的代码:
package com.yovn.labs.sendfile;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.mortbay.io.EndPoint;
import org.mortbay.io.nio.NIOBuffer;

/**
 * 
@author yovn
 *
 
*/
public class JettySendFile implements SendFile {

    
static Field endpointField=null;
    
static Class reqCls=null;
    
static 
    {
        
try {
            reqCls
=Class.forName("org.mortbay.jetty.Request");
            endpointField
=reqCls.getDeclaredField("_endp");
            endpointField.setAccessible(
true);
        } 
catch (Exception e) {
            
// TODO Auto-generated catch block
            e.printStackTrace();
        } 
    }
        
    
    


    
public void doSend(HttpServletRequest req, HttpServletResponse res,File todo,String headerOpt)
            
throws IOException {
        
        
if(endpointField==null)throw new IOException("Jetty Not Available!!");
        
if(!req.getClass().equals(reqCls))
        {
            
throw new IOException("Not in Jetty Context!!");
        }
        EndPoint ep;
        
try {
            ep 
= (EndPoint)endpointField.get(req);
        
            
if(headerOpt==null)
            {
                headerOpt
="HTTP/1.1 200 OK \r\nContent-Type: APPLICATION/OCTET-STREAM\r\n"+
                      
"Content-Disposition: attachment;filename=\""+todo.getName()+"\"\r\n"+
                      
"Content-Length: "+todo.length()+"\r\n\r\n";
            }
            
byte[] headerBytes=headerOpt.getBytes("UTF-8");
            NIOBuffer header
=new NIOBuffer(headerBytes.length,false);
            header.put(headerBytes);
            
            NIOBuffer buffer
=new NIOBuffer(todo);
            
            ep.flush(header, buffer, 
null);
        } 
catch (IllegalArgumentException e) {
            
throw new IOException(e);
        } 
catch (IllegalAccessException e) {
            
throw new IOException(e);
        }
        
        
        
    }

}

正常发送文件的代码:
package com.yovn.labs.sendfile;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 
@author yovn
 *
 
*/
public class NormalSendFile implements SendFile {

    
/* (non-Javadoc)
     * We simply ignore the 'headerOpt'
     * @see com.yovn.labs.sendfile.SendFile#doSend(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.io.File, java.lang.String)
     
*/
    
public void doSend(HttpServletRequest req, HttpServletResponse res,
            File todo, String headerOpt) 
throws IOException {
        res.setHeader(
"Content-Type""APPLICATION/OCTET-STREAM");
        res.setHeader(
"Content-Disposition""attachment;filename=\""+todo.getName()+"\"");
        res.setHeader(
"Content-Length", todo.length()+"");
        res.setStatus(HttpServletResponse.SC_OK);
        OutputStream out
=res.getOutputStream();
        InputStream in
=new FileInputStream(todo);
        
        
byte[] buffer=new byte[8192];
        
        
int read=0;
        
while((read=in.read(buffer))>0)
        {
            out.write(buffer, 
0, read);
        }
        out.flush();
        in.close();
        
        

    }

}


posted @ 2008-03-29 01:54 DoubleH 阅读(1763) | 评论 (0)编辑 收藏

过道里依次挂着标号是1,2,3, ......,100的电灯泡,开始它们
都是灭着的。当第一个人走过时,他将标号为 1 的倍数的电灯泡的开关
线拉了一下;当第二个人走过时,他将标号为 2 的倍数的电灯泡的开关
线拉了一下;当第三个人走过时,他将标号为 3 的倍数的电灯泡的开关
线拉了一下;......  如此进行下去,当第一百个人走过时,他将标号为
100 的倍数的电灯泡的开关线拉了一下。
问:当第一百个人走过后,过道里亮着的电灯泡标号是多少?


我的思路:
设标号为K的灯泡被拉了L(K)次,那么当L(K)为奇数的时候,灯泡是亮的。
那么那些标号被拉了奇数次呢?
K=1时,很显然是只拉了1次,最后是亮的。
其次K>=2时,据题意,K号灯第1次,和第K次肯定是拉下了,其余的只会被第K的因子次拉,
据因式分解定理,数K分解为
K=p1^(n1)*p2^(n2)*.....pi^(ni)
其中p1,p2,...pi为素数。
那么,K有那些因子呢?
其实可以考虑任一个因子,他可能是从n1个p1中选若干个(0个到n1个),从n2个p2中选若干个。。。。。(当全是0个的时候,这个特殊的因子是1)
这样,根据乘法原理,总共有L(K)=(n1+1)*(n2+1)*(n3+1).....
比如,12=2^2*3
一种有3*2=6个因子,他们是1,2,3,4,6,12.

现在考虑要使L(K)为奇数,那么n1,n2,n3不能有一个是奇数,或则,有一个ni+1为偶数,而偶数与任何数相乘仍为偶数。
从而,n1,n2,n3都为偶数,都能被2除。
因为n1,n2,n3都为偶数,显然该数必须是个平方数,可写成K=(X)^2.
从而,1,4,9,16,25,36,49,64,81,100最后是亮的。

posted @ 2008-03-05 15:00 DoubleH 阅读(2104) | 评论 (7)编辑 收藏

去年也大概是这个时候写了第一个Java2EXE,之后又加了写特性,但是每次我看代码都感觉惨不忍睹,很混乱,而且编译,链接的过程也有点绕。
现在又过了一年了,如果说上次版本的Load过程主要是靠Java(Java加密,解压),那么这次基本把这些费时的操作全交给CPP了。
好了,总结一下这次的改动
1)Loader以及Starter完全是CPP代码,结构很清晰了。
2)加密以及解压交给CPP,速度比以前快了。
3)整合了JNative,这个是重点,下文详述。
4)生成工具用MFC写,一个简单的向导。

OK,那么JNative是干什么的呢?
官方的描述是 “JNative, Java framework for DLL access for Windows and Linux”
就是说,有了这个框架,你访问DLL里的方法就不再需要写DLL了,只需要写Java Code了,可能有人问它是怎么做到的呢?
假如说你要访问Kernel32.dll里的某个方法A,你首先需要这个方法的句柄,这个句柄就是通过new一个org.xvolks.jnative.JNative实例来保持的,
类似如:
org.xvolks.jnative.Native methodA=new org.xvolks.jnative.JNative("Kernel32.dll","A");
有了这个句柄,你只要在上面设置参数,返回值,以及类型就可以调用它了。每个调用它上面的JNI里的本地方法就会自动来进行参数解析,解码,调用到目标DLL方法,这个过程基本不可避免需要少量的汇编代码。
JNative为了可移植性,代码是在Cygwin下可编译的,没有MSVC可编译的版本。

对此,本人改了部分代码用于直接一起链接(主要是把GCC嵌入汇编改为对应的MSVC的嵌入汇编代码),而不是让JNative生成一个动态链接库。

如上,由于JNative改成了静态库,程序发布的时候,只要是通过Java2EXE Builder来创建成EXE的话,你就不需要那个JNativeCpp.dll文件了,只有一个EXE.

你调试的时候可以用官方的版本,发布就只要你的代码(JNative的class也都在集成在生成工具里,不需要你自己添加进来)。

来看个简单的例子,我们从Java代码里取得当前进程的全路径名:
import org.xvolks.jnative.JNative;
import org.xvolks.jnative.Type;
import org.xvolks.jnative.exceptions.NativeException;
import org.xvolks.jnative.pointers.Pointer;
import org.xvolks.jnative.pointers.memory.HeapMemoryBlock;

/**
 * DWORD GetModuleFileName(
 * HMODULE hModule,
 * LPTSTR lpFilename,
 * DWORD nSize
 *);

 * 
@author yovn
 *
 
*/
public class TestReadProcessPath {

    
/**
     * 
     * 
@param args
     * 
@throws NativeException 
     * 
@throws IllegalAccessException 
     
*/
    
public static void main(String[] args) throws NativeException, IllegalAccessException {
        JNative v
=new JNative("Kernel32.dll","GetModuleFileNameA");
        
int i = 0;
        v.setRetVal(Type.INT);
        Pointer pName 
= new Pointer(new HeapMemoryBlock(1024));
        
        v.setParameter(i
++0);//module handle
        v.setParameter(i++, pName);//pFileName
        v.setParameter(i++1024);//nSize
        v.setRetVal(Type.INT);
        v.invoke();
        
int ret = Integer.parseInt(v.getRetVal());
        
if (ret == 0) {
            
// return "null";
            System.err.println(
                    
"GetModuleFileName failed!");
        } 
else {
            
            String path 
= pName.getAsString().substring(0,
                    ret);
            pName.dispose();
            v.dispose();
            System.out.println(
"current process's path is:"+path);
        }
    }

}

编译,把这个文件单独打包成一个jar文件,下面是个用这个工具生成EXE的截图:
生成EXE向导第一步
生成 EXE向导第二步



请从这里下载 Java2EXE Builder Platform











posted @ 2008-02-26 00:31 DoubleH 阅读(1798) | 评论 (7)编辑 收藏

     摘要: 红黑树可能是要考虑情况最多的BST树了,它有自己的规则(见代码的注释),通过这些规则可以保证花费较小的代价来达到相对平衡。 注意,红黑树仍然不是平衡树,但是统计性能要好于AVL树。 要保持红黑树的规则,主要通过两类操作,一类是换色,一类还是旋转。 红黑树插入主要要解决红-红冲突,而删除主要则解决“双黑” 同样,红黑树的删除节点实现是最复杂的,不过,复杂也就在于考...  阅读全文
posted @ 2007-12-20 18:25 DoubleH 阅读(8468) | 评论 (20)编辑 收藏

     摘要: 伸展树与半伸展树属于自组织的数据结构,能按访问频率调整节点的位置 调整一般通过如下方式: 1)绕根的单旋转,跟AVL的单旋转类似 2)一字型旋转(ZigZig Rotation) 3)之字形旋转(ZigZag Rotation) 旋转操作较简单,有点点繁琐。 半伸展树不做完全的一字型旋转,它只让父节点绕祖父节点做单旋转。 不管怎样,每次访问(插入/查找 ,删除时展开被删除父节...  阅读全文
posted @ 2007-12-19 00:39 DoubleH 阅读(2392) | 评论 (0)编辑 收藏

     摘要: AVL树的是一种平衡的二叉搜索树。每次插入,删除的时候需要一个局部的平衡化操作。 实现AVL树的插入操作一般不是很难,清楚的理解了平衡因子以及旋转操作实现起来就没多大问题了。 难点一般在于删除操作的实现,教科书上一般用很大的篇幅来详细说明各种情况,看起来很凌乱,理解起来很是费劲。考虑到可以把删除操作看成插入操作的逆操作,这里我给出另一种较为清晰的实现方式: 1)删除的时候做一个标记的过程 ...  阅读全文
posted @ 2007-12-18 18:30 DoubleH 阅读(3597) | 评论 (0)编辑 收藏

仅列出标题
共5页: 上一页 1 2 3 4 5 下一页