我正在建立一個代理服務器的android和我已經打了一堵牆。我絕望地需要幫助。我對Android非常陌生。 因此,我首先在Java SE中創建了代理服務器。代理服務器的工作原理如下:拼命地需要幫助建立一個代理服務器的Android
它監聽本地端口,
當客戶端連接,一個新的線程被創建。每個線程也被賦予一個名字。
HOST從請求中提取。
然後客戶端的請求被轉發到遠程地址(從主機獲取)。
代理然後讀取遠程服務器的地址,直到找到-1。
該響應然後被轉發給客戶端。
代理服務器運行在筆記本電腦上。客戶端是Android手機的Youtube APP。 手機已經植根,我已經安裝了ProxyDroid以告訴客戶端代理服務器在哪裏。 使用ProxyDroid的「全局代理」選項。
在Java SE代碼:
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
class clientThread implements Runnable
{
Socket clientSocket = null;//each client socket.
Socket connectYoutubeServerSock = null;//This socket is used to write client's request to the
//YouTube Server.
int videoFlag = 0;//this flag determines whether the GET request is a video request or not.
final int BufferSize = 8019;
public String hostURL;
int youtubePort = 80;
//public DataOutputStream sendClientResponse = null;
public clientThread(Socket clientSocket)
{
this.clientSocket = clientSocket;
}
public void run()
{
System.out.println("Client connected: "+clientSocket.toString());
System.out.println("Current Thread Name: "+Thread.currentThread().getName());
try
{
byte youtubeAppReqArray[] = new byte[BufferSize];//this byte array will house youtube app's request!
InputStream youtubeAppReq = clientSocket.getInputStream();
// reading the request and put it into youtubeAppReqArray.
int bytesRead = youtubeAppReq.read(youtubeAppReqArray,0,BufferSize);
String youtubeAppReqString = new String(youtubeAppReqArray, 0, bytesRead);
System.out.println(youtubeAppReqString);
// extract the url of the GET request!
int gStart = youtubeAppReqString.indexOf("GET: ") + 4;
int gEnd = youtubeAppReqString.indexOf('\n', gStart);
String gURL = youtubeAppReqString.substring(gStart, gEnd - 9);
System.out.println("URL of GET: " + gURL);
//test if videoplayback is there or not?
if(gURL.indexOf("videoplayback") > -1 )
{
System.out.println("This is a video request!");
videoFlag = 1;
}
// extract the host to connect to
int hStart = youtubeAppReqString.indexOf("Host: ") + 6;
int hEnd = youtubeAppReqString.indexOf('\n', hStart);
String host = youtubeAppReqString.substring(hStart, hEnd - 1);
System.out.println("Connecting to host " + host);
//forward the youtube app request from proxy to the youtube server
Socket youtubeServerSocket = new Socket(host, 80);
OutputStream writeToYoutubeServerStream = youtubeServerSocket.getOutputStream();
System.out.println("Forwarding request to server");
writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
writeToYoutubeServerStream.flush();
// forward the response from the server to the browser
byte youtubeServerResArray[] = new byte[BufferSize];//this byte array will house youtube server's response.
InputStream readFromYoutubeServerStream = youtubeServerSocket.getInputStream();
OutputStream writeToYoutubeAppStream = clientSocket.getOutputStream();
System.out.println("Forwarding request from server");
int remoteBytesRead;
do
{
remoteBytesRead = readFromYoutubeServerStream.read(youtubeServerResArray,0,BufferSize);
System.out.println("Receiving " + remoteBytesRead + " bytes");
if (remoteBytesRead > 0)
{
writeToYoutubeAppStream.write(youtubeServerResArray, 0, remoteBytesRead);
String rData = new String(youtubeServerResArray,0,remoteBytesRead);
System.out.println("Remote data: "+rData);
}
} while (remoteBytesRead > 0);
writeToYoutubeAppStream.flush();
youtubeServerSocket.close();
clientSocket.close();
System.out.println("End of communication");
}
catch(IOException ioe)
{
System.out.println("Error"+ioe.getMessage());
}
}
}
public class ChallengeProxy extends IOException
{
public static final int SERVERPORT = 4447;
public static int threadName = 0;
public static void main(String[] args)
{
ChallengeProxy proxyObj = new ChallengeProxy();
proxyObj.knowIP();//get the IP address of the local machine!
try
{
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
System.out.println("Started on: "+SERVERPORT);
while(true)//Non stop listen for clients!
{
Socket clientSocket = serverSocket.accept();//blocks until client is connected!
System.out.println("Client connected: "+clientSocket.toString());
Thread t = new Thread(new clientThread(clientSocket), Integer.toString(threadName));
t.start();
threadName++;
}
}
catch (IOException ioe)
{
System.out.println("Could not listen on port: "+SERVERPORT);
System.out.println("Error"+ioe.getMessage());
}
catch(Exception e)
{
System.out.println("Error"+e.getMessage());
}
}
public void knowIP()
{
try
{
Enumeration e = NetworkInterface.getNetworkInterfaces();
while(e.hasMoreElements())
{
NetworkInterface ni = (NetworkInterface) e.nextElement();
System.out.println("Net interface: "+ni.getName());
Enumeration e2 = ni.getInetAddresses();
while (e2.hasMoreElements())
{
InetAddress ip = (InetAddress) e2.nextElement();
System.out.println("IP address: "+ ip.toString());
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
它確實是正是我想要的。現在,我將代碼稍微轉換一下,以便它在Android中運行。 但是,下面的邏輯是相同的。這裏還有,當一個新的客戶端連接時,一個新的線程被創建。 Youtube APP仍然是客戶端。所以,現在,YouTube應用程序會請求駐留在同一臺Android機器上的代理服務器。和以前一樣,ProxyDroid的配置使得YouTube APP知道我的代理服務器在哪裏運行。
爲Android的代碼如下所示(後我得到的第一個回答,這是不完全的,因爲在完成代碼已開始出現嚴重的錯誤之前,該代碼相應的修改!):
public class ChallengeAndroidProxyActivity extends Activity
{
public static final int SERVERPORT = 4453;
public static int threadName = 0;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
(new Thread(new Runnable()
{
public void run()
{
startSocketServer();
}
}
)).start();
}
/*
* Here we will create an infinite loop that will listen
* for client connections.
*
* */
public void startSocketServer()
{
knowIP();// Now we find the IP address of the native machine.
String LOG_TAG = "SocketServerThread";
Log.i(LOG_TAG,"Inside the server thread! ");
try
{
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
Log.i(LOG_TAG, "Started on : " + SERVERPORT);
threadName = 0;
while (true)// Non stop listen for clients!
{
Socket clientSocket = serverSocket.accept();
Log.d(LOG_TAG , "Client connected : " + clientSocket.toString());
Thread t = new Thread(new clientThread(clientSocket), Integer.toString(threadName));
t.start();
threadName++;
}
}
catch (IOException ioe)
{
Log.i(LOG_TAG, "Could not listen on port: " + SERVERPORT);
Log.i(LOG_TAG, "Error : " + ioe.getMessage());
}
catch (Exception e)
{
Log.i(LOG_TAG, "Error : " + e.getMessage());
}
}
class clientThread implements Runnable
{
String LOG_TAG = "clientSocketThread";
Socket clientSocket = null;//each client socket.
Socket connectYoutubeServerSock = null;//This socket is used to write client's request to the
//YouTube Server.
int videoFlag = 0;//this flag determines whether the GET request is a video request or not.
final int BufferSize = 8019;
public String hostURL;
int youtubePort = 80;
public clientThread(Socket clientSocket)
{
this.clientSocket = clientSocket;
}
public void run()
{
Log.i(LOG_TAG,"Client connected: "+clientSocket.toString());
Log.i(LOG_TAG,"Current Thread Name: "+Thread.currentThread().getName());
try
{//1
byte youtubeAppReqArray[] = new byte[BufferSize];//this byte array will house youtube app's request!
InputStream youtubeAppReq = clientSocket.getInputStream();
// reading the request and put it into youtubeAppReqArray.
int bytesRead = youtubeAppReq.read(youtubeAppReqArray,0,BufferSize);
String youtubeAppReqString = new String(youtubeAppReqArray, 0, bytesRead);
Log.i("Youtube App Request: ",youtubeAppReqString);
// extract the host to connect to
int hStart = youtubeAppReqString.indexOf("Host: ") + 6;
int hEnd = youtubeAppReqString.indexOf('\n', hStart);
String host = youtubeAppReqString.substring(hStart, hEnd - 1);
Log.i("Connecting to host ",host);
InetAddress addr = InetAddress.getByName(host);
int port = 80;
SocketAddress sockaddr = new InetSocketAddress(addr, port);
Socket youtubeServerSocket = new Socket();
youtubeServerSocket.connect(sockaddr);
OutputStream writeToYoutubeServerStream = youtubeServerSocket.getOutputStream();
//writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
}//1
catch(IOException ioe)
{//1
Log.i("Error",ioe.getMessage());
}//1
}
}
/************************************************************************************/
public void knowIP()
{
This function just gets the IP of the native machine.
}
}
代碼已經根據第一個答案建議的更改進行修改。當代碼行
//writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
是註釋掉(通過這條線,我的代理寫入客戶端的請求到遠程服務器),我從客戶端獲得請求的樣子:
07-19 22:30:16.309: I/ApplicationPackageManager(2843): cscCountry is not German : NEE
07-19 22:30:16.399: I/Net interface:(2843): wlan0
07-19 22:30:16.429: I/IP address:(2843): /192.168.1.129
07-19 22:30:16.429: I/Net interface:(2843): lo
07-19 22:30:16.439: I/IP address:(2843): /127.0.0.1
07-19 22:30:16.439: I/SocketServerThread(2843): Inside the server thread!
07-19 22:30:16.439: I/SocketServerThread(2843): Started on : 4453
07-19 22:30:20.929: D/SocketServerThread(2843): Client connected : Socket[addr=/192.168.1.129,port=44276,localport=4453]
07-19 22:30:20.959: I/clientSocketThread(2843): Client connected: Socket[addr=/192.168.1.129,port=44276,localport=4453]
07-19 22:30:20.959: I/clientSocketThread(2843): Current Thread Name: 0
07-19 22:30:20.969: I/Youtube App Request:(2843): GET http://gdata.youtube.com/feeds/api/users/asadfffx/newsubscriptionvideos?format=2%2C3%2C9&start-index=1&max-results=10&safeSearch=none HTTP/1.1
07-19 22:30:20.969: I/Youtube App Request:(2843): GData-Version: 2
07-19 22:30:20.969: I/Youtube App Request:(2843): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="
07-19 22:30:20.969: I/Youtube App Request:(2843): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"
07-19 22:30:20.969: I/Youtube App Request:(2843): Host: gdata.youtube.com
07-19 22:30:20.969: I/Youtube App Request:(2843): User-Agent: Android-YouTube/2
07-19 22:30:20.969: I/Youtube App Request:(2843): Proxy-Connection: close
07-19 22:30:20.969: I/Youtube App Request:(2843): Connection: close
07-19 22:30:20.969: I/Youtube App Request:(2843):
07-19 22:30:20.979: I/Connecting to host(2843): gdata.youtube.com
這就是客戶請求的樣子。但是,當我對以下行(即被執行)取消註釋時:
writeToYoutubeServerStream.write(youtubeAppReqArray, 0, bytesRead);
一切都崩潰了。特別是,來自YouTube應用的請求沒有任何意義。數百個線程被創建。我的GET請求看起來像:
07-19 22:36:21.969: I/Youtube App Request:(2916): GData-Version: 2
07-19 22:36:21.969: I/Youtube App Request:(2916): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="
07-19 22:36:21.969: I/Youtube App Request:(2916): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"
07-19 22:36:21.969: I/Youtube App Request:(2916): Host: gdat
07-19 22:36:21.969: I/Connecting to host(2916): gdata.youtube.com
07-19 22:36:21.979: D/SocketServerThread(2916): Client connected : Socket[addr=/192.168.1.129,port=55126,localport=4453]
07-19 22:36:21.979: I/clientSocketThread(2916): Client connected: Socket[addr=/192.168.1.129,port=55125,localport=4453]
07-19 22:36:21.979: I/clientSocketThread(2916): Current Thread Name: 463
07-19 22:36:21.979: I/Youtube App Request:(2916): GET http://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.comhttp://gdata.youtube.com/feeds/api/users/asadfffx/newsubscriptionvideos?format=2%2C3%2C9&start-index=1&max-results=10&safeSearch=none HTTP/1.1
07-19 22:36:21.979: I/Youtube App Request:(2916): GData-Version: 2
07-19 22:36:21.979: I/Youtube App Request:(2916): X-GData-Device: device-id="AOuj_RqmoX-WkCNNaJKieF2mmwMlkOMFRk7sQsKP_wmdrL1BB1N9V_iVIJAUBkvvyzGdpxWVS83wE7UkGPYjWf0BWvbPa0Uoo0cmgKfxzEqOog8EC-Rm1Wg", data="H1NEdDZ+FuL4U9v3Bx1hlVIAm1s="
07-19 22:36:21.979: I/Youtube App Request:(2916): Authorization: GoogleLogin auth="DQAAAKcAAAC5aU6IN0t6yUkoiU9OmjU8fYjKm1m7MLKleHLhtR-uwCclnZGcKGm-6gYfkjvAGKGXK88dbKnB708CVCQkvJofL6smBXp7TEFj1FqGaRasdOx2iVYrbaTbWtIc8sBaga7v2P1BfctMiSTtEU2HWCqqCiubMvpfspnl9wS284SLgk-Se4jjFsZTo-84la_2wJy_Wmap8OSTdif7JoaxpxYLAWECByrJO50iMTj__6cN3A"
07-19 22:36:21.979: I/Youtube App Request:(2916): Host: gdata.youtube.com
爲什麼GET請求看起來像這樣?我的猜測是,線程有問題。 正在創建一個插座,讀/寫線程安全的?代碼是否在線程之間跳轉?我究竟做錯了什麼?相同的代碼在Java SE中起作用;那麼爲什麼它會在Android中崩潰?
任何建議,意見和代碼段將不勝感激。
嗨,謝謝你的回覆。根據您的建議,我已對代碼進行了更改。但現在我看到了一些問題,這可能是線程相關的。我已經按照你的建議編輯的代碼,並把它放在這裏。請看看並給我一些建議。 – user1185396 2012-07-19 19:47:41