Java中的代理原理及代理使用示例
今天再測(cè)試Socket編程時(shí),無法連接外網(wǎng)。公司用的是Http的代理。上網(wǎng)搜索也沒看太懂,所以花了大量時(shí)間來學(xué)習(xí)。看了HTTP和TCP協(xié)議的關(guān)系好,才有所明白。現(xiàn)在能通過Socket使用HTTP代理了,結(jié)果很簡(jiǎn)單,過程卻好難。
1. 先簡(jiǎn)要說說HTTP和TCP(具體內(nèi)容自行Google,資料很多很全),這里就講講要點(diǎn):
HTTP:是應(yīng)用層協(xié)議,是基于傳輸層協(xié)議的。
TCP: 是傳輸層協(xié)議,是基于網(wǎng)絡(luò)層協(xié)議的。
IP: 是網(wǎng)絡(luò)層協(xié)議。
一個(gè)TCP的連接要進(jìn)行三次握手(就像轉(zhuǎn)戶口一樣,不詳說),HTTP只是一個(gè)應(yīng)用協(xié)議,也就是相當(dāng)于一個(gè)自定義協(xié)議,即其沒有對(duì)底層的傳輸方式進(jìn)行干涉,只是對(duì)數(shù)據(jù)內(nèi)容格式進(jìn)行了定義。打個(gè)比方,別人說“SB”(你的名字),你回答“是”,僅僅是內(nèi)容格式,沒有改變聲音的傳輸方式(通過聲波傳送<網(wǎng)絡(luò)硬件介質(zhì)>,通過雙方都能聽懂的語(yǔ)言<TCP/IP>)。同理,F(xiàn)TP, Telnet也是一種應(yīng)用層協(xié)議,打個(gè)比方對(duì)于FTP,別人說“SB",你回答“哎”,只是格式內(nèi)容不同而已。
2. 認(rèn)識(shí)到以上之后,我們?cè)僬f說HTTP代理,從上可以理解,HTTP代理服務(wù)器就是這樣一臺(tái)機(jī)器:你把所有的HTTP請(qǐng)求(不管是想請(qǐng)求百度還是Google)都發(fā)到這個(gè)HTTP代理服務(wù)器,然后這個(gè)HTTP代理服務(wù)器請(qǐng)求你要訪問的最終地址,把響應(yīng)回傳給你。這里還要注意它代理的是HTTP協(xié)議,而HTTP又是基于TCP的,也就是說這個(gè)服務(wù)器代理的是指定HTTP內(nèi)容格式的TCP連接。再說下去也沒意思了,看以下代碼:
//以下地址是代理服務(wù)器的地址
Socket socket = new Socket("10.1.2.188", 80);
//寫與的內(nèi)容就是遵循HTTP請(qǐng)求協(xié)議格式的內(nèi)容,請(qǐng)求百度
socket.getOutputStream().write(new String("GET http://www.baidu.com/ HTTP/1.1\r\n\r\n").getBytes());
byte[] bs = new byte[1024];
InputStream is = socket.getInputStream();
int i;
while ((i = is.read(bs)) > 0) {
System.out.println(new String(bs, 0, i));
}
is.close();
當(dāng)然在Java中,有Proxy代理上網(wǎng)的使用,此時(shí)使用URL(HTTP)就不涉及Socket(TCP)了,看如下代碼
//設(shè)置代理
System.setProperty("http.proxySet", "true");
System.setProperty("http.proxyHost", "10.1.2.188");
System.setProperty("http.proxyPort", "80");
//直接訪問目的地址
URL url = new URL("http://www.baidu.com");
URLConnection con = url.openConnection();
InputStreamReader isr = new InputStreamReader(con.getInputStream());
char[] cs = new char[1024];
int i = 0;
while ((i = isr.read(cs)) > 0) {
System.out.println(new String(cs, 0, i));
}
isr.close();
最后總結(jié)一下:
在使用HTTP代理的環(huán)境中,
如果使用Socket(TCP)連接外網(wǎng),則直接連接代理服務(wù)器,然后在發(fā)送的HTTP請(qǐng)求中指明要轉(zhuǎn)發(fā)到的外網(wǎng)網(wǎng)址。
如果使用URL(HTTP)連接外網(wǎng),則需要設(shè)置HTTP代理參數(shù)或使用Proxy。
OK,明白以后可以隨意使用了,看以下代碼,使用NIO的Socket通過HTTP代理訪問外網(wǎng)的例子:
SocketChannel sc = SocketChannel.open(new InetSocketAddress("10.1.2.188", 80));
sc.write(Charset.forName("utf8").encode("GET http://www.baidu.com/ HTTP/1.1\r\n\r\n"));
ByteBuffer buffer = ByteBuffer.allocate(1024);
while (sc.read(buffer) != -1) {
buffer.flip();
System.out.println(Charset.forName("utf8").decode(buffer));
buffer.clear();
}
sc.close();
Java Socket編程中加入代理示例
有些時(shí)候我們的網(wǎng)絡(luò)不能直接連接到外網(wǎng), 需要使用http或是https或是socket代理來連接到外網(wǎng), 這里是java使用代理連接到外網(wǎng)的一些方法,:方法一使用系統(tǒng)屬性來完成代理設(shè)置, 這種方法比較簡(jiǎn)單, 但是不能對(duì)單獨(dú)的連接來設(shè)置代理:
public static void main(String[] args) {
Properties prop = System.getProperties();
// 設(shè)置http訪問要使用的代理服務(wù)器的地址
prop.setProperty("http.proxyHost", "192.168.0.254");
// 設(shè)置http訪問要使用的代理服務(wù)器的端口
prop.setProperty("http.proxyPort", "8080");
// 設(shè)置不需要通過代理服務(wù)器訪問的主機(jī),可以使用*通配符,多個(gè)地址用|分隔
prop.setProperty("http.nonProxyHosts", "localhost|192.168.0.*");
// 設(shè)置安全訪問使用的代理服務(wù)器地址與端口
// 它沒有https.nonProxyHosts屬性,它按照http.nonProxyHosts 中設(shè)置的規(guī)則訪問
prop.setProperty("https.proxyHost", "192.168.0.254");
prop.setProperty("https.proxyPort", "443");
// 使用ftp代理服務(wù)器的主機(jī)、端口以及不需要使用ftp代理服務(wù)器的主機(jī)
prop.setProperty("ftp.proxyHost", "192.168.0.254");
prop.setProperty("ftp.proxyPort", "2121");
prop.setProperty("ftp.nonProxyHosts", "localhost|192.168.0.*");
// socks代理服務(wù)器的地址與端口
prop.setProperty("socksProxyHost", "192.168.0.254");
prop.setProperty("socksProxyPort", "8000");
// 設(shè)置登陸到代理服務(wù)器的用戶名和密碼
Authenticator.setDefault(new MyAuthenticator("userName", "Password"));
}
static class MyAuthenticator extends Authenticator {
private String user = "";
private String password = "";
public MyAuthenticator(String user, String password) {
this.user = user;
this.password = password;
}
protected PasswordAuthentication getPasswordAuthentication() {
returnnew PasswordAuthentication(user, password.toCharArray());
}
}
方法二使用Proxy來對(duì)每個(gè)連接實(shí)現(xiàn)代理, 這種方法只能在jdk 1.5以上的版本使用(包含jdk1.5), 優(yōu)點(diǎn)是可以單獨(dú)的設(shè)置每個(gè)連接的代理, 缺點(diǎn)是設(shè)置比較麻煩:
public static void main(String[] args) {
try {
URL url = new URL("http://www.baidu.com");
// 創(chuàng)建代理服務(wù)器
InetSocketAddress addr = new InetSocketAddress("192.168.0.254",
8080);
// Proxy proxy = new Proxy(Proxy.Type.SOCKS, addr); // Socket 代理
Proxy proxy = new Proxy(Proxy.Type.HTTP, addr); // http 代理
// 如果我們知道代理server的名字, 可以直接使用
// 結(jié)束
URLConnection conn = url.openConnection(proxy);
InputStream in = conn.getInputStream();
// InputStream in = url.openStream();
String s = IOUtils.toString(in);
System.out.println(s);
} catch (Exception e) {
e.printStackTrace();
}
}
相關(guān)文章
Java線程池FutureTask實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Java線程池FutureTask實(shí)現(xiàn)原理詳解,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下2018-02-02關(guān)于Linux服務(wù)器配置java環(huán)境遇到的問題小結(jié)
這篇文章主要介紹了關(guān)于Linux服務(wù)器配置java環(huán)境遇到的問題小結(jié),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Spring Boot 多個(gè)定時(shí)器沖突問題的解決方法
這篇文章主要介紹了Spring Boot 多個(gè)定時(shí)器沖突問題的解決方法,實(shí)際開發(fā)中定時(shí)器需要解決多個(gè)定時(shí)器同時(shí)并發(fā)的問題,也要解決定時(shí)器之間的沖突問題,本文通過問題場(chǎng)景重現(xiàn)給大家介紹的非常詳細(xì),需要的朋友參考下吧2022-05-05Spring中的EurekaServer啟動(dòng)詳解
這篇文章主要介紹了Spring中的EurekaServer啟動(dòng)詳解,初始化eureka,包含eureka集群的同步和發(fā)布注冊(cè),這個(gè)方法時(shí)重寫ServletContextListener#contextInitialized,是eureka啟動(dòng)的入口了,需要的朋友可以參考下2023-11-11java實(shí)現(xiàn)一個(gè)接口調(diào)取另一個(gè)接口(接口一調(diào)取接口二)
這篇文章主要介紹了java實(shí)現(xiàn)一個(gè)接口調(diào)取另一個(gè)接口(接口一調(diào)取接口二),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09Java為實(shí)體類動(dòng)態(tài)添加屬性的方法詳解
這篇文章主要介紹了Java如何給已有實(shí)體類動(dòng)態(tài)的添加字段并返回新的實(shí)體對(duì)象且不影響原來的實(shí)體對(duì)象結(jié)構(gòu)。文中的方法講解詳細(xì),需要的可以參考一下2022-06-06基于Spring接口集成Caffeine+Redis兩級(jí)緩存
這篇文章主要介紹了基于Spring接口集成Caffeine+Redis兩級(jí)緩存,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下2022-07-07IntelliJ IDEA(或者JetBrains PyCharm)中彈出"IntelliJ IDEA License
今天小編就為大家分享一篇關(guān)于IntelliJ IDEA(或者JetBrains PyCharm)中彈出"IntelliJ IDEA License Activation"的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-10-10