1. 程式人生 > >socket模擬http傳送請求

socket模擬http傳送請求

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

/**
 * 一個簡單的HTTP客戶端,的作用
 * 和httpUrlConnection,HttpClient 
 * ,AsycnHttpClient,
 * xutils中httpUtils是一樣的。
 * 傳送HTTP請求,模擬瀏覽器
 * 可列印伺服器傳送過來的HTTP訊息
 */
public class SimpleHttpClient {
	private static String encoding = "GBK";

	public void send(String ip,int port,String url,String sendData)
	{
		try {
			//http連線(短連線,缺點每次再連,佔用時間):http定義請求由三部分組成,返回的內容由三部分組成
//http傳送的內容由socket傳送
			//socket連線
			Socket socket = new Socket(ip, port);
			OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
			StringBuffer sb = new StringBuffer();
			//http協議中請求行
			sb.append("GET "+url+" HTTP/1.1\r\n");
			
			//http協議中請求頭
			sb.append("Host: "+ip+"\r\n");
			sb.append("Connection: Keep-Alive\r\n");
			sb.append("user-agent: 1601\r\n");
			//注,這是關鍵的關鍵,忘了這裡讓我搞了半個小時。這裡一定要一個回車換行,表示訊息頭完,不然伺服器會等待
			sb.append("\r\n");
			osw.write(sb.toString());
			osw.flush();

			//--輸出伺服器傳回的訊息的頭資訊
			InputStream is = socket.getInputStream();
			String line = null;
			int contentLength = 0;//伺服器傳送回來的訊息長度
			// 讀取所有伺服器傳送過來的請求引數頭部資訊
			do {
				line = readLine(is, 0);
				//如果有Content-Length訊息頭時取出
				if (line.startsWith("Content-Length")) {
					contentLength = Integer.parseInt(line.split(":")[1].trim());
				}
				//列印請求部資訊
				System.out.print(line);
				//如果遇到了一個單獨的回車換行,則表示請求頭結束
			} while (!line.equals("\r\n"));

			//--輸訊息的體
			System.out.print(readLine(is, contentLength));

			//關閉流
			is.close();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		SimpleHttpClient httpClient=new SimpleHttpClient();
		//遠端 124.207.192.18
		//本地班172.60.5.100
		httpClient.send("172.60.5.100", 
				8080, "/allRunServer/login.html",
				null);
	}

	/*
	 * 這裡我們自己模擬讀取一行,因為如果使用API中的BufferedReader時,它是讀取到一個回車換行後
	 * 才返回,否則如果沒有讀取,則一直阻塞,直接伺服器超時自動關閉為止,如果此時還使用BufferedReader
	 * 來讀時,因為讀到最後一行時,最後一行後不會有回車換行符,所以就會等待。如果使用伺服器傳送回來的
	 * 訊息頭裡的Content-Length來擷取訊息體,這樣就不會阻塞
	 * 
	 * contentLe 引數 如果為0時,表示讀頭,讀時我們還是一行一行的返回;如果不為0,表示讀訊息體,
	 * 時我們根據訊息體的長度來讀完訊息體後,客戶端自動關閉流,這樣不用先到伺服器超時來關閉。
	 */
	private static String readLine(InputStream is, int contentLe) throws IOException {
		ArrayList lineByteList = new ArrayList();
		byte readByte;
		int total = 0;
		if (contentLe != 0) {
			do {
				readByte = (byte) is.read();
				lineByteList.add(Byte.valueOf(readByte));
				total++;
			} while (total < contentLe);//訊息體讀還未讀完
		} else {
			do {
				readByte = (byte) is.read();
				lineByteList.add(Byte.valueOf(readByte));
			} while (readByte != 10);
		}

		byte[] tmpByteArr = new byte[lineByteList.size()];
		for (int i = 0; i < lineByteList.size(); i++) {
			tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
		}
		lineByteList.clear();

		return new String(tmpByteArr, encoding);
	}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;

/**
 * 一個簡單的HTTP客戶端,
 * 傳送HTTP請求,模擬瀏覽器
 * 可列印伺服器傳送過來的HTTP訊息
 */
public class ConnectMyWebServer {
	private static String encoding = "GBK";

	public static void main(String[] args) {
		try {
			//本地班124.207.192.18改成172.60.5.100
			Socket socket = new Socket("172.60.50.223", 8080);
			OutputStreamWriter osw = new OutputStreamWriter(socket.getOutputStream());
			StringBuffer sb = new StringBuffer();
			sb.append("GET /index.html HTTP/1.1\r\n");
			sb.append("Host: 172.60.50.223\r\n");
			sb.append("Connection: Keep-Alive\r\n");
			sb.append("user-agent: simpleHttpClinet zhangjiujun\r\n");
			//注,這是關鍵的關鍵,忘了這裡讓我搞了半個小時。這裡一定要一個回車換行,表示訊息頭完,不然伺服器會等待
			sb.append("\r\n");
			osw.write(sb.toString());
			osw.flush();

			//--輸出伺服器傳回的訊息的頭資訊
			InputStream is = socket.getInputStream();
			String line = null;
			int contentLength = 0;//伺服器傳送回來的訊息長度
			// 讀取所有伺服器傳送過來的請求引數頭部資訊
			do {
				line = readLine(is, 0);
				//如果有Content-Length訊息頭時取出
				if (line.startsWith("Content-Length")) {
					contentLength = Integer.parseInt(line.split(":")[1].trim());
				}
				//列印請求部資訊
				System.out.print(line);
				//如果遇到了一個單獨的回車換行,則表示請求頭結束
			} while (!line.equals("\r\n"));

			//--輸訊息的體
			System.out.print(readLine(is, contentLength));

			//關閉流
			is.close();

		} catch (UnknownHostException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/*
	 * 這裡我們自己模擬讀取一行,因為如果使用API中的BufferedReader時,它是讀取到一個回車換行後
	 * 才返回,否則如果沒有讀取,則一直阻塞,直接伺服器超時自動關閉為止,如果此時還使用BufferedReader
	 * 來讀時,因為讀到最後一行時,最後一行後不會有回車換行符,所以就會等待。如果使用伺服器傳送回來的
	 * 訊息頭裡的Content-Length來擷取訊息體,這樣就不會阻塞
	 * 
	 * contentLe 引數 如果為0時,表示讀頭,讀時我們還是一行一行的返回;如果不為0,表示讀訊息體,
	 * 時我們根據訊息體的長度來讀完訊息體後,客戶端自動關閉流,這樣不用先到伺服器超時來關閉。
	 */
	private static String readLine(InputStream is, int contentLe) throws IOException {
		ArrayList lineByteList = new ArrayList();
		byte readByte;
		int total = 0;
		if (contentLe != 0) {
			do {
				readByte = (byte) is.read();
				lineByteList.add(Byte.valueOf(readByte));
				total++;
			} while (total < contentLe);//訊息體讀還未讀完
		} else {
			do {
				readByte = (byte) is.read();
				lineByteList.add(Byte.valueOf(readByte));
			} while (readByte != 10);
		}

		byte[] tmpByteArr = new byte[lineByteList.size()];
		for (int i = 0; i < lineByteList.size(); i++) {
			tmpByteArr[i] = ((Byte) lineByteList.get(i)).byteValue();
		}
		lineByteList.clear();

		return new String(tmpByteArr, encoding);
	}
}