<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    小菜毛毛技術(shù)分享

    與大家共同成長

      BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
      164 Posts :: 141 Stories :: 94 Comments :: 0 Trackbacks

    那就首先說點(diǎn)Runtime類吧,他是一個(gè)與JVM運(yùn)行時(shí)環(huán)境有關(guān)的類,這個(gè)類是Singleton的。我說幾個(gè)自己覺得重要的地方。

    1、Runtime.getRuntime()可以取得當(dāng)前JVM的運(yùn)行時(shí)環(huán)境,這也是在Java中唯一一個(gè)得到運(yùn)行時(shí)環(huán)境的方法。

    2、Runtime上其他大部分的方法都是實(shí)例方法,也就是說每次進(jìn)行運(yùn)行時(shí)調(diào)用時(shí)都要用到getRuntime方法。

    3、Runtime中的exit方法是退出當(dāng)前JVM的方法,估計(jì)也是唯一的一個(gè)吧,因?yàn)槲铱吹絊ystem類中的exit實(shí)際上也是通過調(diào)用Runtime.exit()來退出JVM的,這里說明一下Java對Runtime返回值的一般規(guī)則(后邊也提到了),0代表正常退出,非0代表異常中止,這只是Java的規(guī)則,在各個(gè)操作系統(tǒng)中總會(huì)發(fā)生一些小的混淆。


    4、Runtime.addShutdownHook()方法可以注冊一個(gè)hook在JVM執(zhí)行shutdown的過程中,方法的參數(shù)只要是一個(gè)初始化過但是沒有執(zhí)行的Thread實(shí)例就可以。(注意,Java中的Thread都是執(zhí)行過了就不值錢的哦)

    5、說到addShutdownHook這個(gè)方法就要說一下JVM運(yùn)行環(huán)境是在什么情況下shutdown或者abort的。文檔上是這樣寫的,當(dāng)最后一個(gè)非精靈進(jìn)程退出或者收到了一個(gè)用戶中斷信號(hào)、用戶登出、系統(tǒng)shutdown、Runtime的exit方法被調(diào)用時(shí)JVM會(huì)啟動(dòng)shutdown的過程,在這個(gè)過程開始后,他會(huì)并行啟動(dòng)所有登記的shutdown hook(注意是并行啟動(dòng),這就需要線程安全和防止死鎖)。當(dāng)shutdown過程啟動(dòng)后,只有通過調(diào)用halt方法才能中止shutdown的過程并退出JVM。

    那什么時(shí)候JVM會(huì)abort退出那?首先說明一下,abort退出時(shí)JVM就是停止運(yùn)行但并不一定進(jìn)行shutdown。這只有JVM在遇到SIGKILL信號(hào)或者windows中止進(jìn)程的信號(hào)、本地方法發(fā)生類似于訪問非法地址一類的內(nèi)部錯(cuò)誤時(shí)會(huì)出現(xiàn)。這種情況下并不能保證shutdown hook是否被執(zhí)行。


    現(xiàn)在開始看這篇文章,呵呵。


    首先講的是Runtime.exec()方法的所有重載。這里要注意的有一點(diǎn),就是public Process exec(String [] cmdArray, String [] envp);這個(gè)方法中cmdArray是一個(gè)執(zhí)行的命令和參數(shù)的字符串?dāng)?shù)組,數(shù)組的第一個(gè)元素是要執(zhí)行的命令往后依次都是命令的參數(shù),envp我個(gè)人感覺應(yīng)該和C中的execve中的環(huán)境變量是一樣的,envp中使用的是name=value的方式。


    <!--[if !supportLists]-->1、 <!--[endif]-->一個(gè)很糟糕的調(diào)用程序,代碼如下,這個(gè)程序用exec調(diào)用了一個(gè)外部命令之后馬上使用exitValue就對其返回值進(jìn)行檢查,讓我們看看會(huì)出現(xiàn)什么問題。


    import java.util.*;
    import java.io.*;

    public class BadExecJavac
    {
    public static void main(String args[])
    {
    try
    {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("javac");
    int exitVal = proc.exitValue();
    System.out.println("Process exitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    A run of BadExecJavac produces:


    E:classescomjavaworldjpitfallsarticle2>java BadExecJavac
    java.lang.IllegalThreadStateException: process has not exited
    at java.lang.Win32Process.exitValue(Native Method)
    at BadExecJavac.main(BadExecJavac.java:13)


    這里看原文就可以了解,這里主要的問題就是錯(cuò)誤的調(diào)用了exitValue來取得外部命令的返回值(呵呵,這個(gè)錯(cuò)誤我也曾經(jīng)犯過),因?yàn)閑xitValue這個(gè)方法是不阻塞的,程序在調(diào)用這個(gè)方法時(shí)外部命令并沒有返回所以造成了異常的出現(xiàn),這里是由另外的方法來等待外部命令執(zhí)行完畢的,就是waitFor方法,這個(gè)方法會(huì)一直阻塞直到外部命令執(zhí)行結(jié)束,然后返回外部命令執(zhí)行的結(jié)果,作者在這里一頓批評設(shè)計(jì)者的思路有問題,呵呵,反正我是無所謂阿,能用就可以拉。但是作者在這里有一個(gè)說明,就是exitValue也是有好多用途的。因?yàn)楫?dāng)你在一個(gè)Process上調(diào)用waitFor方法時(shí),當(dāng)前線程是阻塞的,如果外部命令無法執(zhí)行結(jié)束,那么你的線程就會(huì)一直阻塞下去,這種意外會(huì)影響我們程序的執(zhí)行。所以在我們不能判斷外部命令什么時(shí)候執(zhí)行完畢而我們的程序還需要繼續(xù)執(zhí)行的情況下,我們就應(yīng)該循環(huán)的使用exitValue來取得外部命令的返回狀態(tài),并在外部命令返回時(shí)作出相應(yīng)的處理。


    2、對exitValue處改進(jìn)了的程序

    import java.util.*;
    import java.io.*;

    public class BadExecJavac2
    {
    public static void main(String args[])
    {
    try
    {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("javac");
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    不幸的是,這個(gè)程序也無法執(zhí)行完成,它沒有輸出但卻一直懸在那里,這是為什么那?


    JDK文檔中對此有如此的解釋:因?yàn)楸镜氐南到y(tǒng)對標(biāo)準(zhǔn)輸入和輸出所提供的緩沖池有效,所以錯(cuò)誤的對標(biāo)準(zhǔn)輸出快速的寫入和從標(biāo)準(zhǔn)輸入快速的讀入都有可能造成子進(jìn)程的鎖,甚至死鎖。


    文檔引述完了,作者又開始批評了,他說JDK僅僅說明為什么問題會(huì)發(fā)生,卻并沒有說明這個(gè)問題怎么解決,這的確是個(gè)問題哈。緊接著作者說出自己的做法,就是在執(zhí)行完外部命令后我們要控制好Process的所有輸入和輸出(視情況而定),在這個(gè)例子里邊因?yàn)檎{(diào)用的是Javac,而他在沒有參數(shù)的情況下會(huì)將提示信息輸出到標(biāo)準(zhǔn)出錯(cuò),所以在下面的程序中我們要對此進(jìn)行處理。


    import java.util.*;
    import java.io.*;

    public class MediocreExecJavac
    {
    public static void main(String args[])
    {
    try
    {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("javac");
    InputStream stderr = proc.getErrorStream();
    InputStreamReader isr = new InputStreamReader(stderr);
    BufferedReader br = new BufferedReader(isr);
    String line = null;
    System.out.println("<ERROR>");
    while ( (line = br.readLine()) != null)
    System.out.println(line);
    System.out.println("</ERROR>");
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }


    程序的運(yùn)行結(jié)果為

    E:classescomjavaworldjpitfallsarticle2>java MediocreExecJavac
    <ERROR>
    Usage: javac <options> <source files>

    where <options> includes:
    -g Generate all debugging info
    -g:none Generate no debugging info
    -g:{lines,vars,source} Generate only some debugging info
    -O Optimize; may hinder debugging or enlarge class files
    -nowarn Generate no warnings
    -verbose Output messages about what the compiler is doing
    -deprecation Output source locations where deprecated APIs are used
    -classpath <path> Specify where to find user class files
    -sourcepath <path> Specify where to find input source files
    -bootclasspath <path> Override location of bootstrap class files
    -extdirs <dirs> Override location of installed extensions
    -d <directory> Specify where to place generated class files
    -encoding <encoding> Specify character encoding used by source files
    -target <release> Generate class files for specific VM version
    </ERROR>
    Process exitValue: 2


    哎,不管怎么說還是出來了結(jié)果,作者作了一下總結(jié),就是說,為了處理好外部命令大量輸出的情況,你要確保你的程序處理好外部命令所需要的輸入或者輸出。


    下一個(gè)題目,當(dāng)我們調(diào)用一個(gè)我們認(rèn)為是可執(zhí)行程序的時(shí)候容易發(fā)生的錯(cuò)誤(今天晚上我剛剛犯這個(gè)錯(cuò)誤,沒事做這個(gè)練習(xí)時(shí)候發(fā)生的)

    import java.util.*;
    import java.io.*;

    public class BadExecWinDir
    {
    public static void main(String args[])
    {
    try
    {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("dir");
    InputStream stdin = proc.getInputStream();
    InputStreamReader isr = new InputStreamReader(stdin);
    BufferedReader br = new BufferedReader(isr);
    String line = null;
    System.out.println("<OUTPUT>");
    while ( (line = br.readLine()) != null)
    System.out.println(line);
    System.out.println("</OUTPUT>");
    int exitVal = proc.waitFor();
    System.out.println("Process exitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    A run of BadExecWinDir produces:


    E:classescomjavaworldjpitfallsarticle2>java BadExecWinDir
    java.io.IOException: CreateProcess: dir error=2
    at java.lang.Win32Process.create(Native Method)
    at java.lang.Win32Process.<init>(Unknown Source)
    at java.lang.Runtime.execInternal(Native Method)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at BadExecWinDir.main(BadExecWinDir.java:12)


    說實(shí)在的,這個(gè)錯(cuò)誤還真是讓我摸不著頭腦,我覺得在windows中返回2應(yīng)該是沒有找到這個(gè)文件的緣故,可能windows 2000中只有cmd命令,dir命令不是當(dāng)前環(huán)境變量能夠解釋的吧。我也不知道了,慢慢往下看吧。

    嘿,果然和作者想的一樣,就是因?yàn)閐ir命令是由windows中的解釋器解釋的,直接執(zhí)行dir時(shí)無法找到dir.exe這個(gè)命令,所以會(huì)出現(xiàn)文件未找到這個(gè)2的錯(cuò)誤。如果我們要執(zhí)行這樣的命令,就要先根據(jù)操作系統(tǒng)的不同執(zhí)行不同的解釋程序command.com 或者cmd.exe。

    作者對上邊的程序進(jìn)行了修改

    import java.util.*;
    import java.io.*;

    class StreamGobbler extends Thread
    {
    InputStream is;
    String type;

    StreamGobbler(InputStream is, String type)
    {
    this.is = is;
    this.type = type;
    }

    public void run()
    {
    try
    {
    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    String line=null;
    while ( (line = br.readLine()) != null)
    System.out.println(type + ">" + line);
    } catch (IOException ioe)
    {
    ioe.printStackTrace();
    }
    }
    }

    public class GoodWindowsExec
    {
    public static void main(String args[])
    {
    if (args.length < 1)
    {
    System.out.println("USAGE: java GoodWindowsExec <cmd>");
    System.exit(1);
    }

    try
    {
    String osName = System.getProperty("os.name" );
    String[] cmd = new String[3];

    if( osName.equals( "Windows NT" ) )
    {
    cmd[0] = "cmd.exe" ;
    cmd[1] = "/C" ;
    cmd[2] = args[0];
    }
    else if( osName.equals( "Windows 95" ) )
    {
    cmd[0] = "command.com" ;
    cmd[1] = "/C" ;
    cmd[2] = args[0];
    }

    Runtime rt = Runtime.getRuntime();
    System.out.println("Execing " + cmd[0] + " " + cmd[1]
    + " " + cmd[2]);
    Process proc = rt.exec(cmd);
    // any error message?
    StreamGobbler errorGobbler = new
    StreamGobbler(proc.getErrorStream(), "ERROR");

    // any output?
    StreamGobbler outputGobbler = new
    StreamGobbler(proc.getInputStream(), "OUTPUT");

    // kick them off
    errorGobbler.start();
    outputGobbler.start();

    // any error???
    int exitVal = proc.waitFor();
    System.out.println("ExitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    Running GoodWindowsExec with the dir command generates:


    E:classescomjavaworldjpitfallsarticle2>java GoodWindowsExec "dir *.java"
    Execing cmd.exe /C dir *.java
    OUTPUT> Volume in drive E has no label.
    OUTPUT> Volume Serial Number is 5C5F-0CC9
    OUTPUT>
    OUTPUT> Directory of E:classescomjavaworldjpitfallsarticle2
    OUTPUT>
    OUTPUT>10/23/00 09:01p 805 BadExecBrowser.java
    OUTPUT>10/22/00 09:35a 770 BadExecBrowser1.java
    OUTPUT>10/24/00 08:45p 488 BadExecJavac.java
    OUTPUT>10/24/00 08:46p 519 BadExecJavac2.java
    OUTPUT>10/24/00 09:13p 930 BadExecWinDir.java
    OUTPUT>10/22/00 09:21a 2,282 BadURLPost.java
    OUTPUT>10/22/00 09:20a 2,273 BadURLPost1.java
    ... (some output omitted for brevity)
    OUTPUT>10/12/00 09:29p 151 SuperFrame.java
    OUTPUT>10/24/00 09:23p 1,814 TestExec.java
    OUTPUT>10/09/00 05:47p 23,543 TestStringReplace.java
    OUTPUT>10/12/00 08:55p 228 TopLevel.java
    OUTPUT> 22 File(s) 46,661 bytes
    OUTPUT> 19,678,420,992 bytes free
    ExitValue: 0

    這里作者教了一個(gè)windows中很有用的方法,呵呵,至少我是不知道的,就是cmd.exe /C +一個(gè)windows中注冊了后綴的文檔名,windows會(huì)自動(dòng)地調(diào)用相關(guān)的程序來打開這個(gè)文檔,我試了一下,的確很好用,但是好像文件路徑中有空格的話就有點(diǎn)問題,我加上引號(hào)也無法解決。

    這里作者強(qiáng)調(diào)了一下,不要假設(shè)你執(zhí)行的程序是可執(zhí)行的程序,要清楚自己的程序是單獨(dú)可執(zhí)行的還是被解釋的,本章的結(jié)束作者會(huì)介紹一個(gè)命令行工具來幫助我們分析。

    這里還有一點(diǎn),就是得到process的輸出的方式是getInputStream,這是因?yàn)槲覀円獜腏ava 程序的角度來看,外部程序的輸出對于Java來說就是輸入,反之亦然。


    最后的一個(gè)漏洞的地方就是錯(cuò)誤的認(rèn)為exec方法會(huì)接受所有你在命令行或者Shell中輸入并接受的字符串。這些錯(cuò)誤主要出現(xiàn)在命令作為參數(shù)的情況下,程序員錯(cuò)誤的將所有命令行中可以輸入的參數(shù)命令加入到exec中(這段翻譯的不好,湊合看吧)。下面的例子中就是一個(gè)程序員想重定向一個(gè)命令的輸出。


    import java.util.*;
    import java.io.*;

    // StreamGobbler omitted for brevity

    public class BadWinRedirect
    {
    public static void main(String args[])
    {
    try
    {
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("java jecho 'Hello World' > test.txt");
    // any error message?
    StreamGobbler errorGobbler = new
    StreamGobbler(proc.getErrorStream(), "ERROR");

    // any output?
    StreamGobbler outputGobbler = new
    StreamGobbler(proc.getInputStream(), "OUTPUT");

    // kick them off
    errorGobbler.start();
    outputGobbler.start();

    // any error???
    int exitVal = proc.waitFor();
    System.out.println("ExitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    Running BadWinRedirect produces:


    E:classescomjavaworldjpitfallsarticle2>java BadWinRedirect
    OUTPUT>'Hello World' > test.txt
    ExitValue: 0

    程序員的本意是將Hello World這個(gè)輸入重訂向到一個(gè)文本文件中,但是這個(gè)文件并沒有生成,jecho僅僅是將命令行中的參數(shù)輸出到標(biāo)準(zhǔn)輸出中,用戶覺得可以像dos中重定向一樣將輸出重定向到一個(gè)文件中,但這并不能實(shí)現(xiàn),用戶錯(cuò)誤的將exec認(rèn)為是一個(gè)shell解釋器,但它并不是,如果你想將一個(gè)程序的輸出重定向到其他的程序中,你必須用程序來實(shí)現(xiàn)他。可用java.io中的包。


    import java.util.*;
    import java.io.*;

    class StreamGobbler extends Thread
    {
    InputStream is;
    String type;
    OutputStream os;

    StreamGobbler(InputStream is, String type)
    {
    this(is, type, null);
    }

    StreamGobbler(InputStream is, String type, OutputStream redirect)
    {
    this.is = is;
    this.type = type;
    this.os = redirect;
    }

    public void run()
    {
    try
    {
    PrintWriter pw = null;
    if (os != null)
    pw = new PrintWriter(os);

    InputStreamReader isr = new InputStreamReader(is);
    BufferedReader br = new BufferedReader(isr);
    String line=null;
    while ( (line = br.readLine()) != null)
    {
    if (pw != null)
    pw.println(line);
    System.out.println(type + ">" + line);
    }
    if (pw != null)
    pw.flush();
    } catch (IOException ioe)
    {
    ioe.printStackTrace();
    }
    }
    }

    public class GoodWinRedirect
    {
    public static void main(String args[])
    {
    if (args.length < 1)
    {
    System.out.println("USAGE java GoodWinRedirect <outputfile>");
    System.exit(1);
    }

    try
    {
    FileOutputStream fos = new FileOutputStream(args[0]);
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec("java jecho 'Hello World'");
    // any error message?
    StreamGobbler errorGobbler = new
    StreamGobbler(proc.getErrorStream(), "ERROR");

    // any output?
    StreamGobbler outputGobbler = new
    StreamGobbler(proc.getInputStream(), "OUTPUT", fos);

    // kick them off
    errorGobbler.start();
    outputGobbler.start();

    // any error???
    int exitVal = proc.waitFor();
    System.out.println("ExitValue: " + exitVal);
    fos.flush();
    fos.close();
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    Running GoodWinRedirect produces:


    E:classescomjavaworldjpitfallsarticle2>java GoodWinRedirect test.txt
    OUTPUT>'Hello World'
    ExitValue: 0

    這里就不多說了,看看就明白,緊接著作者給出了一個(gè)監(jiān)測命令的小程序

    import java.util.*;
    import java.io.*;

    // class StreamGobbler omitted for brevity

    public class TestExec
    {
    public static void main(String args[])
    {
    if (args.length < 1)
    {
    System.out.println("USAGE: java TestExec "cmd"");
    System.exit(1);
    }

    try
    {
    String cmd = args[0];
    Runtime rt = Runtime.getRuntime();
    Process proc = rt.exec(cmd);

    // any error message?
    StreamGobbler errorGobbler = new
    StreamGobbler(proc.getErrorStream(), "ERR");

    // any output?
    StreamGobbler outputGobbler = new
    StreamGobbler(proc.getInputStream(), "OUT");

    // kick them off
    errorGobbler.start();
    outputGobbler.start();

    // any error???
    int exitVal = proc.waitFor();
    System.out.println("ExitValue: " + exitVal);
    } catch (Throwable t)
    {
    t.printStackTrace();
    }
    }
    }

    對這個(gè)程序進(jìn)行運(yùn)行:
    E:classescomjavaworldjpitfallsarticle2>java TestExec "e:javadocsindex.html"
    java.io.IOException: CreateProcess: e:javadocsindex.html error=193
    at java.lang.Win32Process.create(Native Method)
    at java.lang.Win32Process.<init>(Unknown Source)
    at java.lang.Runtime.execInternal(Native Method)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at java.lang.Runtime.exec(Unknown Source)
    at TestExec.main(TestExec.java:45)

    193在windows中是說這不是一個(gè)win32程序,這說明路徑中找不到這個(gè)網(wǎng)頁的關(guān)聯(lián)程序,下面作者決定用一個(gè)絕對路徑來試一下。

    E:classescomjavaworldjpitfallsarticle2>java TestExec
    "e:program filesnetscapeprogramnetscape.exe e:javadocsindex.html"
    ExitValue: 0


    好用了,這個(gè)我也試了一下,用的是IE。


    最后,作者總結(jié)了幾條規(guī)則,防止我們在進(jìn)行Runtime.exec()調(diào)用時(shí)出現(xiàn)錯(cuò)誤。


    <!--[if !supportLists]-->1、 <!--[endif]-->在一個(gè)外部進(jìn)程執(zhí)行完之前你不能得到他的退出狀態(tài)

    <!--[if !supportLists]-->2、 <!--[endif]-->在你的外部程序開始執(zhí)行的時(shí)候你必須馬上控制輸入、輸出、出錯(cuò)這些流。

    <!--[if !supportLists]-->3、 <!--[endif]-->你必須用Runtime.exec()去執(zhí)行程序

    <!--[if !supportLists]-->4、 <!--[endif]-->你不能象命令行一樣使用Runtime.exec()。

    posted on 2010-01-19 13:50 小菜毛毛 閱讀(559) 評論(0)  編輯  收藏 所屬分類: J2EE相關(guān)技術(shù)與框架
    主站蜘蛛池模板: 88av免费观看| 免费福利在线播放| 中文字幕在线免费看线人| 亚洲av成人中文无码专区| 亚洲国产精品专区| 久久精品国产亚洲AV忘忧草18| 亚洲人成网www| 亚洲高清资源在线观看| 久久精品亚洲一区二区三区浴池| 亚洲综合色婷婷七月丁香| 久久亚洲AV成人无码电影| 亚洲黄色免费电影| 亚洲色欲色欲www在线播放 | 十八禁在线观看视频播放免费| 大片免费观看92在线视频线视频| 一级毛片视频免费| 1000部拍拍拍18勿入免费视频下载| 97在线观看永久免费视频| 永久久久免费浮力影院| 亚洲尤码不卡AV麻豆| 久久亚洲国产精品五月天| 亚洲欧洲日韩国产一区二区三区| 校园亚洲春色另类小说合集| 99精品免费视频| 四虎成人免费影院网址| 国产成人毛片亚洲精品| 亚洲国产人成在线观看| 一个人看的www免费视频在线观看| 日韩在线播放全免费| 亚洲国产小视频精品久久久三级| 99亚洲精品高清一二区| 国产视频精品免费视频| 欧洲黑大粗无码免费| 水蜜桃亚洲一二三四在线| 极品美女一级毛片免费| 久久不见久久见免费影院| 亚洲AV日韩AV永久无码绿巨人| 亚洲AV无码国产剧情| 永久免费av无码不卡在线观看 | a级毛片在线免费| 亚洲精品久久久www|