最近需要通过cgi调用本地c程序所以想到了cgi,出现如下错误
信息: cgi: Caught exception java.io.IOException: Cannot run program "cmd /c" (in directory "D:\tomcat\webapps\abc\WEB-INF\cgi"): CreateProcess error=2, ?????????
十二月 06, 2014 10:05:57 上午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [cgi] in context with path [/abc] threw exception
java.io.IOException: Cannot run program "cmd /c" (in directory "D:\tomcat\webapps\abc\WEB-INF\cgi"): CreateProcess error=2, ?????????
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1041)
at java.lang.Runtime.exec(Runtime.java:617)
at org.apache.catalina.servlets.CGIServlet$CGIRunner.run(CGIServlet.java:1602)
at org.apache.catalina.servlets.CGIServlet.doGet(CGIServlet.java:591)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:620)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:503)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:421)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1070)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:611)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.doRun(AprEndpoint.java:2466)
at org.apache.tomcat.util.net.AprEndpoint$SocketProcessor.run(AprEndpoint.java:2455)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.io.IOException: CreateProcess error=2, ?????????
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.<init>(ProcessImpl.java:385)
at java.lang.ProcessImpl.start(ProcessImpl.java:136)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:1022)
... 26 more
利用百度搜索,搜索到很多相似问题,但是没有一个能解决我的问题,他们的大体思路如下:
1.如果是用perl写的脚本,可能是本机没有装perl,或者没有配置环境变量,导致不能运行。(我的是c写的不存在此问题)
2.访问路径问题,web.xml配置文件出错,不能正确访问到cgi程序。(上面报错明显找到的目录是正确的)
3.配置文件给出一个参数配置,我也写了
<init-param>
<param-name>executable</param-name>
<param-value>cmd /c </param-value>
</init-param>
百度搜索出的帖子大部分都出自一处让我很愤怒,没有一个能解决问题,搜到一个,跟我问题一样,但是最后结贴说:“你们说的问题都不对,我自找到问题所在了”,没有下文了,晕死我了。
最后,拉出微软的必应搜索,完全是胡乱投医,把英文错误输出沾上,在stack overflow上找到了,是一个人有意无意的一个回复
<span style="font-size:18px;">Thanks everyone, i didnt find out what was the correct syntax to run C++ cgi scripts, but if you leave the
param blank it will run any script type.
<init-param>
<param-name>executable</param-name>
<param-value></param-value>
</init-param>
answered Feb 1 '09 at 10:03</span>
最后问题是,这个参数必须指定,但是最好指定为空,什么脚本都可以执行,不写的话默认为perl脚本,所以这个参数必须写,但是保留为空。下面是我的配置,参考博客
http://alexrenguoly.blog.163.com/blog/static/120505597201111881824933/
1.配置文件。 如果使用exe文件来做cgi,还需要设置一个参数executable,这个参数的默认值是支持perl的,也就是说是用来解释perl脚本的。如果你用c++来写cgi脚本,那么executable这个参数的value要设为 cmd /c 。在下面的配置文件中您将会看到。
如果想让Tomcat下所有的Application支持支持CGI,可以修改 $CATALINA_BASE/conf/web.xml(CATALINA_BASE就是你的tomcat的路径);如果只希望某些项目支持CGI,那么只需要修改这些应用root目录下的/WEB-INF/web.xml文件。
这里要说一下,上图就是项目的root目录,除了foo是我自己创建的其他都是tomcat自带的,每个项目里面一般都应该有WEB-INF,而且里面应该有自己的web.xml以作一些只使用与本项目的一些配置。
好了,看看 $CATALINA_BASE/conf/web.xml要怎么配置,在文件里可以找到下面的servlet,去掉注释,修改和增加一些变量:
<servlet>
<servlet-name>cgi</servlet-name>
<servlet-class>org.apache.catalina.servlets.CGIServlet</servlet-class>
<init-param>
<param-name>clientInputTimeout</param-name>
<param-value>100</param-value>
</init-param>
<!--debug的值越高,调试信息越详细-->
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<!--cgiPathPrefix是cgi路径前缀,我个人目前就当做是可以用cgi-bin来替代WEB-INF/cgi使用,但是访问时必须使用cgi-bin而不能用WEB-INF/cgi,其中可能涉及到什么,暂时不太清楚。还有cgi是一个自己建的文件夹名,随意取-->
<init-param>
<param-name>cgiPathPrefix</param-name>
<param-value>WEB-INF/cgi</param-value>
</init-param>
<!--这里代表以c++的方式来解释cgi脚本-->
<init-param>
<param-name>executable</param-name>
<param-value>cmd /c </param-value>
</init-param>
<load-on-startup>5</load-on-startup>
</servlet>
可以看到下面的几行就代表一个变量,param-name是变量名,param-value就是变量的值
<init-param>
<param-name>clientInputTimeout</param-name>
<param-value>100</param-value>
</init-param>
接下来同样是在配置文件找到cgi的servlet映射,去掉注释,这里要说明一下cgi-bin可以看成是个变量,代表上面的”WEB-INF/cgi“,以后会用到,这里一般不作修改。
<servlet-mapping>
<servlet-name>cgi</servlet-name>
<url-pattern>/cgi-bin/*</url-pattern>
</servlet-mapping>
如果修改<url-pattern>/cgi-bin/*</url-pattern>为<url-pattern>/mycgibin/*</url-pattern>,那么访问时要做相应修改
原来访问地址 http://localhost:8080/foo/cgi-bin/Hello.exe 要想应改为 http://localhost:8080/foo/mycgibin/Hello.exe,这里foo是项目名称,等下将作进一步说明。
2.配置文件做好了,还要修改权限,否则启动tomcat服务器会提示错误
同样是conf文件夹, 打开context.xml文件,改为
<!-- The contents of this file will be loaded for each web application -->
<Context privileged="true">
<!-- Default set of monitored resources -->
<WatchedResource>myweb/web.xml</WatchedResource>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
<!-- Uncomment this to enable Comet connection tacking (provides events
on session expiration as well as webapp lifecycle) -->
<!--
<Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
-->
</Context>
其实就是<Context privileged="true">,这里,加了privileged="true"。
3.好了,可以启动tomcat服务器,就是双击bin文件夹下的 startup.bat (windows下,linux是startup.sh),没有提示错误就成功了,恭喜。
4.举个cgi运行的例子吧。
在webapps文件夹下建立自己的项目foo(也就是新建文件夹foo),在foo下新建文件夹WEB-INF,在WEB-INF里新建文件夹cgi (这个要根据配置文件WEB-INF/cgi , 看你写的是什么),WEB-INF可以新建一个web.xml文件作为这个项目的配置,前面提到过了,怎么写就要自己学习下。
#include <stdio.h>
main(int argc,char * argv[]){
printf("Content-type:text/html%c%c",10,10);
printf("<html><body>");
printf("<font color = blue>");
printf("<H1>Hello there!</H>");
printf("</font>");
printf("</body></html>");
}
接下来用以上代码编译生成exe文件,就是我们要的脚本文件。<url-pattern>/cgi-bin/*</url-pattern>,如果你注意到这行和上面jsp的servlet映射,也会推测我们的cgi文件是不要求后缀名,也就是你可以将其改任何后缀名或者没有后缀名,姑且改为Hello.cgi。好了,吧脚本文件放到cgi文件夹里面吧,然后在浏览器地址栏贴上http://localhost:8080/foo/cgi-bin/Hello.cgi , 回车,恭喜,调用成功
若不成功,一定什么步骤错了,检查吧。