第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

全部開發(fā)者教程

Android 入門教程

菜單類控件
菜單:Menu
并發(fā)編程
多線程

Socket 網(wǎng)絡接口

大家在學習計算機網(wǎng)絡的時候一定學習過 TCP/IP 協(xié)議以及最經(jīng)典的 OSI 七層結構,簡單的回憶一下這 7 層結構:
從下到上依次是:

  • 物理層
  • 數(shù)據(jù)鏈路層
  • 互聯(lián)層
  • 網(wǎng)絡層
  • 會話層
  • 表示層
  • 應用層

osi

TCP/IP 協(xié)議對這 7 層了做一點精簡,變?yōu)榱?4 層結構:

tcp/ip

我們現(xiàn)在的網(wǎng)路通信模型基本上都是按照這個層級來分發(fā)的,當然也包括了 Android 中的網(wǎng)絡模型,簡單回顧一下基礎之后,開始學習今天的網(wǎng)絡接口——Socket。

1. TCP 與 UDP

在模型之下,又衍生出兩種經(jīng)典的傳輸層協(xié)議——TCP 和 UDP,我們分別看看這兩個協(xié)議。

1.1 TCP 協(xié)議

TCP 協(xié)議是傳輸控制協(xié)議是一個面向連接的協(xié)議,所謂的面向連接表示的是通信雙方在傳輸數(shù)據(jù)之前,需要搭建一個專用的通信線路,并且在結束的時候需要將其關閉。在有了這條專用線路作保障之后,就能準確無誤的將數(shù)據(jù)傳遞給對方,所以 TCP 是一種可靠的通信方式,它能夠準確知道對方是否成功接收了消息。

1.2 UDP 協(xié)議

UDP 又叫用戶數(shù)據(jù)包協(xié)議,相對于 TCP,它是一種面向無連接的協(xié)議,也就是通信雙方在交換數(shù)據(jù)之前無需建立一條專用通道,當然在通信結束前也無需釋放通道。這樣一來,通信的效率非常高,但缺點是我們無法確定發(fā)出去的消息對方是否能夠準確收到,所以它是一個輕量不可靠的通信方式。

以上的定義描述了二者主要的差異,更多細致的內(nèi)容可以參考其他資料。

2. Socket 的基礎概念

Socket 翻譯成中文是“套接字”,它是應用層和傳輸層中間的一個抽象中間件,它封裝了底層的 TCP / IP 協(xié)議族,并向上暴露 API 給應用層,從而向上屏蔽底層協(xié)議細節(jié)。 所以 Socket 可以作為底層網(wǎng)絡門面來讓我們不在拘泥于復雜的底層傳輸協(xié)議,而將更多的重心放在自己的功能開發(fā)上。 下圖是 Socket 的一個整體工作原理:

socket

每個 Socket 對象都對應著一個 IP 地址和一個端口號,用來標識互聯(lián)網(wǎng)上的唯一目的地址,然后就可以通過 TCP 或者 UDP 將數(shù)據(jù)發(fā)送給對方。

3. Socket 的工作流程

首先看看 Socket 的工作流程圖:

socketworkflow

3.1 Server 監(jiān)聽端口

首先由服務端初始化 Socket 接口,然后綁定并監(jiān)聽自己的端口號,此時服務端會阻塞式等待客戶端連接。

3.2 Client 連接端口

客戶端可以在需要發(fā)送消息的時候初始化 Socket 接口,設置服務端的 IP 地址和端口號就可以連接到服務器,接著在連接成功之后,雙方就完成了連接的建立。

3.3 數(shù)據(jù)傳遞和連接斷開

在連接建立好之后,客戶端或者服務端雙方就可以開始發(fā)送數(shù)據(jù)了,在數(shù)據(jù)傳輸完畢之后,雙方任一方都可以申請斷開連接,此后通道關閉,數(shù)據(jù)傳輸完成。

4. Socket 的基本用法

  1. 首先創(chuàng)建一個 ServerSocket 對象
public ServerSocket(int port) throws IOException

創(chuàng)建 Socket 服務只需要傳入一個端口號即可。

  1. 阻塞監(jiān)聽端口
public Socket accept() throws IOException

通過調(diào)用accept()方法,server 便會阻塞式的監(jiān)聽第 1 步設置的端口號,等待客戶端連接。

  1. 客戶度創(chuàng)建 Socket 對象
public Socket(String host, int port)  throws UnknownHostException, IOException

和前面說的一樣,創(chuàng)建 Socket 需要兩個必要的參數(shù):

  • **host:**服務端的網(wǎng)絡地址
  • **port:**服務端開放的對應端口號
  1. 獲取輸入輸出流
socket.getInputStream();
socket.getOutputStream();

服務端和客戶端通過這兩個方法分別拿到輸入輸出流,從而向流里面寫消息或者從流里面讀數(shù)據(jù)完成數(shù)據(jù)的發(fā)送和接收。

  1. 斷開連接
    在數(shù)據(jù)傳輸完畢之后,通過close()方法斷開連接,完成本次通信。

5. Socket 網(wǎng)絡通信示例

本節(jié)在電腦上通過 Java 搭建一個 Socket Server,然后手機作為 Client 來連接 Server。這個需要保證手機和電腦在同一個 Wifi 網(wǎng)段下。

5.1 搭建 Server

大家在學習 Android 之前,應該都有學過純 Java 程序,可以通過javac命令來將 java 代碼編譯成字節(jié)碼,然后通過java命令運行,當然也可以在 Android Studio 里面直接運行帶main()方法的 Java 程序。
首先在工程里新建一個 Java Library,注意不是 Android Library。

libsocket

然后創(chuàng)建一個帶main()函數(shù)的類,在里面完成 Socket 的創(chuàng)建和初始化:

package com.emercy.libsocket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;

public class SocketServer {
    public static void main(String[] args) throws IOException {
        // 1. Create ServerSocket
        ServerSocket serverSocket = new ServerSocket(8888);
        // 2. monitoring
        System.out.println("server start listen : " + getIpAddress());

        Socket socket = serverSocket.accept();
        System.out.println("accept");

        // 3. input stream
        InputStream is = socket.getInputStream();
        InputStreamReader reader = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(reader);
        String content;
        StringBuffer sb = new StringBuffer();
        while ((content = br.readLine()) != null) {
            sb.append(content);
        }

        System.out.println("server receiver: " + sb.toString());

        socket.shutdownInput();

        br.close();
        reader.close();
        is.close();

        socket.close();
        serverSocket.close();


        System.out.println("server receiver: ");

    }

    public static String getIpAddress() {
        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            InetAddress ip = null;
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = (NetworkInterface) allNetInterfaces.nextElement();
                if (netInterface.isLoopback() || netInterface.isVirtual() || !netInterface.isUp()) {
                    continue;
                } else {
                    Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                    while (addresses.hasMoreElements()) {
                        ip = addresses.nextElement();
                        if (ip instanceof Inet4Address) {
                            return ip.getHostAddress();
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println("IP地址獲取失敗" + e.toString());
        }
        return "";
    }
}

運行之后,開始等待連接并打印當前設備的 IP 地址,這里要特別注意,有些教程里面會用InetAddress.getLocalHost()這種方式獲取 IP 返回“127.0.0.1”,這個是 local host,在跨設備通信中無法使用。

5.2 Client 連接

接下來編寫 Android 程序,xml 里面只放置一個 Button 用于觸發(fā)連接,這里就不列出來了。點擊 button 之后按照上面的步驟來依次創(chuàng)建 Socket,設置 IP 和 port,接著獲取輸入輸出流即可。
**注意:**網(wǎng)絡請求屬于耗時操作, Android 要求網(wǎng)絡請求必須在子線程中執(zhí)行,所以我們需要在onClick()中 new 一個 thread。


package com.emercy.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //1. Create Client
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Socket socket;
                        try {
                            //1. create socket
                            socket = new Socket("10.64.210.51", 12345);
                            //2. output stream
                            OutputStream os = socket.getOutputStream();
                            //3. Send data
                            os.write("Hello world".getBytes());
                            System.out.println("send message");
                            os.flush();

                            socket.shutdownOutput();

                            os.close();
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }).start();
            }
        });
    }
}

首先運行 Server,接著打開 App,點擊“連接”Button 就可以和 Server 通信了。

6. 小結

本節(jié)學習了一個底層的網(wǎng)絡接口——Socket,它內(nèi)部實現(xiàn)了計算機網(wǎng)絡中最基礎的協(xié)議和模型,可以讓我們不再關心那些繁瑣復雜的協(xié)議規(guī)則,從而輕松的將數(shù)據(jù)傳輸出去。首先給大家回顧了 IOS 和 TCP / IP 的幾層模型,然后工作在傳輸層的兩個重要通信協(xié)議 TCP / UDP,接著按照步驟來分別創(chuàng)建 SocketServer 和 Socket,通過 InputStream 和 OutputStream 進行通信。