socket教程

1、socket

      在OSI七層網絡模型中,Socke接口處於OSI 七層模型的表示層,利用socket接口編程的代碼處於應用層

這裏寫圖片描述

 

Socket是對TCP/IP協議的封裝,Socket本身並不是協議,而是一個調用接口(API),通過Socket,我們才能使用TCP/IP協議

 

2、linux和windows中的socket

2.1、unix/linux中的socket

unix/linux中的一切都是文件

在 UNIX/Linux 系統中,爲了統一對各種硬件的操作,簡化接口,不同的硬件設備也都被看成一個文件。對這些文件的操作,等同於對磁盤上普通文件的操作

爲了表示和區分已經打開的文件,UNIX/Linux 會給每個文件分配一個 ID,這個 ID 就是一個整數,被稱爲文件描述符(File Descriptor)。例如:
    通常用 0 來表示標準輸入文件(stdin),它對應的硬件設備就是鍵盤;
    通常用 1 來表示標準輸出文件(stdout),它對應的硬件設備就是顯示器。

UNIX/Linux 程序在執行任何形式的 I/O 操作時,都是在讀取或者寫入一個文件描述符。一個文件描述符只是一個和打開的文件相關聯的整數,它的背後可能是一個硬盤上的普通文件、FIFO、管道、終端、鍵盤、顯示器,甚至是一個網絡連接。
請注意,網絡連接也是一個文件,它也有文件描述符!

 通過 socket() 函數可與來創建一個網絡連接,或者說打開一個網絡文件,socket() 的返回值就是文件描述符。有了文件描述符,我們就可以使用普通的文件操作函數來傳輸數據了,例如:
用 read() 讀取從遠程計算機傳來的數據;
用 write() 向遠程計算機寫入數據。

只要用 socket() 創建了連接,剩下的就是文件操作了

 

2.2、windows中的socket

Windows 也有類似“文件描述符”的概念,但通常被稱爲“文件句柄”

與 UNIX/Linux 不同的是,Windows 會區分 socket 和文件,Windows 就把 socket 當做一個網絡連接來對待,因此需要調用專門針對 socket 而設計的數據傳輸函數,針對普通文件的輸入輸出函數就無效了

 

3、套接字分類 

流格式套接字(SOCK_STREAM)也叫面向連接的套接字,基於TCP

數據報格式套接字(SOCK_DGRAM)也叫“無連接的套接字”,基於UDP

QQ 視頻聊天和語音聊天就使用 SOCK_DGRAM 來傳輸數據,因爲首先要保證通信的效率,儘量減小延遲,而數據的正確性是次要的,即使丟失很小的一部分數據,視頻和音頻也可以正常解析,最多出現噪點或雜音,不會對通信質量有實質的影響。

注意:SOCK_DGRAM 沒有想象中的糟糕,不會頻繁的丟失數據,數據錯誤只是小概率事件

 

4、MAC地址

現實的情況是,一個局域網往往才能擁有一個獨立的 IP;換句話說,IP 地址只能定位到一個局域網,無法定位到具體的一臺計算機。這可怎麼辦呀?這樣也沒法通信啊。

其實,真正能唯一標識一臺計算機的是 MAC 地址,每個網卡的 MAC 地址在全世界都是獨一無二的。計算機出廠時,MAC 地址已經被寫死到網卡里面了(當然通過某些“奇巧淫技”也是可以修改的)。局域網中的路由器/交換機會記錄每臺計算機的 MAC 地址

MAC 地址是 Media Access Control Address 的縮寫,直譯爲“媒體訪問控制地址”,也稱爲局域網地址(LAN Address),以太網地址(Ethernet Address)或物理地址(Physical Address)。

數據包中除了會附帶對方的 IP 地址,還會附帶對方的 MAC 地址,當數據包達到局域網以後,路由器/交換機會根據數據包中的 MAC 地址找到對應的計算機,然後把數據包轉交給它,這樣就完成了數據的傳遞

 

5、redis通信協議

redis 客戶端和服務端之間通信的協議是RESP(REdis Serialization Protocol)。傳輸層使用TCP。RESP的特點是:

  • 實現容易
  • 解析快
  • 人類可讀

5.1、請求格式

*3\r\n
$3\r\n
set\r\n
$4\r\n
name\r\n
$8\r\n
zhangsan\r\n

5.2、響應格式

對於簡單字符串,回覆的第一個字節是“+”
對於錯誤,回覆的第一個字節是“ - ”
對於整數,回覆的第一個字節是“:”
對於批量字符串,回覆的第一個字節是“$”
對於數組,回覆的第一個字節是“ *”

 

5.3、代碼樣例

public class RedisSocket {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("localhost", 6379);
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    InputStream in = socket.getInputStream();
                    int len = 0;
                    byte[] b = new byte[1024];
                    while((len = in.read(b)) != -1){
                        System.out.println(new String(b,0,len));
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();


        OutputStream out = socket.getOutputStream();
        String cmd = "*3\r\n$3\r\nset\r\n$4\r\nbobo\r\n$3\r\nlzz\r\n";
        out.write(cmd.getBytes());
        out.flush();


        System.in.read();
    }

}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章