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

全部開發(fā)者教程

Android 入門教程

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

Socket 網(wǎng)絡(luò)接口

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

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

osi

TCP/IP 協(xié)議對(duì)這 7 層了做一點(diǎn)精簡(jiǎn),變?yōu)榱?4 層結(jié)構(gòu):

tcp/ip

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

1. TCP 與 UDP

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

1.1 TCP 協(xié)議

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

1.2 UDP 協(xié)議

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

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

2. Socket 的基礎(chǔ)概念

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

socket

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

3. Socket 的工作流程

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

socketworkflow

3.1 Server 監(jiān)聽端口

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

3.2 Client 連接端口

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

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

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

4. Socket 的基本用法

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

創(chuàng)建 Socket 服務(wù)只需要傳入一個(gè)端口號(hào)即可。

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

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

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

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

  • **host:**服務(wù)端的網(wǎng)絡(luò)地址
  • **port:**服務(wù)端開放的對(duì)應(yīng)端口號(hào)
  1. 獲取輸入輸出流
socket.getInputStream();
socket.getOutputStream();

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

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

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

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

5.1 搭建 Server

大家在學(xué)習(xí) Android 之前,應(yīng)該都有學(xué)過(guò)純 Java 程序,可以通過(guò)javac命令來(lái)將 java 代碼編譯成字節(jié)碼,然后通過(guò)java命令運(yùn)行,當(dāng)然也可以在 Android Studio 里面直接運(yùn)行帶main()方法的 Java 程序。
首先在工程里新建一個(gè) Java Library,注意不是 Android Library。

libsocket

然后創(chuàng)建一個(gè)帶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 "";
    }
}

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

5.2 Client 連接

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

首先運(yùn)行 Server,接著打開 App,點(diǎn)擊“連接”Button 就可以和 Server 通信了。

6. 小結(jié)

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