精华内容
下载资源
问答
  • 如何编写一个MapReduce程序

    千次阅读 2019-01-28 13:10:40
    这篇来说说编写一个MapReduce程序都需要做哪些事情. 大体上要编写三个模块:map类,reduce类,以及驱动. Map 我们编写的map类需要继承org.apache.hadoop.mapreduce.Mapper.在打开Mapper类之后,会看到几个方法以及一...

    这篇来说说编写一个MapReduce程序都需要做哪些事情.

    大体上要编写三个模块:map类,reduce类,以及驱动.

    Map

    我们编写的map类需要继承org.apache.hadoop.mapreduce.Mapper.在打开Mapper类之后,会看到几个方法以及一个类:

    public class Mapper<KEYIN, VALUEIN, KEYOUT, VALUEOUT> {
    
      public abstract class Context
        implements MapContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
      }
      
      protected void setup(Context context
                           ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      @SuppressWarnings("unchecked")
      protected void map(KEYIN key, VALUEIN value, 
                         Context context) throws IOException, InterruptedException {
        context.write((KEYOUT) key, (VALUEOUT) value);
      }
    
      protected void cleanup(Context context
                             ) throws IOException, InterruptedException {
        // NOTHING
      }
      
      public void run(Context context) throws IOException, InterruptedException {
        setup(context);
        try {
          while (context.nextKeyValue()) {
            map(context.getCurrentKey(), context.getCurrentValue(), context);
          }
        } finally {
          cleanup(context);
        }
      }
    }

    有一个Context类,这个类在编写reduce类需要继承的org.apache.hadoop.mapreduce.Reducer类中也存在.只不过Mapper中的Context实现的是MapContext类,Reducer中实现的是ReduceContext类.

    然后还包含4个方法:setup(),map(),cleanup(),run().我们可以在run()中看到其他三个方法的执行顺序:先执行setup(),在try{}中执行map(),在finally中执行cleanup().都将Context实例作为参数传入.

    setup()主要用来执行map()之前的一些准备工作,比如要进行join操作的时候,就可以利用setup()先将小表加载进来.默认方法体中没有任何代码,我们如果需要前期准备工作,就需要重写它.

    接下来看看try{}中的map().可以通过方法名看出具体的逻辑:当有下一个KV对,就执行一次map(),map()中有3个参数:当前的key,当前的value,Context实例.看起来有点像迭代器:

    //假设存在一个Iterator对象it.
        whille(it.hasNext()){
            it.next();
            //其他代码
        }

    nextKeyValue()跟hasNext()很相似,map()跟next()很相似,当然Context并没有实现迭代器接口,只是看起来相似.

    将参数传入之后,就执行我们编写的map()中的逻辑对数据进行处理.

    最后是cleanup(),既然在finally{}中,回想之前的异常处理,就表示无论如何都要执行一次,默认同setup()一样,没有任何代码,如果需要在map()执行完毕后需要一些善后工作,我们需要重写这个方法.

    然后我们来看看我们自己编写的map,这里以我写的词频统计为例,输入文件为Hadoop中的README.txt:

    class Map extends Mapper<LongWritable,Text,Text,LongWritable>{
                          //       1        2   3        4
        protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
            String[] words = value.toString().split(" ");
            for (String word: words)
                context.write(new Text(word),new LongWritable(1));
        }
    }

    这里没有重写setup()与cleanup(),只重写了map().特殊情况下,map()也不需要重写,直接利用Mapper提供的map即可.

    首先看Mapper后面的四个泛型,意义分别是:1.map()输入key类型,2.map()输入value类型,3.map()输出key类型,4.map()输出value类型.一般来说,由于map()的处理结果需要传输至reduce(),所以3和4需要和reduce类的1和2相匹配.

    参数1,2被传入map(),作为输入KV的类型.中间是对输入的KV进行处理,此处是将传入的value用空格切割,返回一个String数组,在这里,输入的key是行号,value是文本文档中的一行文本.最后有一个context.write(),两个参数的类型应该与参数3,4匹配,此处将处理结果写入至Context,然后传输至reduce.这里context.write()就是将每个单词创建一个Text对象作为输出key,创建一个LongWritable对象,将值设为1,作为输出value,在reduce()中,会对同key的value进行累加,以获得(单词,出现次数)这样的结果.

    Reduce

    我们编写的reduce同样需要继承org.apache.hadoop.mapreduce.Reducer,我们也来看看它的源码:

    public class Reducer<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
    
      public abstract class Context 
        implements ReduceContext<KEYIN,VALUEIN,KEYOUT,VALUEOUT> {
      }
    
      protected void setup(Context context
                           ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      @SuppressWarnings("unchecked")
      protected void reduce(KEYIN key, Iterable<VALUEIN> values, Context context
                            ) throws IOException, InterruptedException {
        for(VALUEIN value: values) {
          context.write((KEYOUT) key, (VALUEOUT) value);
        }
      }
    
      protected void cleanup(Context context
                             ) throws IOException, InterruptedException {
        // NOTHING
      }
    
      public void run(Context context) throws IOException, InterruptedException {
        setup(context);
        try {
          while (context.nextKey()) {
            reduce(context.getCurrentKey(), context.getValues(), context);
            // If a back up store is used, reset it
            Iterator<VALUEIN> iter = context.getValues().iterator();
            if(iter instanceof ReduceContext.ValueIterator) {
              ((ReduceContext.ValueIterator<VALUEIN>)iter).resetBackupStore();        
            }
          }
        } finally {
          cleanup(context);
        }
      }
    }

    除了Context实现换成了ReduceContext,与run()中的逻辑略有不同之外,其余的都跟Mapper中一样.

    再来看看词频统计的reduce,同样是使用我编写的代码为例:

    class Reduce extends Reducer<Text,LongWritable,Text,LongWritable>{
                            //     1       2         3        4
        protected void reduce(Text key, Iterable<LongWritable> values, Context context) 
                            throws IOException, InterruptedException {
            long count = 0;
            for (LongWritable number: values)
                count += number.get();
            context.write(key,new LongWritable(count));
        }
    }
    

    同样没有重写setup()与cleanup().传入的KV的类型,参数1,2对应了map的参数3,4.而最终的输出结果,参数3,4就可以定义为自己所需要的类型.整个方法的逻辑是,首先定义一个long类型的数据用来统计数据,在for循环中进行累加,最后在context.write()中写入key与它出现的次数.

    驱动

    public class WordCount {
        public static void main(String[] args) throws Exception{
            String inputPath = "E:\\Hadoop\\READMEtxt";                //1
            String outputPath = "E:\\Hadoop\\output";                  //2
            Job job = Job.getInstance(new Configuration());            //3
            job.setJarByClass(WordCount.class);                        //4
            job.setMapperClass(Map.class);                             //5
            job.setReducerClass(Reduce.class);                         //6
            job.setCombinerClass(Reduce.class);                        //7
            job.setMapOutputKeyClass(Text.class);                      //8
            job.setMapOutputValueClass(LongWritable.class);            //9
            job.setOutputKeyClass(Text.class);                         //10
            job.setOutputValueClass(LongWritable.class);               //11
            FileInputFormat.addInputPath(job,new Path(inputPath));     //12
            FileOutputFormat.setOutputPath(job,new Path(outputPath));  //13
            job.waitForCompletion(true);                               //14
        }
    }

    1和2就是输入和输出路径,注意输出路径不能存在,否则抛出FileAlreadyExistsException(文件已经存在).为什么要这样,因为万一输入的路径是其他作业的执行结果,如果不抛出异常并中断程序,那么那个作业的结果就会被这个作业覆盖.

    3是创建一个Job对象,这里省略了Configuration configuration = new Configuration(),而改为直接在方法中创建Configuration目的是传入配置信息.还可以使用newJob(),不过该构造方法已经被标记为弃用,所以最好使用静态方法newInstance().

    4是设置Jar包的主类.作业是以Jar的形式上传至集群的,这里需要设置程序的入口类,即main()所在类.

    5,6分别是设置Mapper类与Reducer类,这里传入自己编写的Map类和Reduce类就可以了.

    7是设置Combiner类,一般设置为Reduce类,前面说过Combiner不是必须的,因为有些作业并不适用.

    8,9是设置Mapper输出的key,value类型,应该与map的参数3,4一致.

    10,11是设置Reducer输出的key,value类型,应该与reduce的参数3,4一致.

    12是设置输入文件路径,需要传入作业的Job对象,以及一个Path对象,Path中设置了作业的输入文件路径,可以使用正则表达式匹配,这里使用了第1行的字符串.这里的Path与Java的File不同,不可混用.注意,输入路径可以设置多个.

    13是设置作业结果的输出路径,同样需要传入Job对象与Path对象,这里使用了第2行的字符串.注意,输出路径只可以有一个.

    14是提交作业的方法,也可以使用submit().

    Job对象还有很多方法可以调用,这里由于不需要就没有设置,大家可以自己看看还有什么方法.

    到了这里,一个完整的MapReduce程序就编写完毕了,下一步就是上传至集群并执行.下一篇就来看看作业是怎么提交的.

     

    展开全文
  • 编写一个程序模拟扔硬币的结果 package test; import java.util.Random; public class CoinTossing { public static void main(String[] args) { // TODO Auto-generated method stub Random random=new ...

    编写一个程序模拟扔硬币的结果

    package test;
    
    import java.util.Random;
    
    public class CoinTossing {
    
    	public static void main(String[] args) {
    		// TODO Auto-generated method stub
    		Random random=new Random();
    		int i=random.nextInt(2);
    		System.out.println("i======="+i);
    		if(i==0) {
    			System.out.println("第一枚硬币正面");
    		}else {
    			System.out.println("第一枚硬币反面");
    		}
    		
    		double j=Math.random();
    		System.out.println("j======="+j);
    		if(j>0.5) {
    			System.out.println("第二枚硬币正面");
    		}else {
    			System.out.println("第二枚硬币反面");
    		}
    	}
    
    }
    

    i=0
    第一枚硬币正面
    j
    =0.20116398384674605
    第二枚硬币反面

    加群获取学习资源,一起学习
    在这里插入图片描述

    展开全文
  • 如何编写一个金字塔程序 代码如下: public class xing { public static void main(String[] args) { for(int i=1;i<=5;i++) { for(int x=1;x<=5-i;x++) { System.out.print(" "); } for(int ...

    用Java如何编写一个金字塔程序

    Java通过一个for语句编写金字塔

    代码如下:

    public class xing {
    	public static void main(String[] args) {
    		for(int i=1;i<=5;i++) {
    			for(int x=1;x<=5-i;x++) {
    				System.out.print(" ");
    			}
    			for(int y=1;y<=2*i-1;y++) {
    				System.out.print("*");
    			}
    			System.out.print("\n");
    		}
    	}
    }
    
    

    运行结果如下:
    在这里插入图片描述

    展开全文
  • 最近接手了一个投票的任务,也即需要编写一个程序自动投票,从而也引发了如何编写自动投票程序和如何编写投票程序(投票程序怎么样防止自动投票)的话题。正所谓道高一尺、魔高一丈。自动投票和投票程序本身就是一种...
    
    	

    导读:
      
      我经常去网站抓些东西,有时也做一些自动填写表单的事情。最近接手了一个投票的任务,也即需要编写一个程序自动投票,从而也引发了如何编写自动投票程序和如何编写投票程序(投票程序怎么样防止自动投票)的话题。正所谓道高一尺、魔高一丈。自动投票和投票程序本身就是一种对弈状态。


     


    ***********************************************************************************
      * 版权声明
      * 此文章为ocean所有,版权归ocean所有,任何网站
      *和 媒体转载必须包含此段声明,否则将视为侵权,作者将
      * 保留一切权力。此声明为此文章中不可或缺的一部分。
      * 作者网名:ocean
      * 作者email:ocean@forever.net.cn
      * 作者网站:http://www.oceanstudio.net
      * http://sps.oceanstudio.net
      * 作者blog:博客园,http://www.cnblogs.com/ocean
      * 此文章发表时间:2005年2月1日
      * 此文章源: http://www.cnblogs.com/ocean/archive/2005/02/01/100445.html
      ************************************************************************************
      我经常去网站抓些东西,有时也做一些自动填写表单的事情。最近接手了一个投票的任务,也即需要编写一个程序自动投票,从而也引发了如何编写自动投票程序和如何编写投票程序(投票程序怎么样防止自动投票)的话题。正所谓道高一尺、魔高一丈。自动投票和投票程序本身就是一种对弈状态。
      如何编写投票程序,大致分为这么几步:
      1:手动投票,分析中间出现的每一个页面的代码,找出投票规律。
      2:捕获提交页面的时候所post的信息。
      3:编程模拟这个手动过程。
      我以我刚写的这个自动投票程序为例。在此我不会给出网址链接(保密),也不会给出真实数据和截图。
      首先手动投票,是一个多选投票,点击投票按钮后,会弹出一个网页,这个网页会问你是确认还是放弃,点击确认后,返回投票成功的提示。当在此点击投票按钮的时候提示已经投过一票,不能重复投票。关闭所有浏览器窗口,打开一个新窗口,投票,仍然可以投票成功。根据如下行为,可以得出如下结论:
      1:投票需要有两次和服务器的交互,第一次向服务器提交投票结果,第二次交互向服务器提交是否确认此结果。
      2:此两页面之间的session是有联系的,也即同一个session下不能投两次票。当关闭浏览器,重新开启刘拉尼后,因为相当于新开了一个session,所以仍然会投票成功。
      知道了这个后,就开始抓去两次交互的HTTP头信息(Header信息)
      第一次交互的信息如下(点击投票按钮):
      --------------------------------------------------------------------------
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
      Referer: http://xxxxx/xxxxxxxxxxxxxxxxxxxxxxxx
      Accept-Language: zh-cn
      Content-Type: application/x-www-form-urlencoded
      Accept-Encoding: gzip, deflate
      User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.1.4322)
      Host: xxx.xxx.xxx.xxx
      Content-Length: 167
      Connection: Keep-Alive
      Cache-Control: no-cache
      checkvalue=32&bbb=%CD%B6%C6%B1&ilc=0&kkk=22
      ---------------------------------------------------------------------------------
      从网页源代码中可以分析出来,数据是post上去的,post的数据为"checkvalue=32&bbb=%CD%B6%C6%B1&ilc=0&kkk=22",其中checkvalue=32即为投票选中的复选框的值,bbb为投票按钮的名称,"%CD%B6%C6%B1"为"投票"两个汉字的转码。ilc=0和kkk=22是两个隐藏域中信息,作用还不明确。从网页源代码中可以分析出来,数据是post上去的,post的数据为"checkvalue=32&bbb=%CD%B6%C6%B1&ilc=0&kkk=22",其中checkvalue=32即为投票选中的复选框的值,bbb为投票按钮的名称,"%CD%B6%C6%B1"为"投票"两个汉字的转码。ilc=0和kkk=22是两个隐藏域中信息,作用还不明确。
      然后接收到的Header如下:
      -------------------------------------------------------------
      Date: Wed, 05 Jan 2005 12:45:10 GMT
      Server: Apache/1.3.27 (Win32)
      X-Powered-By: PHP/4.1.2
      Set-Cookie: ilc=22
      Keep-Alive: timeout=15, max=100
      Connection: Keep-Alive
      Transfer-Encoding: chunked
      Content-Type: text/html
      --------------------------------------------------------------------
      可以看到里面有一个关键的地方Set-Cookie : ilc = 22,也即设置了一个cookie,这个cookie值为22,也即post上去的kkk的值,猜测这是此次投票的编码。可以看到里面有一个关键的地方Set-Cookie : ilc = 22,也即设置了一个cookie,这个cookie值为22,也即post上去的kkk的值,猜测这是此次投票的编码。
      从返回的源代码中可以分析出来checkvalue=32这个值并没有写在第二个页面的隐藏域中,那么它就只能记录在session中。从第二次交互的信息中也可以证明。
      第二次交互的信息:
      发送:
      ------------------------------------------------------------
      Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
      Referer: http://xxxxx/xxxxxxxxxxxxxxxxxxxxxxxx
      Accept-Language: zh-cn
      Content-Type: application/x-www-form-urlencoded
      Accept-Encoding: gzip, deflate
      User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; MyIE2; .NET CLR 1.1.4322)
      Host: xxx.xxx.xxx.xxx
      Content-Length: 22
      Connection: Keep-Alive
      Cache-Control: no-cache
      Cookie: ilc=22
      inbtn=%C8%B7%C8%CF
      -----------------------------------------------------------------
      可以看到第二次post上去的信息仅仅是一个按钮的信息。inbtn为"确认"按钮的名字。而"%C8%B7%C8%CF"就是"确认"两个字的转码。checkvalue=32这个投票信息并不包含在第二次交互中,这只能说明第一次交互中就把这个信息写入到session中保存了。可以看到第二次post上去的信息仅仅是一个按钮的信息。inbtn为"确认"按钮的名字。而"%C8%B7%C8%CF"就是"确认"两个字的转码。checkvalue=32这个投票信息并不包含在第二次交互中,这只能说明第一次交互中就把这个信息写入到session中保存了。
      不能重复投票可能是session中有记录,也可能是cookie中有记录。cookie的可能性大一些。
      那么怎么模拟这个过程呢,我用了WebClient类,这个类非常好。其中的Headers属性可以设置头信息。而UploadData函数则可以post数据上去。并且同一个WebClient的两次连接是在同一个Session中的。这样完成两次交互也就是一次投票之后,就可以重新new一个WebClient,这样就相当于重新开了一个Session。
      代码如下:
      
      None.gif
      
      static void post()
      ExpandedBlockStart.gif
      
      ContractedBlock.gif
      
      dot.gif
      {
      InBlock.gif
      string uriString = "http://xxxxx/xxxxxxxxxxxxxxxxxxxxxxxx"
      InBlock.gif
      
      WebClient myWebClient = new WebClient();
      InBlock.gif
      string postData = null
      InBlock.gif
      byte[] byteArray;
      InBlock.gif
      byte[] responseArray;
      InBlock.gif
      
      WebHeaderCollection myWebHeaderCollection;
      InBlock.gif
      
      
      InBlock.gif
      
      postData = "checkvalue=32&bbb=%CD%B6%C6%B1&ilc=0&kkk=22"
      InBlock.gif
      
      myWebClient.Headers.Add("Content-Type","application/x-www-form-urlencoded");
      InBlock.gif
      
      myWebClient.Headers.Add("Referer","http://xxxxx/xxxxxxxxxxxxxxxxxxxxxxxx");
      InBlock.gif
      
      myWebClient.Headers.Add("Accept-Language","zh-cn");
      InBlock.gif
      
      myWebHeaderCollection = myWebClient.Headers;
      InBlock.gif
      
      
      InBlock.gif
      //第一次交互
      InBlock.gif
      Console.WriteLine("发送的HTTP头信息");
      InBlock.gif
      for (int i=0 i < myWebHeaderCollection.Count; i++)
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      Console.WriteLine (myWebHeaderCollection.GetKey(i) + " : " + myWebHeaderCollection.Get(i));
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      
      
      InBlock.gif
      
      byteArray = Encoding.Default.GetBytes(postData);
      InBlock.gif
      
      responseArray = myWebClient.UploadData(uriString,"POST",byteArray);
      InBlock.gif
      
      
      InBlock.gif
      
      Console.WriteLine("接收的HTTP头信息");
      InBlock.gif
      
      myWebHeaderCollection = myWebClient.ResponseHeaders;
      InBlock.gif
      for (int i=0 i < myWebHeaderCollection.Count; i++)
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      Console.WriteLine (myWebHeaderCollection.GetKey(i) + " : " + myWebHeaderCollection.Get(i));
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      
      Console.WriteLine("接收的正文信息");
      InBlock.gif
      
      Console.WriteLine(Encoding.Default.GetString(responseArray));
      InBlock.gif
      //Console.ReadLine();
      InBlock.gif
      
      
      InBlock.gif
      //第二次交互(用同一个WebClient实例)
      InBlock.gif
      postData = "inputinfo=%C8%B7%C8%CF"
      InBlock.gif
      
      myWebClient.Headers.Add("Content-Type","application/x-www-form-urlencoded");
      InBlock.gif
      
      myWebClient.Headers.Add("Referer","http://xxxxx/xxxxxxxxxxxxxxxxxxxxxxxx");
      InBlock.gif
      
      myWebClient.Headers.Add("Accept-Language","zh-cn");
      InBlock.gif
      
      myWebClient.Headers.Add("Cookie","ilc=126");
      InBlock.gif
      
      myWebHeaderCollection = myWebClient.Headers;
      InBlock.gif
      
      
      InBlock.gif
      
      Console.WriteLine("发送的HTTP头信息");
      InBlock.gif
      for (int i=0 i < myWebHeaderCollection.Count; i++)
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      Console.WriteLine (myWebHeaderCollection.GetKey(i) + " : " + myWebHeaderCollection.Get(i));
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      
      
      InBlock.gif
      
      byteArray = Encoding.Default.GetBytes(postData);
      InBlock.gif
      
      responseArray = myWebClient.UploadData(uriString,"POST",byteArray);
      InBlock.gif
      
      
      InBlock.gif
      
      Console.WriteLine("接收的HTTP头信息");
      InBlock.gif
      
      myWebHeaderCollection = myWebClient.ResponseHeaders;
      InBlock.gif
      for (int i=0 i < myWebHeaderCollection.Count; i++)
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      Console.WriteLine (myWebHeaderCollection.GetKey(i) + " : " + myWebHeaderCollection.Get(i));
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      
      
      InBlock.gif
      
      Console.WriteLine("接收的正文信息");
      InBlock.gif
      
      Console.WriteLine(Encoding.Default.GetString(responseArray));
      InBlock.gif
      //Console.ReadLine();
      ExpandedBlockEnd.gif
      }
      None.gif
      
      
      运行后输出的信息和手动投票时截获的信息基本一致。
      然后就可以运行一个无限循环
      
      None.gif
      
      int i = 0
      None.gif
      while (true)
      ExpandedBlockStart.gif
      
      ContractedBlock.gif
      
      dot.gif
      {
      InBlock.gif
      try
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      post();
      InBlock.gif
      
      i ++
      InBlock.gif
      
      Console.WriteLine("这是您投的第" + i + "张票");
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      catch (Exception e)
      ExpandedSubBlockStart.gif
      
      ContractedSubBlock.gif
      
      dot.gif
      {
      InBlock.gif
      
      Console.WriteLine("有错误发生:" + e.Message);
      ExpandedSubBlockEnd.gif
      
      }
      InBlock.gif
      
      Console.WriteLine("---------------------------------");
      ExpandedBlockEnd.gif
      
      }
      我做的命令行程序,要捕捉错误避免程序停止。停止程序的时候直接X掉窗口即可。另外用命令行程序的一个好处是不用做多线程,直接多运行几个exe的实例就可以达到多线程的目的(实际是多进程了)。
      那么我们在做投票(包括其它表单)如何防备别人自动投票或者自动填写表但呢?session限制的方法显然不是一个有效的方法。而ip限制不实际,因为很多用户都没有ip地址,都是网络运营商作的NAT映射,封掉一个ip地址相当于封掉一批机器。所以一般也不采用。那么如何最有效呢。可以采用两种方法:
      1:验证码,验证码直接导致了无法用程序来填写表单,因为验证码都为图片,文字的验证码是没有任何意义的。图片的验证码就决定了,如果要自动,那么必须识别出来验证码的数字和字母。至少一般人是没法做的,这是模式识别的问题。当然我也有朋友专门做模式识别的,可以从复杂背景下辨别出来潦草的手写笔迹,碰上这样的人谁也没办法了。但是像微软有些表单的验证码的图片作的非常复杂。除了背景有很多底纹之外,数字和图片还是花体的,并且角度也不一样,有竖的,有斜的,这样就很难识别。采用了验证码基本可以保证不会被自动投票。
      2:ip限时间或票数:限制ip在一段时间内的投票数量或者投两票之间的间隔时间。比如同一ip地址一天内投票数不能超过100张。或者两次投票间隔至少5分钟等。这样即使有自动投票程序,其速度也就大大降低。起不到快速投票的作用。
      如果同时结合这两种手段,那么基本很难再做自动投票的事情了。
      另外就是上面我所提供的头信息是怎么抓取的,这个在IE上有个插件叫做ieHTTPHeader,您可以从此处
      http://www.oceanstudio.net/oceanstudy/download/ieHTTPHeadersSetup.rar
      可以方便的看到提交网页时所提交的头信息和post数据。

    本文转自
    http://www.cnblogs.com/ocean/archive/2007/11/21/100445.html

    展开全文
  • 如何使用Java语言编写一个日历程序

    千次阅读 2019-04-15 20:43:19
    我们需要编写一个日历程序,这个程序将显示当前月份的日历,当前的日用一个*进行标志。想信大家都见过日历,因此,这个程序需要解决如何计算某月的天数以及一个给定日期相应的是星期几。 解决步骤: 下面看一下这...
  • 编写程序,要求用户输入一个分数,然后将其约分为最简式。如: 输入一个分数:8/12 最简分式:2/3
  •  主要内容包括JavaSE、JavaEE的基础知识以及如何用Java语言编写一个简单的软件、一个小型的游戏、一个简易的项目、或者一些比较复杂的项目实战等等。  这些文章我不准备用概念来引入Java知识,因为这些概念类的...
  • 如何快速优雅的编写一个脚本程序?用这个!

    万次阅读 多人点赞 2019-06-07 21:40:00
    在日常工作当中,我们会不时借助脚本程序来处理一些重复性工作,以帮助我们提升工作效率。近几年 Python 与 Ruby 发展迅猛,使得它们成为了很多人编写脚本程序时的首选...
  • 如何用CodeBlocks分多个文件编写一个C++程序

    万次阅读 多人点赞 2016-09-10 17:32:21
    网上有许多教程,说的是如何用codeblocks编写一个简单的C\C++程序,但没有说如果分多个文件编写程序效果会怎样?下面向大家介绍该如何做: 1.首先打开codeblocks: 2.单击“File"-"new"-“Projects",或者单击...
  • 我想问一下,如果想用VC编写一个程序,去抓取正在一个播放器,例如迅雷播放器正在播放的视频,然后以某种格式将这个视频存起来的思路是怎么进行的,求大神帮忙 这个问题就我所知应该比较复杂,例如要如何去抓取...
  • 如何编写一个没有主函数的C程序

    千次阅读 2015-08-30 10:12:01
    Question:我如何才能写一个没有主函数的C程序? Answer From Travis Hance: 你可以编译任何一个C程序,无论有没有主函数,或者是一个对象文件(.o文件)。只有当你把所有对象文件链接起来,
  • 一:编写源码:本文末尾是我自己编写一个简单的按键应用程序keyFunction.c 二:编译源码:在linux环境下,用对应的toolchain 编译源码,生成应用程序的可执行文件 keyFunction 例如:# arm-none-linux-gnueabi-...
  • 以下,通过一个实例来展示如何编写一个Java程序: 代码 public class HelloWorld{ public static void main(String[] args){ System.out.println("Hello world!"); } } 注意: (1)文件名要与类名保持一致,如...
  • 用eclipse编写一个简单的java程序,输出hello world 在使用eclipse编写程序之前先保证jdk安装的完成,才能正确运行程序 1.打开eclipse,选择工作空间,工作空间就是你新建工程存放的指定文件夹文件夹 2.打开eclipse...
  • 今天就先了解一下如何建立一个Java程序,安装JDK以及编译器的过程我就不多赘述了,网上也有很多教程,编译器例如Eclipse、IDEA等等有很多种可供选择,下面以eclipse为例,建立一个简单的Java程序。 首先启动eclipse...
  • 第三行给出一个整数X。 输出格式: 在一行内输出将X插入后仍然从小到大有序的整数序列,每个数字后面有一个空格。 输入样例: 5 1 2 4 5 7 3 输出样例: 1 2 3 4 5 7 我的代码展示: #include "stdio.h" int main...
  • 学习上一篇文章之后,确定好JDK和环境变量都成功之后,我们来编写我们第一个java程序命名为HelloWorld.java。上一篇文章链接:JDK下载与环境变量的安装桌面上右击,新建一个文本文档用记事本打开文本文档编写如上图...
  • 如何编写一个自动投票程序

    千次阅读 2006-10-24 10:39:00
    最近接手了一个投票的任务,也即需要编写一个程序自动投票,从而也引发了如何编写自动投票程序和如何编写投票程序(投票程序怎么样防止自动投票)的话题。正所谓道高一尺、魔高一丈。自动投票和投票程序本身就是一种...
  • 如何编写一个图片标注程序能实现一张图片对应多个可选标注,标注后自动保存到一个数据库中? 在MATLAB中可以实现吗,或者其他方法?
  • **要求:** 1.该程序不能从外部读取输入; 2.该程序输出的源码不能为空; 3.不能使用语言与shell的特性投机取巧; 在满足以上3点要求的情况下改程序可以对外输出自身的源代码
  • 如何将三角形做成死循环,当输入特殊字符才停止跳出程序?? import java.util.Scanner; class Trangle { double A,B,C,area,length; Trangle (double a,double b,double c)throws TrangleException{ if(a+b||a+...
  • 如何使用javascript编写一个加法程序,从文本框输入两个数字,用alert输出结果?
  • 如何编写一个简单的linux内核模块和设备驱动程序。我将学习到如何在内核模式下以三种不同的方式来打印hello world,这三种方式分别是: printk(),/proc文件,/dev下的设备文件。 准备:安装内核模块的编译环境 ...
  • python编写一个类似抢红包的程序如何实现每个人随机平均的分配
  • 编写程序,输出一个整数的每一位 程序代码如下: #include &lt;stdio.h&gt; void print_integer(int num) { int i = 0; while (num) { if (num &lt; 0) { num = -num; } ...
  • 如何使用Python 为 Hadoop编写一个简单的MapReduce程序。 尽管Hadoop框架是使用Java编写的但是我们仍然需要使用像C++、Python等语言来实现Hadoop程序。尽管Hadoop官方网站给的示例程序是使用Jython编写并打包成Jar...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 23,476
精华内容 9,390
关键字:

如何编写一个程序