我是網絡I/O編程的新手,我碰到了一個障礙 - 基本上我想要做的是讓桌面應用程序與谷歌地圖JavaScript API。爲了促進這一點,我已經構建了一個Java applet,它將充當桌面應用程序和瀏覽器JavaScript應用程序之間的橋樑。當我在Eclipse中一起運行桌面應用程序和applet時,它們可以完美地通信,並且我可以通過將字符串寫入綁定到Applet與ServerSocket建立連接的同一端口的Socket來調用Applet函數。爲了在Eclipse中進行測試,我將字符串「sendJSAlertTest」發送到套接字的輸出流,然後使用ServerSocket輸入流中的java.lang.reflect API派生Method實例,最後調用applet中的結果方法。當applet在瀏覽器中運行時,我將「sendJSAlert」寫入套接字,因爲它導致實際調用javascript。 Eclipse中使用appletviewer的結果是,桌面應用程序上下文打印輸出「awesome sendJSAlert」,而applet上下文打印sendJSAlertTest()方法的輸出,「Hello Client,我是服務器!」。將「sendJSAlert」傳遞給在瀏覽器中運行的小程序的結果是,桌面應用程序打印出null,這表明由於某種原因,ServerSocket的輸入流爲空,並且瀏覽器本身什麼也不做,因爲它應該生成一個javascript alert框文本「你好客戶端,我是服務器!」。我使用的瀏覽器是谷歌Chrome,而且目前我只是運行在本地機器上的一切(還涉及如沒有遠程服務器)通過套接字在Java桌面應用程序和Java瀏覽器小應用程序之間建立通信
下面是相關的Java代碼和HTML:
SocketClient。 java的
import java.awt.event.*;
import java.io.*;
import java.net.*;
public class SocketClient {
Socket socket = null;
PrintWriter out = null;
BufferedReader in = null;
private InetAddress myAddress;
private String remoteFunction;
public SocketClient(){
}
public void listenSocket(int portNum){
//Create socket connection
try{
System.out.println("@Client Trying to create socket bound to port " + portNum);
socket = new Socket(<my hostname here as a string>, portNum);
System.out.println("the attached socket port is " + socket.getLocalPort());
System.out.flush();
out = new PrintWriter(socket.getOutputStream(), true);
out.println("sendJSAlertTest");
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = in.readLine();
System.out.println("@CLient side Text received from server: " + line);
} catch (UnknownHostException e) {
System.out.println("Unknown host: <my hostname here as a string>.eng");
System.exit(1);
} catch (IOException e) {
System.out.println("No I/O");
e.printStackTrace();
System.exit(1);
}
}
public void setRemoteFunction(String funcName){
remoteFunction = funcName;
}
public String getRemoteFunction(){
return remoteFunction;
}
}
SocketServer.java
import java.io.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.*;
class SocketServer {
ServerSocket server = null;
Socket client = null;
BufferedReader in = null;
PrintWriter out = null;
String line;
private NetComm hNet;
private Method serverMethod;
SocketServer(NetComm netmain){
hNet = netmain;
}
public void listenSocket(int portNum){
try{
System.out.println("@server Trying to create socket bound to port " + portNum);
server = new ServerSocket(portNum);
System.out.println("the attached socket port is " + server.getLocalPort());
} catch (IOException e) {
System.out.println("Could not listen on port " + portNum);
System.exit(-1);
}
try{
client = server.accept();
System.out.println("Connection accepted!");
} catch (IOException e) {
System.out.println("Accept failed: " + portNum);
System.exit(-1);
}
try{
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.out.println("Accept failed: " + portNum);
System.exit(-1);
}
while(true){
try{
System.out.println("trying to read from inputstream...");
line = in.readLine();
System.out.println(line);
//Now that we have a method name, invoke it
try {
serverMethod = hNet.getClass().getDeclaredMethod(line,
String.class);
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
serverMethod.invoke(hNet, "Hello Client, I'm a Server!");
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Send data back to client
out.println("awesome " + line);
} catch (IOException e) {
System.out.println("Read failed");
System.out.flush();
System.exit(-1);
}
}
}
protected void finalize(){
//Clean up
try{
in.close();
out.close();
server.close();
} catch (IOException e) {
System.out.println("Could not close.");
System.exit(-1);
}
}
public int getBoundLocalPort(){
return server.getLocalPort();
}
}
NetComm.java
import cresco.ai.att.ccm.core.CCMMain;
import cresco.ai.att.ccm.gui.DataPanel;
import java.io.*;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URL;
import java.util.ArrayList;
import javax.servlet.*;
import javax.servlet.http.*;
import java.applet.*;
public class NetComm extends JApplet{//HttpServlet{
private CCMMain hMain;
private DataPanel dpLocal;
private SocketServer sockserver;
private Method serverMethod;
String testStr;
Integer testInt; /*integer */
Character testChar; /*character*/
//Testing this...
ServerSocket server = null;
Socket client = null;
BufferedReader in = null;
PrintWriter out = null;
String line;
@Override
public void init(){
sockserver = new SocketServer(this);
//For offline debug (should be disabled in a release to the webapp):
//initSocketServer is commented out in the release version and
//invoked in the Eclipse testbed version. In the webapp,
//initSocketServer is invoked from javascript (see below js sockPuppet())
//////initSocketServer(0);
String msg = "Hello from Java (using javascript alert)";
try {
getAppletContext().showDocument(new URL("javascript:doAlert(\"" +
msg +"\")"));
}
catch (MalformedURLException me) { }
}
public void sendJSAlertTest(String message){
System.out.println("sendJSAlert remotely invoked, with message: " +
message);
}
public void sendJSAlert(String message){
try {
getAppletContext().showDocument(new URL("javascript:doAlert(\"" +
message +"\")"));
}
catch (MalformedURLException me) { }
}
public void initSocketServer(int portNum){
sockserver.listenSocket(portNum);
}
public void finalizeSocketServer(){
sockserver.finalize();
}
public int socket2Me(int portNum){
try {
socks.add(new ServerSocket(portNum));
return 0; //socket opened successfully
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return -1; //socket failed to open
}
}
public int getSocketServerPort(){
return sockserver.getBoundLocalPort();
}
public void showRectTest(){
try {
getAppletContext().showDocument(new
URL("javascript:overlayRect()"));
}
catch (MalformedURLException me) { }
}
public void setGUI(DataPanel d){
dpLocal = d;
}
}
MapViz.html
<html>
<head>
<title>Welcome to Geographic Midpoint Map Vizualization!</title>
<meta name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no">
<meta charset="UTF-8">
<link href="https://google-developers.appspot.com/maps/documentation/javascript
/examples/default.css"
rel="stylesheet" type="text/css">
...google maps stuff omitted...
<script type="text/javascript">
<script type="text/javascript">
function overlayRect(){
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="#FF0000";
ctx.fillRect(0,0,150,75);
}
function doAlert(s){
alert(s);
}
function testJava(){
document.ccmApplet.showRectTest();
}
function sockPuppet(){
var i = parseInt(document.getElementById("args").value,10);
alert("parsing the input args... got " + i);
if(i == NaN || i == null){
i = 0;
}
alert("passed NaN OR null block, i is " + i);
//i = 6672; //because $%*& you, that's why!
document.ccmApplet.initSocketServer(i);
//document.ccmApplet.listenSocket(i);
alert("inittializing socket server...");
//queryPort();
alert("querying port...");
document.ccmApplet.finalizeSocketServer();
//document.ccmApplet.finalize();
alert("finalizing socket server...");
}
function queryPort(){
var d = document.getElementById("debug");
var s1 = "Last port opened was: ";
//var s2 = document.ccmApplet.getLastBoundPort();
var s2 = document.ccmApplet.getSocketServerPort();
var sFinal = s1.concat(s2);
d.value = sFinal;
}
</script>
</head>
<body>
<applet width="500" height="50" name="ccmApplet" archive="CCM.jar"
code="cresco.ai.att.ccm.io.NetComm" MAYSCRIPT></applet>
<p></p>
<canvas id="myCanvas" width="200" height="100"></canvas>
<div id="map_canvas"></div>
<input id="args" type="textentry" value="" />
<button height="50" width="50" onClick="sockPuppet()">Test Socket
Creation</button>
<input id="debug" type="debugthingy" value="debug area..." />
<button height="50" width="50" onClick="testJava()">Test Java Callback</button>
</body>
</html>
在web應用,我填寫輸入與本地計算機上有效的端口號的指定參數和按下該調用馬甲()的javascript測試插座連接按鈕。這應該創建一個ServerSocket並將其綁定到指定的端口,然後我通過SocketClient.listenSocket單獨連接我的桌面客戶端應用程序。 Eclipse在桌面應用上下文中的結果是「awesome sendJSAlertTest」,在appletviewer上下文中是輸出「sendJSAlert遠程調用,消息:Hello Client,我是服務器!」。調用sendJSAlert()的webapp應該調用相同消息的javascript alert函數,創建一個彈出框,其中包含消息「sendJSAlert遠程調用,消息:Hello Client,我是服務器!但在瀏覽器中沒有任何反應(Chrome java或javascript調試控制檯),並且桌面應用程序輸出爲空,而不是像預期的那樣「真棒sendJSAlert」
所以問題:可能導致不同結果的原因?我知道瀏覽器的安全沙箱可能是一個問題,但我已經包含了許可文件,它應該允許任何本地主機端口上通過套接字通信:
grant {
permission java.net.SocketPermission
"localhost:1024-",
"accept, connect, listen, resolve";
};
,雖然我已經無法正常應用的權限這當然是可能的(我用太陽policytool gui); applet代碼中究竟需要做什麼(如果有的話)來應用權限?安全問題是否會導致我看到的響應缺乏?我希望在Chrome的java調試控制檯中報告一個異常,但是沒有任何...
任何幫助將不勝感激,謝謝!
-CCJ
UPDATE: 好吧,一些新的信息:我在Chrome再次運行小程序的JavaScript控制檯打開(可以發誓我想在此之前沒有效果,但顯然不是),並取得了以下控制檯輸出 -
"Uncaught Error: java.security.AccessControlException: access denied
("java.net.SocketPermission" "<myipaddress>:4218" "accept,resolve") MapVizApp.html:154
sockPuppet MapVizApp.html:154 onclick MapVizApp.html:179 Uncaught Error: Error
calling method on NPObject. sockPuppet onclick "
所以現在的問題是我爲什麼跳閘這種安全異常?與上面給出的權限的政策文件是在同一個工作目錄作爲HTML頁面,包含applet的jar文件,並添加以下到我的系統的JRE的安全策略文件
//Grants my NetComm applet the ability to accept, connect, and listen on unpriv. ports
grant codeBase "file:${user.home}\Desktop\dev\invention\ATT\MapViz\CCM.jar" {
permission java.net.SocketPermission
"localhost:1024-",
"accept, connect, listen, resolve";
};
我還沒有但是我的理解是,如果政策文件是爲了一個小程序不需要簽名......如果我錯了,請讓我知道。無論如何,沒有人有任何建議,爲什麼這個安全異常被拋出,儘管策略文件具有上述授予的權限? JRE查找的工作目錄中是否存在策略文件的命名約定?我的工作目錄策略文件現在只是名爲ccmPolFile,但我不清楚JRE應該如何找到它;有什麼我需要添加到小程序代碼來指向預期的工作目錄策略文件的JRE?此外,不應該添加足夠的系統策略文件來滿足CCM.jar中我的applet的套接字權限嗎?
更新2: 我簽署了小程序並將行policy.url.3 = file:$ {user.home} \ Desktop \ dev \ invention \ ATT \ MapViz \ ccmPolFile.policy添加到我的java.security文件中在$ {java.home}/lib/security中(通過http://docs.oracle.com/javase/tutorial/security/tour2/step4.html#Approach2,這顯然是JRE如何查找要加載的策略文件)......可悲的是,結果是完全相同的安全異常。我知道的唯一剩下的就是
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// perform the security-sensitive operation here
return null;
}
});
這應該讓我做任何事情,因爲小程序現在已經簽署。我想繼續退出等式,但政策文件由於某種原因而不起作用。我很快就會回來與如何工作了
1)鑑於你沒有添加一個,提示我問..你的問題是什麼? 2)爲了更快地獲得更好的幫助,請發佈[SSCCE](http://sscce.org/)。對於這種用例,它需要是一個混合應用程序/ applet(擴展applet,但有一個'main(String [])'來啓動應用程序。)。 3)觀察到的任何差異可能與安全性有關。一旦小應用程序加載並嘗試與應用程序通信,請檢查Java控制檯的輸出。 – 2012-07-19 02:39:48
@Andrew Thompson:是的,對的是真正的問題......現在加入。如果我按照您的建議設置應用程序(將applet嵌入到應用程序中),如何將applet上下文設置爲在瀏覽器中運行? – CCJ 2012-07-19 04:46:45
下面是一個[混合的例子](https://sites.google.com/site/drjohnbmatthews/subway)這個applet並沒有嵌入到網頁的任何地方。針對您的使用案例,小程序和應用程序。版本顯然會做非常不同的事情,而不是那個爲兩者加載相同GUI的例子。 – 2012-07-19 04:55:54