自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Netty學(xué)習(xí)基礎(chǔ):BIO、NIO、AIO

開(kāi)發(fā) 架構(gòu)
Netty是一個(gè)提供異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用以快速開(kāi)發(fā)高性能、高可靠的網(wǎng)絡(luò)服務(wù)器和客戶(hù)端程序。

其實(shí)我的重點(diǎn)呢,是來(lái)和大家一起學(xué)習(xí)接下來(lái)的Netty篇。

然而嘞,這個(gè)Netty又不太合適直接講,為啥呢,我們學(xué)習(xí)一門(mén)技術(shù)必須知道這門(mén)技術(shù)的由來(lái)的初衷是啥,對(duì)吧。

先來(lái)給大家簡(jiǎn)單的介紹一下Netty是什么

Netty是一個(gè)提供異步事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架,用以快速開(kāi)發(fā)高性能、高可靠的網(wǎng)絡(luò)服務(wù)器和客戶(hù)端程序。

Netty簡(jiǎn)化了網(wǎng)絡(luò)程序的開(kāi)發(fā),屬于BIO、NIO、AIO的演變中的產(chǎn)物,屬于一種NIO框架。

在我們平時(shí)使用的很多中間件中,很多底層通信都是采用的Netty,比如rocketmq、dubbo,這些我們最常見(jiàn)的底層通信都是用的netty,足以可見(jiàn)這個(gè)的性能是多么的優(yōu)秀了。

ok,接下來(lái)再來(lái)理解一下同步、異步、阻塞、非阻塞這四個(gè)概念。

從簡(jiǎn)單的開(kāi)始,我們以經(jīng)典的讀取文件的模型舉例。(對(duì)操作系統(tǒng)而言,所有的輸入輸出設(shè)備都被抽象成文件。)

在發(fā)起讀取文件的請(qǐng)求時(shí),應(yīng)用層會(huì)調(diào)用系統(tǒng)內(nèi)核的I/O接口。

阻塞和非阻塞

如果應(yīng)用層調(diào)用的是阻塞型I/O,那么在調(diào)用之后,應(yīng)用層即刻被掛起,一處于等待數(shù)據(jù)返回的狀態(tài),直到系統(tǒng)內(nèi)核從磁盤(pán)讀取完數(shù)據(jù)并返回給應(yīng)用層,應(yīng)用層才用獲得的數(shù)據(jù)進(jìn)行接下來(lái)的其他操作。

如果應(yīng)用層調(diào)用的是非阻塞I/O,那么調(diào)用后,系統(tǒng)內(nèi)核會(huì)立即返回(雖然還沒(méi)有文件內(nèi)容的數(shù)據(jù)),應(yīng)用層并不會(huì)被掛起,它可以做其他任意它想做的操作。(至于文件內(nèi)容數(shù)據(jù)如何返回給應(yīng)用層,這已經(jīng)超出了阻塞和非阻塞的辨別范疇。)

這便是(脫離同步和異步來(lái)說(shuō)之后)阻塞和非阻塞的區(qū)別??偨Y(jié)來(lái)說(shuō),是否是阻塞還是非阻塞,關(guān)注的是接口調(diào)用(發(fā)出請(qǐng)求)后等待數(shù)據(jù)返回時(shí)的狀態(tài)。被掛起無(wú)法執(zhí)行其他操作的則是阻塞型的,可以被立即「抽離」去完成其他「任務(wù)」的則是非阻塞型的。

同步和異步

阻塞和非阻塞解決了應(yīng)用層等待數(shù)據(jù)返回時(shí)的狀態(tài)問(wèn)題,那系統(tǒng)內(nèi)核獲取到的數(shù)據(jù)到底如何返回給應(yīng)用層呢?這里不同類(lèi)型的操作便體現(xiàn)的是同步和異步的區(qū)別。

對(duì)于同步型的調(diào)用,應(yīng)用層需要自己去向系統(tǒng)內(nèi)核問(wèn)詢(xún),如果數(shù)據(jù)還未讀取完畢,那此時(shí)讀取文件的任務(wù)還未完成,應(yīng)用層根據(jù)其阻塞和非阻塞的劃分,或掛起或去做其他事情(所以同步和異步并不決定其等待數(shù)據(jù)返回時(shí)的狀態(tài));如果數(shù)據(jù)已經(jīng)讀取完畢,那此時(shí)系統(tǒng)內(nèi)核將數(shù)據(jù)返回給應(yīng)用層,應(yīng)用層即可以用取得的數(shù)據(jù)做其他相關(guān)的事情。

而對(duì)于異步型的調(diào)用,應(yīng)用層無(wú)需主動(dòng)向系統(tǒng)內(nèi)核問(wèn)詢(xún),在系統(tǒng)內(nèi)核讀取完文件數(shù)據(jù)之后,會(huì)主動(dòng)通知應(yīng)用層數(shù)據(jù)已經(jīng)讀取完畢,此時(shí)應(yīng)用層即可以接收系統(tǒng)內(nèi)核返回過(guò)來(lái)的數(shù)據(jù),再做其他事情。

這便是(脫離阻塞和非阻塞來(lái)說(shuō)之后)同步和異步的區(qū)別。也就是說(shuō),是否是同步還是異步,關(guān)注的是任務(wù)完成時(shí)消息通知的方式。由調(diào)用方盲目主動(dòng)問(wèn)詢(xún)的方式是同步調(diào)用,由被調(diào)用方主動(dòng)通知調(diào)用方任務(wù)已完成的方式是異步調(diào)用。

上面這幾個(gè)概念大家一定要搞懂,這是基礎(chǔ),必須好好理解上面這些,才能真正理解netty的出處,這也是面試常被問(wèn)到的點(diǎn)之一。

總結(jié)一下

阻塞和非阻塞,關(guān)注的是發(fā)起請(qǐng)求之后等待數(shù)據(jù)返回時(shí)的狀態(tài),被掛起無(wú)法執(zhí)行其他操作的是阻塞型的,可以立即去進(jìn)行其他作業(yè)的是非阻塞型的。

同步和異步,關(guān)注的是任務(wù)完成時(shí)的消息通知的方式,由調(diào)用方主動(dòng)去詢(xún)問(wèn)的方式屬于同步調(diào)用,而被調(diào)用方主動(dòng)通知調(diào)用方該任務(wù)已完成的方式屬于異步調(diào)用。

這個(gè)在網(wǎng)上最常見(jiàn)的一個(gè)例子就是燒水的例子了,我也繼續(xù)給大家啰嗦一下咯。

老王燒水,老王把水放在爐子上,在這里干等著,啥也沒(méi)有去做,并且需要隨時(shí)看著水是否開(kāi)了,這叫阻塞同步,阻塞是因?yàn)槔贤跎兑膊荒苋プ?,同步是因?yàn)樗_(kāi)他得自己看著。

老王后來(lái)學(xué)精了,不在這里傻等著了,把水放在爐子上之后,然后就去開(kāi)了一把緊張又刺激的lol手游,這叫非阻塞同步,非阻塞是因?yàn)槔贤踉诘人陂g自己打游戲了,同步是因?yàn)樗_(kāi)他還是得自己看著。

后來(lái),老王覺(jué)得自己看著水太麻煩了,于是買(mǎi)了個(gè)升級(jí)版的水壺,牛了啊,這個(gè)水壺把水煮開(kāi)了之后,會(huì)吹哨,哎。

老王不需要每隔幾分鐘就去看一眼水是否開(kāi)了,只需要聽(tīng)這個(gè)哨聲即可,做水期間可以打游戲,并且水開(kāi)了還會(huì)主動(dòng)通知老王,這就是異步非阻塞,非阻塞就是因?yàn)槔贤蹩梢匀ネ嬗螒?,異步就是水壺的那個(gè)哨子。

這下大家應(yīng)該很好理解了吧!

接下來(lái)繼續(xù)看BIO、NIO、AIO

Socket 網(wǎng)絡(luò)通信過(guò)程簡(jiǎn)單來(lái)說(shuō)分為下面 4 步:

  1. 建立服務(wù)端并且監(jiān)聽(tīng)客戶(hù)端請(qǐng)求。
  2. 客戶(hù)端請(qǐng)求,服務(wù)端和客戶(hù)端建立連接。
  3. 兩端之間可以傳遞數(shù)據(jù)。
  4. 關(guān)閉資源。

傳統(tǒng)的阻塞式通信BIO流程

BIO就是屬于最傳統(tǒng)的一種阻塞同步的通信方式,也是屬于最簡(jiǎn)單的一種,使用起來(lái)比較方便,但是處理并發(fā)能力低,通信比較耗時(shí)。

服務(wù)器會(huì)通過(guò)一個(gè)線(xiàn)程負(fù)責(zé)監(jiān)聽(tīng)客戶(hù)端請(qǐng)求和為每一個(gè)客戶(hù)端創(chuàng)建一個(gè)新的線(xiàn)程進(jìn)行鏈路的處理,屬于一種典型的請(qǐng)求應(yīng)答模式,若客戶(hù)端數(shù)量增加,則需要頻繁的創(chuàng)建和銷(xiāo)毀線(xiàn)程,會(huì)給服務(wù)器增加很大的壓力。

服務(wù)器提供IP地址和監(jiān)聽(tīng)的端口,客戶(hù)端通過(guò)TCP的三次握手和服務(wù)器建立連接通信,連接成功之后,雙方進(jìn)行通過(guò),之后通過(guò)四次揮手進(jìn)行斷開(kāi)連接。

即使用線(xiàn)程池的方式來(lái)改進(jìn)新增加線(xiàn)程,這也是屬于一種偽異步IO,這樣實(shí)現(xiàn)能夠?yàn)樯贁?shù)的客戶(hù)端提供服務(wù),如果客戶(hù)端并發(fā)量足夠多,還是會(huì)因?yàn)榫€(xiàn)程池滿(mǎn)導(dǎo)致OOM的問(wèn)題。

給大家看一個(gè)簡(jiǎn)單的Demon

public class SocketServer {
public static void main(String[] args) throws IOException {
SocketServer socketServer = new SocketServer();
socketServer.start(9000);
}
public void start(int port) {
//1.創(chuàng)建 ServerSocket 對(duì)象并且綁定一個(gè)端口
try (ServerSocket server = new ServerSocket(port);) {
System.out.println("server start");
Socket socket;
//2.通過(guò) accept()方法監(jiān)聽(tīng)客戶(hù)端請(qǐng)求, 這個(gè)方法會(huì)一直阻塞到有一個(gè)連接建立
while ((socket = server.accept()) != null) {
System.out.println("client connected");
try (ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream())) {
//3.通過(guò)輸入流讀取客戶(hù)端發(fā)送的請(qǐng)求信息
String message = (String) objectInputStream.readObject();
System.out.println("server receive message:" + message);
//4.通過(guò)輸出流向客戶(hù)端發(fā)送響應(yīng)信息
objectOutputStream.writeObject(message);
objectOutputStream.flush();
} catch (IOException | ClassNotFoundException e) {
System.out.println("occur exception:");
}
}
} catch (IOException e) {
System.out.println("occur IOException:");
}
}
}

這是服務(wù)端的代碼:

public class Client {
public Object send(String message, String host, int port) {
//1. 創(chuàng)建Socket對(duì)象并且指定服務(wù)器的地址和端口號(hào)
try (Socket socket = new Socket(host, port)) {
ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
//2.通過(guò)輸出流向服務(wù)器端發(fā)送請(qǐng)求信息
objectOutputStream.writeObject(message);
//3.通過(guò)輸入流獲取服務(wù)器響應(yīng)的信息
ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());
return objectInputStream.readObject();
} catch (ClassNotFoundException | IOException e) {
System.out.println("occur exception:");
}
return null;
}
public static void main(String[] args) {
Client helloClient = new Client();
helloClient.send("content from client", "127.0.0.1", 9000);
System.out.println("發(fā)送數(shù)據(jù)成功");
}
}

這是客戶(hù)端的代碼,我們接下來(lái)先運(yùn)行服務(wù)器,再運(yùn)行客戶(hù)端,看效果。

。

服務(wù)器啟動(dòng)之后,便會(huì)一直阻塞在這里,等待客戶(hù)端的連接處理。

接著我們啟動(dòng)客戶(hù)端,然后看到發(fā)送數(shù)據(jù)成功,此時(shí)我們?cè)偾袚Q到服務(wù)器的控制臺(tái),看下效果。

我們也可以通過(guò)命令行直接執(zhí)行telnet localhost 9000去連接服務(wù)端,效果如下:

從上面例子看出的問(wèn)題

我們看到服務(wù)器和客戶(hù)端成功的進(jìn)行通信了,也就是這段服務(wù)器的代碼只能同時(shí)為一個(gè)客戶(hù)端服務(wù),當(dāng)然有改進(jìn)方法,我們監(jiān)聽(tīng)到連接之后,就立刻new Thread().start()創(chuàng)建一個(gè)線(xiàn)程用于這個(gè)客戶(hù)端接下來(lái)的處理。

這也就意味著,每一個(gè)客戶(hù)端都要建立一個(gè)線(xiàn)程為其處理,如果客戶(hù)端數(shù)量很多,或者說(shuō)客戶(hù)端處理很慢,那就很糟糕了。

我們從線(xiàn)程文章中也介紹過(guò)線(xiàn)程是一個(gè)很寶貴的資源,我們需要合理的利用這些資源,需要根據(jù)機(jī)器的性能去合理的控制線(xiàn)程的數(shù)量。

即使線(xiàn)程池可以?xún)?yōu)化上面的例子,讓線(xiàn)程創(chuàng)建和銷(xiāo)毀的成本降低,我們也可以執(zhí)行線(xiàn)程池的最大數(shù)量,控制線(xiàn)程資源的使用,但是,即使如何改進(jìn),我們并沒(méi)有從根本上解決這個(gè)問(wèn)題,根本上還是屬于BIO,也就是同步阻塞IO的模式。

NIO

同步非阻塞模型,在JDK1.4中引入了NIO的框架,NIO 中的 N 可以理解為 Non-blocking,NIO是面向緩沖Buffer的,基于通道Channel的操作。

NIO提供了和傳統(tǒng)BIO模型中的ServerSocket和Socket相對(duì)應(yīng)的ServerSocketChannel和SocketChannel兩種不同的套接字通道,對(duì)應(yīng)服務(wù)端和客戶(hù)端。

兩種通道都支持阻塞和非阻塞的模式。

阻塞模式一般不會(huì)被使用,既然使用了阻塞,那就意味著使用起來(lái)就像上面的BIO一樣了,性能和可靠性都不是很好。

非阻塞模式,對(duì)于高負(fù)載和高并發(fā)的網(wǎng)絡(luò)應(yīng)用是很友好的,后續(xù)我們要說(shuō)的Netty就是基于這個(gè)改進(jìn)的。

NIO 相對(duì)于BIO來(lái)說(shuō)一大進(jìn)步。客戶(hù)端和服務(wù)器之間通過(guò)Channel通信。NIO可以在Channel進(jìn)行讀寫(xiě)操作。這些Channel都會(huì)被注冊(cè)在Selector多路復(fù)用器上。Selector通過(guò)一個(gè)線(xiàn)程不停的輪詢(xún)這些Channel。找出已經(jīng)準(zhǔn)備就緒的Channel執(zhí)行IO操作。

NIO 通過(guò)一個(gè)線(xiàn)程輪詢(xún),實(shí)現(xiàn)千萬(wàn)個(gè)客戶(hù)端的請(qǐng)求,這就是非阻塞NIO的特點(diǎn)。

NIO核心組件

Channel:和流不同,通道是雙向的。NIO可以通過(guò)Channel進(jìn)行數(shù)據(jù)的讀,寫(xiě)和同時(shí)讀寫(xiě)操作。通道分為兩大類(lèi):一類(lèi)是網(wǎng)絡(luò)讀寫(xiě)(SelectableChannel),一類(lèi)是用于文件操作(FileChannel),我們使用的SocketChannel和ServerSocketChannel都是SelectableChannel的子類(lèi)。

Buffer:它是NIO與BIO的一個(gè)重要區(qū)別。BIO是將數(shù)據(jù)直接寫(xiě)入或讀取到Stream對(duì)象中。而NIO的數(shù)據(jù)操作都是在緩沖區(qū)中進(jìn)行的。緩沖區(qū)實(shí)際上是一個(gè)數(shù)組。

Selector和Selection Key:多路復(fù)用器提供選擇已經(jīng)就緒的任務(wù)的能力。就是Selector會(huì)不斷地輪詢(xún)注冊(cè)在其上的通道(Channel),如果某個(gè)通道處于就緒狀態(tài),會(huì)被Selector輪詢(xún)出來(lái),然后通過(guò)SelectionKey可以取得就緒的Channel集合,從而進(jìn)行后續(xù)的IO操作。服務(wù)器端只要提供一個(gè)線(xiàn)程負(fù)責(zé)Selector的輪詢(xún),就可以接入成千上萬(wàn)個(gè)客戶(hù)端。

接下來(lái)我們看使用的例子:

public class NioServer {
static List<SocketChannel> channelList = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
serverSocketChannel.socket().bind(new InetSocketAddress(9000));
//設(shè)置serverSocketChannel為非阻塞
serverSocketChannel.configureBlocking(false);
System.out.println("服務(wù)器啟動(dòng)成功");
while (true){
//非阻塞模式的accept不會(huì)阻塞,否則會(huì)阻塞
//NIO的非阻塞是由操作系統(tǒng)實(shí)現(xiàn)的,底層調(diào)用了Linux內(nèi)核的accept函數(shù)
SocketChannel socketChannel = serverSocketChannel.accept();
if(socketChannel != null){ //此時(shí)有客戶(hù)端連接
System.out.println("有客戶(hù)端連接");
socketChannel.configureBlocking(false);
channelList.add(socketChannel);
}
//遍歷
Iterator<SocketChannel> iterator = channelList.iterator();
while (iterator.hasNext()){
SocketChannel channel = iterator.next();
ByteBuffer byteBuffer = ByteBuffer.allocate(128);
int read = channel.read(byteBuffer);
if(read > 0){
System.out.println("接收到消息:" + new String(byteBuffer.array()));
}else if(read == -1){
iterator.remove();
System.out.println("客戶(hù)端斷開(kāi)連接");
}
}
}
}
}

這里我們只寫(xiě)了服務(wù)端的代碼,客戶(hù)端就通過(guò)telnet來(lái)模擬就行了。

我們用debug的模式看下服務(wù)端。

啟動(dòng)成功之后,發(fā)現(xiàn)NIO模式下竟然沒(méi)有在accept函數(shù)這里阻塞,而是直接執(zhí)行過(guò)去了。

NIO優(yōu)點(diǎn)

NIO最大的優(yōu)點(diǎn),就是引入了IO多路復(fù)用機(jī)制,使得一個(gè)服務(wù)器可以同時(shí)為大量的客戶(hù)端提供服務(wù)的同時(shí),效率也不會(huì)低,而這個(gè)IO多路復(fù)用這里,經(jīng)常遇到的一個(gè)面試題就是select、poll、epoll的區(qū)別,這個(gè)我會(huì)單獨(dú)開(kāi)一篇給大家說(shuō)清楚,這一篇放不下了。

NIO存在的問(wèn)題

NIO跨平臺(tái)和兼容性問(wèn)題

使用NIO的時(shí)候需要考慮Linux平臺(tái)和Windows平臺(tái)的兼容性問(wèn)題,如果該程序運(yùn)行在多個(gè)平臺(tái),則需要考慮測(cè)試多個(gè)平臺(tái)。

NIO2看起來(lái)很理想,但是NIO2只支持Jdk1.7+,若你的程序在Java1.6上運(yùn)行,則無(wú)法使用NIO2。另外,Java7的NIO2中沒(méi)有提供DatagramSocket的支持,所以NIO2只支持TCP程序,不支持UDP程序。

NIO對(duì)緩沖區(qū)的聚合和分散操作可能會(huì)導(dǎo)致內(nèi)存泄露

很多Channel的實(shí)現(xiàn)支持Gather和Scatter。這個(gè)功能允許從從多個(gè)ByteBuffer中讀入或?qū)懭?,這樣做可以有更好的性能。

例如,你可能希望header在一個(gè)ByteBuffer中,而body在另外的ByteBuffer中。

下圖顯示的是Scatter(分散),將ScatteringByteBuffer中的數(shù)據(jù)分散讀取到多個(gè)ByteBuffer中:

下圖顯示的是Gather(聚合),將多個(gè)ByteBuffer的數(shù)據(jù)寫(xiě)入到GatheringByteChannel:

可惜Gather/Scatter功能會(huì)導(dǎo)致內(nèi)存泄露,知道Java7才解決內(nèi)存泄露問(wèn)題。使用這個(gè)功能必須小心編碼和Java版本。

Squashing the famous epoll bug(壓碎著名的epoll bug)

著名的epoll-bug也可能會(huì)導(dǎo)致無(wú)效的狀態(tài)選擇和100%的CPU利用率。要解決epoll-bug的唯一方法是回收舊的選擇器,將先前注冊(cè)的通道實(shí)例轉(zhuǎn)移到新創(chuàng)建的選擇器上。

不是十分的清楚這里,感興趣的可以去更深的了解下這里。

還有一個(gè)很真實(shí)貼切的問(wèn)題,就是這個(gè)對(duì)于開(kāi)發(fā)者來(lái)說(shuō)太不友好了,開(kāi)發(fā)成本和維護(hù)成本都比較高。

AIO

AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改進(jìn)版 NIO 2,它是異步非阻塞的IO模型。

異步 IO 是基于事件和回調(diào)機(jī)制實(shí)現(xiàn)的,也就是應(yīng)用操作之后會(huì)直接返回,不會(huì)堵塞在那里,當(dāng)后臺(tái)處理完成,操作系統(tǒng)會(huì)通知相應(yīng)的線(xiàn)程進(jìn)行后續(xù)的操作。

AIO 是異步IO的縮寫(xiě),雖然 NIO 在網(wǎng)絡(luò)操作中,提供了非阻塞的方法,但是 NIO 的 IO 行為還是同步的。對(duì)于 NIO 來(lái)說(shuō),我們的業(yè)務(wù)線(xiàn)程是在 IO 操作準(zhǔn)備好時(shí),得到通知,接著就由這個(gè)線(xiàn)程自行進(jìn)行 IO 操作,IO操作本身是同步的。

AIO 并沒(méi)有采用NIO的多路復(fù)用器,而是使用異步通道的概念。其read,write方法的返回類(lèi)型都是Future對(duì)象。

而Future模型是異步的,其核心思想是:去主函數(shù)等待時(shí)間。AIO模型中通過(guò)AsynchronousSocketChannel和AsynchronousServerSocketChannel完成套接字通道的實(shí)現(xiàn)。非阻塞,異步。

責(zé)任編輯:姜華 來(lái)源: 左耳君
相關(guān)推薦

2020-10-10 19:37:27

BIO 、NIO 、A

2020-04-16 15:20:43

PHP前端BIO

2020-10-14 08:50:38

搞懂 Netty 線(xiàn)程

2019-10-18 08:22:43

BIONIOAIO

2023-07-11 08:40:02

IO模型后臺(tái)

2021-08-12 18:48:31

響應(yīng)式編程Bio

2021-06-11 17:26:06

代碼Java網(wǎng)絡(luò)編程

2023-06-26 07:39:10

2021-03-04 08:34:55

同步阻塞非阻塞

2011-03-31 10:41:49

BIONIOIO

2019-12-10 09:20:30

NettyBIO開(kāi)發(fā)

2011-12-15 11:39:25

JavaNIO

2022-12-08 09:10:11

I/O模型Java

2019-05-05 08:50:42

阻塞非阻塞BIO

2018-09-19 14:53:02

NIOBIO運(yùn)行

2023-03-07 08:00:12

netpollGo

2021-12-27 10:20:46

JavaNetty網(wǎng)絡(luò)

2019-04-24 23:49:57

宜人貸蜂巢API網(wǎng)關(guān)Netty

2024-11-06 16:38:51

IO網(wǎng)絡(luò)

2023-03-31 07:49:51

syscall庫(kù)Echo Serve
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)