1. 程式人生 > >網路程式設計-bio

網路程式設計-bio

ClientSocket
public class TestClient{
    public static void main(String[] args){
        //建議一個Socket連線
        Socket socket = null;
        //通過socket連線,輸出流(請求)物件,獲取輸入流(響應)
        InputStream is = null;
        OutputStream os = null;
        try{
           socket = new Socket("localhost",8080
); //傳送請求 os = socket.getOutputStream(); os.write("GET localhost:8080 HTTP/1.1\n".getBytes()); //請求行 os.write("HOST:localhost:8080\n".getBytes()); //請求頭 os.write("\n".getBytes()); //請求空行 System.out.println("傳送請求,同步阻塞等待響應..."); //響應結果
is = socket.getInputStream(); int len; while((len = is.read())!=-1){ System.out.print((char)len); } System.out.println("請求響應完畢,釋放資源..."); }catch(IOException e){ e.printStackTrace(); }finally{ //釋放資源
... } } }
ServerSocket
public class TestServer{
    public void main(String[] args){
        //建立ServerSocket伺服器,並監聽8080埠
        ServerSocket server = null;
        Socket socket = null;
        OutputStream os = null;
        try{
            server = new ServerSocket(8080);
            while(true){
            //server接收到有socket連線時,自動建立socket
            socket = server.accept();
            //獲取輸出流物件
            os = socket.getOutputStream();
            //響應資料
            os.write("HTTP/1.1 200 OK\n".getBytes());	//響應行
            os.write("Content-Type:text/html;charset=utf-8\n".getBytes());	//響應頭
            os.write("\n".getBytes());	//響應空行
            os.write(("<!DOCTYPE html>\n" +
                    "<html lang=\"en\">\n" +
                    "<head>\n" +
                    "    <meta charset=\"UTF-8\">\n" +
                    "    <title>Title</title>\n" +
                    "</head>\n" +
                    "<body>\n" +
                    "    <h1>Response Success...</h1>\n" +
                    "</body>\n" +
                    "</html>").getBytes());		//響應體
             }
            }catch(IOException e){
                         e.printStackTrace();
            }finally{
                //釋放資源
                ...
            }
        }
    }
}

TomcatServer
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class MyTomcatServer {
    //web資源目錄
    private static String WEB_ROOT = System.getProperty("user.dir") + "/network/src/main/webapp";
    //使用者請求url
    private static String url;
    //儲存檔案集合
    private static Map<String, File> webMap = new HashMap<String, File>();

    public static void main(String[] args) {
        //將WEB_ROOT中路徑反斜槓轉換成正斜槓
        WEB_ROOT = WEB_ROOT.replace("\\", "/");
        //建立ServerSocket伺服器,並監聽8080埠
        ServerSocket server = null;
        Socket socket = null;
        InputStream is = null;
        OutputStream os = null;
        try {
            server = new ServerSocket(8888);
            while (true) {
                //server接收到有socket連線時,自動建立socket
                socket = server.accept();
                //獲取輸入流物件(獲取請求引數)
                is = socket.getInputStream();
                //解析得到請求url
                parseUrl(is);
                //獲取輸出流物件(響應結果)
                os = socket.getOutputStream();
                //根據請求url響應檢視
                responseView(os);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            closeMethod(is);
            closeMethod(os);
            closeMethod(socket);
        }
    }

    //解析得到請求url
    private static void parseUrl(InputStream is) throws IOException {
        byte[] buff = new byte[2048];
        int len = is.read(buff);
        String content = new String(buff, 0, len);
        System.out.println("content:" + content);
        //對請求引數處理
        int index1, index2;
        index1 = content.indexOf(" ");
        if (index1 != -1) {
            index2 = content.indexOf(" ", index1 + 1);
            if (index2 > index1) {
                //找到了請求行中的url索引
                url = WEB_ROOT + content.substring(index1, index2).trim();
                System.out.println("url:" + url);
            }
        }
    }

    //根據請求url響應檢視
    private static void responseView(OutputStream os) {
        InputStream is = null;
        try {
            //讀取web目錄下的所有資源
            loadFile(new File(WEB_ROOT));
            File file = webMap.get(url);
            if (file == null) {
                //說明使用者輸入url沒有匹配的靜態網頁,返回404
                file = webMap.get(WEB_ROOT + "/404.html");
            }
            //讀取file
            is = new FileInputStream(file);
            byte[] buff = new byte[1024];
            int len;
            StringBuilder sb = new StringBuilder();
            String str = "";
            while ((len = is.read(buff)) != -1) {
                str = new String(buff, 0, len);
                sb.append(str);
            }
            String content = sb.toString();
            os.write("HTTP/1.1 200 OK\n".getBytes());    //響應行
            os.write("Content-Type:text/html;charset=utf-8\n".getBytes());    //響應頭
            os.write("\n".getBytes());    //響應空行
            os.write(content.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            closeMethod(is);
        }
    }

    //將WEB_ROOT下的所有資源讀取到map中
    private static void loadFile(File file) {
        if (file != null && file.exists()) {
            //檔案就存到map,資料夾就開啟
            if (file.isFile()) {
                //判斷是不是靜態網頁
                String filename = file.getName();
                if (filename != null && filename.contains("html")) {
                    String absolutePath = file.getAbsolutePath().replace("\\", "/");
                    webMap.put(absolutePath, file);
                }
            } else {
                //資料夾則開啟資料夾
                File[] listFiles = file.listFiles();
                for (File fileSon : listFiles) {
                    loadFile(fileSon);
                }
            }
        }
    }

    //釋放資源的方法
    private static void closeMethod(Closeable closeable) {
        if (closeable != null) {
            try {
                closeable.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}	
TomcatServer原理
1.tomcat原理
	ServerSocket類是tomcat的基石,當tomcat伺服器啟動,底層就啟動了ServerSocket,並且監聽8080,即ServerSocket server = new ServerSocket(8080);當瀏覽器端傳送請求,實際上是建立了一次Socket連線,ServerSocket監聽到這一次連線後,便在伺服器端接收連線;通過socket.getInputStream()獲取請求引數,再通過socket.getOutputStream()相應資料給瀏覽器端;

2.Socket通訊中read()方法阻塞問題:
	is.read()返回-1的底層實現方式是:當讀取磁碟檔案時,輸入流讀取到檔案結束符,輸入流便知道檔案讀取完畢,返回-1;而網路傳輸中,輸入流並不知道什麼時候才能讀取完畢,因此會出現阻塞
	三種解決解決方案:
* 用一個大的位元組陣列接收,避免while()迴圈
byte[] buff = new byte[2048];
int len = is.read(buff);
String str = new String(buff,0,len);
* 客戶端傳輸完畢後,手動關閉流
socket.shutdownOutput();
* 設定超時時間
 socket.setSoTimeout(3000);

3.System.getProperty("user.dir")獲取當前專案的路徑,多級目錄間用"\"隔開