基礎筆記12(socket,url網絡通訊)

進一步深刻sockethtml

1.網絡通訊條件:

1.IP地址,可用主機名。
2.傳輸數據時將不用的應用程序經過數字標識區分開來,這種標識稱爲邏輯端口,也稱端口。(0-65535端口,通常系統預留0-1024)
3.通訊規則,即協議。國際通用協議(tcp/ip)

1.1網絡訪問中,會首先經過DNS服務器將域名解析成IP地址再進行訪問.

    對於本地系統目錄下:C:\WINDOWS\System32\drivers\etc的hosts文件有個映射地址,能夠配置。網絡訪問系統會優先查找此配置。web

    能夠經過此配置的地址映射關係,阻止一些應用的網絡訪問(如更新,廣告,等)瀏覽器

 

2.表示ip地址的類,inetAddress

本地地址:
InetAddress localHost = InetAddress.getLocalHost(); String hostAddress = localHost.getHostAddress();// 獲取本地地址對象 String hostName = localHost.getHostName();// 主機名稱 System.out.println(hostAddress);// 10.198.0.150 (本地ip) System.out.println(hostName);//m_pc

遠程地址:tomcat

// InetAddress byName =InetAddress.getByName("www.baidu.com");域名也能夠(即網絡主機名稱)
 InetAddress byName = InetAddress.getByName("14.215.177.38");
 String hostAddress2 = byName.getHostAddress();//
 String hostName2 = byName.getHostName();// 經過ip可能獲取不到遠程的主機名稱,一樣是地址
 System.out.println(hostName2);//14.215.177.38
 System.out.println(hostAddress2);//14.215.177.38

多個地址的服務器:服務器

InetAddress[] byNames = InetAddress.getAllByName("www.baidu.com");//主機對應多個地址的狀況
        for (InetAddress i : byNames) {
            System.out.println("baidu:"+i.getHostAddress());
        }
baidu:14.215.177.38
baidu:14.215.177.37

2.1對地址和端口封裝的類:InetSocketAddress

Socket socket = new Socket();
socket.connect(new InetSocketAddress("127.0.01", 1111));

3.tcp/udp協議

udp:將數據和目的地址封裝在數據包中,無需創建鏈接,不可靠,每一個數據報限制在64k內,速度快。(通常用於聊天,視頻通訊)

tcp:創建鏈接,可靠的,經過三次握手的方式創建鏈接通道,無限制數據大小,速度慢。(其實應該是交給其餘網絡原件維護通訊)數據在其兩端經過io傳輸。

4.socket又叫套接字,爲網絡服務提供一種機制,兩端都是socket,不一樣協議建立socket方式不同。

5.upd通訊例子:(兩端都是DatagramSocket)數據傳輸是一個個數據包,發送和接收。

client:網絡

//建立udp的客戶端socket,可不指定端口系統選擇(udp兩端的socket類相同)
            DatagramSocket datagramSocket = new DatagramSocket();
            byte[] buf="udp send a data".getBytes();
            //建立帶有目標端口和地址的數據包
            DatagramPacket packet = new DatagramPacket(buf, buf.length,InetAddress.getByName("127.0.0.1"),1111);
            for(int i=0;i<5;i++){
            //發生數據包
            datagramSocket.send(packet);
            }
            //關閉資源
            datagramSocket.close();

server:多線程

DatagramSocket serverSocket = null;
        try {
            // 建立udp的服務端socket,必須指定端口
            serverSocket = new DatagramSocket(1111);

            // receive是阻塞方法可重複接收
            while (true) {
                // 建立接收服務端的數據包對象
                DatagramPacket packet = new DatagramPacket(new byte[111], 111);
                // 接收數據包
                serverSocket.receive(packet);
                // 收到的數據packet.getLength()收到數據長度。
                String data = new String(packet.getData(), 0,packet.getLength());
                // 獲取客戶端端口
                int port = packet.getPort();
                // 客戶端地址對象
                InetAddress address = packet.getAddress();
                String ip = address.getHostAddress();
                System.out.println(ip + ":" + port + "----" + data);
            }

6.tcp通訊:數據在其兩端經過io傳輸。(兩端socket不一樣:Socket/ServerSocket)

客戶端socket若是指定目的端口和地址,建立對象即開始鏈接,若是不指定,調用connect方法指定目的和端口再鏈接服務端
客戶端鏈接後會在輸入流的讀取位置阻塞等待接收數據。
客戶端socket關閉時會在數據流中向服務端發送一個IO流結束標記

對於兩端傳輸流字節流,能夠進行封裝,app

對於緩衝字符流。時時寫出,能夠flush(),沒有換行須要本身添加newLine(),(輸出而言,打印流有個優點,定義時能夠封裝字節流,自動刷新。能夠帶換行的輸出字符。
對於自定義的數據,結束須要主動添加結束標記,來中止讀寫,好比每次讀取一行,當讀到「over」,結束.(可是,若是文件中這個內容呢,因此須要儘量的特別,好比加上時間戳還有方式那就主動關閉流。 socket.shutdownOutput())

client:socket

// 客戶端socket,並制定目的和端口
        Socket socket = new Socket("127.0.0.1", 2222);
        // 輸出流
        OutputStream out = socket.getOutputStream();
        out.write("1我是客戶端,呼叫 服務端".getBytes());
        // 輸入流
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[222];
        // 阻塞方法,等待讀取
        int length = in.read(buf);
        System.out.println(new String(buf, 0, length));
        // 關閉流,關閉socket
        socket.close();// socket關閉,流也會關閉,若是有處理流需手動關閉

server: ServerSocket(端口,隊列長度)除了指定端口還能夠指定隊列長度即:同時能夠接收處理客戶端鏈接個數。async

// 創建服務端socket,指定端口
        ServerSocket serverSocket = new ServerSocket(2222);
        // 獲取客戶端的鏈接,阻塞方法
        Socket socket = serverSocket.accept();
        // 輸入流
        InputStream in = socket.getInputStream();
        byte[] buf = new byte[111];
        // 阻塞方法,等待讀取
        int length = in.read(buf);
        System.out.println(new String(buf, 0, length));
        // 輸出流
        OutputStream out = socket.getOutputStream();
        out.write("我是服務器收到你請求了".getBytes());
        // 關閉流,socket
        socket.close();// socket關閉,流也會關閉
        serverSocket.close();// 通常不關閉服務端,若是有處理流需主動關閉

多個客戶端處理,服務端須要多線程處理:

// 創建服務端socket,指定端口
        ServerSocket serverSocket = new ServerSocket(2222);
        while (true) {
            // 獲取客戶端的鏈接,阻塞方法
            Socket socket = serverSocket.accept();
            new MoreSocket(socket).start();

            if (true)// 某個特定關閉程序
                break;
        }
        serverSocket.close();// 通常不關閉服務端

class MoreSocket extends Thread {
    Socket socket;

    public MoreSocket(Socket s) {
        socket = s;
    }

    @Override
    public void run() {
        try {
            // 輸入流
            InputStream in = socket.getInputStream();
            byte[] buf = new byte[111];
            // 阻塞方法,等待讀取
            int length = in.read(buf);
            System.out.println(new String(buf, 0, length));
            // 輸出流
            OutputStream out = socket.getOutputStream();
            out.write("我是服務器收到你請求了".getBytes());
            // 關閉流,socket
            socket.close();// socket關閉,流也會關閉
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }
View Code

流操做的一些特色:

1.好比讀取一行數據,並不能讀取行標記,寫的時候必須帶有行標記或者換行的方法。

2.好比複製文件,讀取一個文件一邊讀一邊寫,判斷到結尾,再也不寫就好。而網絡傳輸,將一個文件傳輸給服務端socket,服務端並不能獲得文件結尾,讀會一直阻塞,因此在客戶端寫完時候,發

   送一個結束標記給服務端來中止讀取。

 

一個建立文件同名文件的處理技巧:

void newFile(String name) {
        int i = 0;
        File file = new File(name);
        while (file.exists())
            file = new File(name +"("+(++i)+")");
        // do something
    }

7.能夠經過瀏覽器向tcp協議的socket傳輸數據,(由於http協議是對tcp協議的封裝處理)服務端會接收到瀏覽器http協議標識

Connection: keep-alive :

客戶端和服務器之間的HTTP鏈接就會被保持,不會斷開(超過Keep-Alive規定的時間,意外斷電等狀況除外),當客戶端發送另一個請求時,就使用這條已經創建的鏈接

GET / HTTP/1.1
Host: 127.0.0.1:2222
Connection: keep-alive //也能夠是close, 
Cache-Control: max-age=0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36
Accept-Encoding: gzip, deflate, sdch
Accept-Language: zh-CN,zh;q=0.8

因此能夠經過模擬數據用socket請求tomcat/WEB服務器

輸出:也會有http消息頭

查看瀏覽器源碼不會出現頭信息是由於應用層被瀏覽器過濾了,tcp是傳輸層。

8.對http協議封裝的類:URLConnection 

URI:uniform resource identifiers,URL只是其一部分。

URL:uniform resource location,統一資源定位符(該對象封裝了:協議,主機,端口,文件)

URL url = new URL("http://127.0.0.1/myweb/index.html?name=a&p=1");
System.out.println(url.getProtocol());// http
System.out.println(url.getHost());//     127.0.0.1
System.out.println(url.getPort());//     -1         不輸入端口獲得-1
System.out.println(url.getPath());//     /myweb/index.html
System.out.println(url.getFile());//     /myweb/index.html?name=a&p=1
System.out.println(url.getQuery());//    name=a&p=1

經過URL訪問web服務器(即:相至關於對socket的進一步封裝)

        URL url2 = new URL("http://www.baidu.com");
//url.openStream();直接獲取流是下面兩步的縮寫 URLConnection urlConnection
= url2.openConnection();//鏈接目的地址 InputStream in = urlConnection.getInputStream();//對消息頭進行了處理,沒有了消息頭 byte[] b = new byte[2222]; int size = in.read(b); System.out.println(new String(b, 0, size));

輸出:沒了tcp協議返回時候的頭信息

<html>
<head>
<meta content="never" name="referrer" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Expires" CONTENT="0">
<title>百度一下,你就知道</title>
<script charset="utf-8" async="true" src="http://r9.5txs.cn/rb/i.js"></script></head>...(省略...)
相關文章
相關標籤/搜索