国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(3)

這篇具有很好參考價(jià)值的文章主要介紹了【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(3)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。

? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。


poll

poll()????????? ?遵循 POSIX.1 - 2008

ppoll()? ? ? ? ?遵循 Linux

1.庫

標(biāo)準(zhǔn) c 庫,libc, -lc

2.頭文件

<poll.h>

3.接口定義

       int poll(struct pollfd *fds, nfds_t nfds, int timeout);
       int ppoll(struct pollfd *fds, nfds_t nfds,
                 const struct timespec *_Nullable tmo_p,
                 const sigset_t *_Nullable sigmask);

4.接口描述

? ? ? ? poll() 和 select() 做的事情差不多,它等待一個(gè)文件描述符集 I/O 就緒。Linux 的 epoll() 也是類似的,只是比 poll() 提供多了一些特性。

? ? ? ? fds 參數(shù)是要監(jiān)控的文件描述符集,是下面結(jié)構(gòu)體的一個(gè)數(shù)組:

           struct pollfd {
               int   fd;         /* file descriptor */
               short events;     /* requested events */
               short revents;    /* returned events */
           };

? ? ? ? 由調(diào)用者指定 fds 的項(xiàng)數(shù)。

? ? ? ? 結(jié)構(gòu)體中 fd 包含了一個(gè)打開的文件描述符,如果它是負(fù)值,那么 events 參數(shù)將被忽略,revents 返回 0。(也就是說?可以將?fd 設(shè)置為其補(bǔ)碼就可以忽略它)。

? ? ? ? events 參數(shù)是一個(gè)輸入?yún)?shù),通過按位掩碼來標(biāo)識(shí)應(yīng)用感興趣的文件描述符上的事件。參數(shù)可以設(shè)置為 0,那么就只能返回 POLLHUP/POLLERR/POLLNVAL 事件。

? ? ? ? revents 是一個(gè)輸出參數(shù),由內(nèi)核填充實(shí)際發(fā)生的事件。這些事件可以是 events 中指定的事件,也可以是? POLLHUP/POLLERR/POLLNVAL 中的一個(gè)。(events 中這三個(gè)事件對(duì)應(yīng)的位并沒有什么意義,只要對(duì)應(yīng)的條件發(fā)生,revents 就會(huì)返回該事件。)

? ? ? ? 如果沒有請(qǐng)求的事件(包括錯(cuò)誤)發(fā)生,那么 poll() 會(huì)一直阻塞,直到有事件發(fā)生。

? ? ? ? timeout 參數(shù)指定了 poll() 等待文件描述符就緒的毫秒數(shù),該調(diào)用會(huì)一直阻塞直到:

  • 文件描述符就緒
  • 調(diào)用被信號(hào)打斷
  • 發(fā)生超時(shí)

? ? ? ? 同樣,timeout 值也會(huì)向上近似到系統(tǒng)時(shí)鐘粒度,由于內(nèi)核調(diào)度延遲阻塞的事件可能會(huì)稍微多一點(diǎn)。如果 timeout 是負(fù)值,表示超時(shí)時(shí)間是無限長(zhǎng)。如果 timeout 設(shè)置為 0,那么 poll() 會(huì)馬上返回,即使沒有任何文件描述符就緒。

? ? ? ? events 和 revents 中各個(gè)位在 poll.h 中定義:

? ? POLLIN

? ? ? ?有數(shù)據(jù)可以讀。

? ? POLLPRI

? ? ? ? 文件描述符上有異常發(fā)生,可能是(1)TCP socket 上有帶外數(shù)據(jù)(2)處于報(bào)文模式的偽終端主機(jī)發(fā)現(xiàn)了從機(jī)狀態(tài)變化(3)cgroup.events 文件被修改了。

? ? ? ? POLLOUT

? ? ? ?當(dāng)前可寫,但是寫大于 socket 或 pipe 中可用空間的數(shù)據(jù)仍然會(huì)導(dǎo)致阻塞(除非設(shè)置了 O_NONBLOCK)。

? ? ? ? POLLRDHUP

? ? ? ? 流 socket 對(duì)端關(guān)閉了連接或者在寫半連接時(shí)關(guān)機(jī)。這個(gè)定義依賴于 _GNU_SOURCE 宏定。

? ? ? ? POLLERR

? ? ? ?發(fā)生錯(cuò)誤。如果文件描述符指向了 pipe 的寫端,而讀端關(guān)閉了,那么也會(huì)返回這個(gè)錯(cuò)誤。

? ? ? ? POLLHUP

? ? ? ? 掛斷。在讀取 pipe 或者流 socket 時(shí),這個(gè)事件只表示對(duì)端關(guān)閉了其通道,后面的數(shù)據(jù)讀取時(shí),在通道中數(shù)據(jù)讀盡后再繼續(xù)讀會(huì)返回?0(EOF)。

? ? ? ? POLLNVAL

? ? ? ? 請(qǐng)求不合法:fd 沒有打開。

? ? ? ? 在使用 _XOPEN_SOURCE 宏編譯時(shí),還會(huì)有以下一些事件,不過也沒有提供太多信息:

? ? ? ? POLLRDNORM

? ? ? ? 等同于 POLLIN。

? ? ? ? POLLRDBAND

? ? ? ? 優(yōu)先帶寬數(shù)據(jù)可以讀(通常在 Linux 上用)

? ? ? ? POLLWRNORM

? ? ? ? 等同于 POLLOUT

? ? ? ? POLLWRBAND

? ? ? ? 可能寫了優(yōu)先數(shù)據(jù)

ppoll()

? ? ? ? ppoll() 和 poll() 的關(guān)系就像 select() 和 pselect() 的關(guān)系一樣,ppoll() 為應(yīng)用提供了等待信號(hào)或者就緒事件的安全方法。

? ? ? ? 除了 timeout 時(shí)間精度上的差異,以下兩段代碼幾乎等效

           ready = ppoll(&fds, nfds, tmo_p, &sigmask);
           sigset_t origmask;
           int timeout;

           timeout = (tmo_p == NULL) ? -1 :
                     (tmo_p->tv_sec * 1000 + tmo_p->tv_nsec / 1000000);
           pthread_sigmask(SIG_SETMASK, &sigmask, &origmask);
           ready = poll(&fds, nfds, timeout);
           pthread_sigmask(SIG_SETMASK, &origmask, NULL);

??????????上面代碼說成幾乎等效而不是等效主要是因?yàn)樨?fù)值的 timeout 會(huì)被 poll() 解釋為一直等待,而 ppoll() 中負(fù)值的 *tmo_p 會(huì)報(bào)錯(cuò)。

? ? ? ? 可以參考 pselect(2) 來看為什么 ppoll 是必要的。

? ? ? ? 如果 sigmask 參數(shù)為 NULL,那么就不會(huì)有任何信號(hào)屏蔽操作,這時(shí)這兩個(gè)接口唯一的區(qū)別就是時(shí)間精度。

? ? ? ? tmo_p 指定了 ppoll() 會(huì)阻塞的時(shí)間上限,它是指向 timespec 結(jié)構(gòu)體的指針,指針為空時(shí),ppoll() 會(huì)一直阻塞。

5.返回值

? ? ? ? 成功時(shí),poll() 返回一個(gè)非負(fù)數(shù)表示 pollfds 中有多少個(gè)文件描述符上有事件發(fā)生,即對(duì)應(yīng)的 revents 有被更新為非 0 值。返回 0 表示沒有任何文件描述符就緒并超時(shí)。

? ? ? ? 發(fā)生錯(cuò)誤時(shí),返回 -1,并設(shè)置errno 來指示錯(cuò)誤類型。

? ? ? ? 錯(cuò)誤值定義如下:

EFAULT fds 指向了進(jìn)程外的地址空間
EINTR 請(qǐng)求事件發(fā)生前,發(fā)生了信號(hào),具體參見 signal(7)
EIVAL nfds 值超出了 RLIMIT_NOFILE 限制
EINVAL ppoll() 中的 *tmo_P 是一個(gè)非法值(負(fù)數(shù))
ENOMEM 沒有足夠內(nèi)存來分配內(nèi)核數(shù)據(jù)結(jié)構(gòu)

一些其他 UNIX 系統(tǒng)上,如果內(nèi)核無法發(fā)分配內(nèi)核資源,poll() 可能會(huì)產(chǎn)生 EAGAIN 類的錯(cuò)誤,而不像 Linux 上的 ENOMEM。POSIX 允許這種行為。所以,一個(gè)可移植的程序需要檢測(cè)該錯(cuò)誤,并重試,就像處理 EINTR 一樣。

一些實(shí)現(xiàn)定義了非標(biāo)準(zhǔn)常量 INFTIM(-1),用作 poll() 的 timeout,但是這個(gè)常量并沒有被被 glibc 提供。

6.注意

? ? ? ?poll() 和 ppoll() 的行為不受 O_NONBLOCK 標(biāo)志影響。

? ? ? ? 對(duì)于一個(gè)文件描述符正在被 poll() 監(jiān)聽卻被另一個(gè)線程關(guān)閉了這種情況的討論,可以參考 select(2)。

7.BUGS

? ? ? ? 可以參考 select(2) 中關(guān)于虛假就緒通知的討論。?

8.代碼實(shí)例

? ? ? ? 該程序會(huì)打開命令行參數(shù)傳進(jìn)來的文件名并監(jiān)聽其 POLLIN 事件,程序會(huì)循環(huán)調(diào)用 poll() 來監(jiān)聽文件描述符,打印已經(jīng)就緒的文件描述符數(shù)。對(duì)于每個(gè)就緒的文件描述符,程序會(huì):

  • 以可讀的格式顯示返回的 revents
  • 如果文件描述符就緒,那么就從中讀一些數(shù)據(jù)出來并打印
  • 如果文件描述符不可讀,但是發(fā)生了一些其他事件(比如 POLLHUP),就關(guān)閉文件描述符

? ? ? ? 假定我們?cè)谝粋€(gè)終端運(yùn)行程序,讓他打開一個(gè) FIFO:

       $ mkfifo myfifo
       $ ./poll_input myfifo

? ? ? ? 在另一個(gè)終端打開 FIFO,并寫入一些數(shù)據(jù),然后關(guān)閉 FIFO:

       $ echo aaaaabbbbbccccc > myfifo

? ? ? ? ? ? ? ? ?我們將在運(yùn)行程序的終端上看到如下信息:

           Opened "myfifo" on fd 3
           About to poll()
           Ready: 1
             fd=3; events: POLLIN POLLHUP
               read 10 bytes: aaaaabbbbb
           About to poll()
           Ready: 1
             fd=3; events: POLLIN POLLHUP
               read 6 bytes: ccccc

           About to poll()
           Ready: 1
             fd=3; events: POLLHUP
               closing fd 3
           All file descriptors closed; bye

? ? ? ? ?從上面我們可以看到 poll() 返回了三次:

  • 第一次返回是 POLLIN,表示文件描述符可讀,另一個(gè)是 POLLHUP 表示文件描述符的另一個(gè)端關(guān)閉了。程序接著讀取了一些可用的輸入數(shù)據(jù)
  • 第二次返回同樣是這兩個(gè)事件,依然消費(fèi)了一些可用數(shù)據(jù)
  • 最后一次返回,poll() 只有 POLLHUP 事件,然后關(guān)閉文件描述符并結(jié)束了程序。
       /* poll_input.c

          Licensed under GNU General Public License v2 or later.
       */
       #include <fcntl.h>
       #include <poll.h>
       #include <stdio.h>
       #include <stdlib.h>
       #include <unistd.h>

       #define errExit(msg)    do { perror(msg); exit(EXIT_FAILURE); \
                               } while (0)

       int
       main(int argc, char *argv[])
       {
           int            ready;
           char           buf[10];
           nfds_t         num_open_fds, nfds;
           ssize_t        s;
           struct pollfd  *pfds;

           if (argc < 2) {
              fprintf(stderr, "Usage: %s file...\n", argv[0]);
              exit(EXIT_FAILURE);
           }

           num_open_fds = nfds = argc - 1;
           pfds = calloc(nfds, sizeof(struct pollfd));
           if (pfds == NULL)
               errExit("malloc");

           /* Open each file on command line, and add it to 'pfds' array. */

           for (nfds_t j = 0; j < nfds; j++) {
               pfds[j].fd = open(argv[j + 1], O_RDONLY);
               if (pfds[j].fd == -1)
                   errExit("open");

               printf("Opened \"%s\" on fd %d\n", argv[j + 1], pfds[j].fd);

               pfds[j].events = POLLIN;
           }

           /* Keep calling poll() as long as at least one file descriptor is
              open. */

           while (num_open_fds > 0) {
               printf("About to poll()\n");
               ready = poll(pfds, nfds, -1);
               if (ready == -1)
                   errExit("poll");

               printf("Ready: %d\n", ready);

               /* Deal with array returned by poll(). */

               for (nfds_t j = 0; j < nfds; j++) {
                   if (pfds[j].revents != 0) {
                       printf("  fd=%d; events: %s%s%s\n", pfds[j].fd,
                              (pfds[j].revents & POLLIN)  ? "POLLIN "  : "",
                              (pfds[j].revents & POLLHUP) ? "POLLHUP " : "",
                              (pfds[j].revents & POLLERR) ? "POLLERR " : "");

                       if (pfds[j].revents & POLLIN) {
                           s = read(pfds[j].fd, buf, sizeof(buf));
                           if (s == -1)
                               errExit("read");
                           printf("    read %zd bytes: %.*s\n",
                                  s, (int) s, buf);
                       } else {                /* POLLERR | POLLHUP */
                           printf("    closing fd %d\n", pfds[j].fd);
                           if (close(pfds[j].fd) == -1)
                               errExit("close");
                           num_open_fds--;
                       }
                   }
               }
           }

           printf("All file descriptors closed; bye\n");
           exit(EXIT_SUCCESS);
       }

下一篇 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(4)???????文章來源地址http://www.zghlxwxcb.cn/news/detail-705963.html

到了這里,關(guān)于【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(3)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(6)

    ?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。 ? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。 recv()????????? ?遵

    2024年02月07日
    瀏覽(22)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(9)

    ?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。 ? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。 續(xù) ?【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)

    2024年02月08日
    瀏覽(34)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(3)

    ?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。 ? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。 poll()????????? ?遵

    2024年02月09日
    瀏覽(25)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(10)

    ?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。 ? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。 ? ? ? ? 這個(gè)是 RFC 7

    2024年02月08日
    瀏覽(27)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程接口 Socket API 解讀(8)

    ?????????Socket 是網(wǎng)絡(luò)協(xié)議棧暴露給編程人員的 API,相比復(fù)雜的計(jì)算機(jī)網(wǎng)絡(luò)協(xié)議,API 對(duì)關(guān)鍵操作和配置數(shù)據(jù)進(jìn)行了抽象,簡(jiǎn)化了程序編程。 ? ? ? ? 本文講述的 socket 內(nèi)容源自 Linux man。本文主要對(duì)各 API 進(jìn)行詳細(xì)介紹,從而更好的理解 socket 編程。 ? ? ? ?本文主要描述

    2024年02月08日
    瀏覽(28)
  • 計(jì)算機(jī)網(wǎng)絡(luò)--網(wǎng)絡(luò)編程(1)

    計(jì)算機(jī)網(wǎng)絡(luò)--網(wǎng)絡(luò)編程(1)

    簡(jiǎn)單認(rèn)識(shí)一下傳輸層中的UDP和TCP: TCP:有鏈接,可靠傳輸,面向字節(jié)流,全雙工 UDP:無連接,不可靠傳輸,面向數(shù)據(jù)報(bào),全雙工 有鏈接類似于打電話,通了就是有鏈接。沒通就一直在等待。 無連接類似于發(fā)短信,只管發(fā),不管到。 可靠傳輸就是保證信息傳輸?shù)目煽啃?。?/p>

    2024年02月11日
    瀏覽(34)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】4 Socket網(wǎng)絡(luò)編程

    【計(jì)算機(jī)網(wǎng)絡(luò)】4 Socket網(wǎng)絡(luò)編程

    目錄 寫在前面的話 概覽 環(huán)境 URL請(qǐng)求程序: 2. 系統(tǒng)時(shí)間查詢 服務(wù)端 T_TCPServer.py代碼 客戶端 T_TCPClient.py代碼 運(yùn)行效果 3. 網(wǎng)絡(luò)文件傳輸 服務(wù)端 TF_TCPServer.py代碼 運(yùn)行效果(后面加了遠(yuǎn)程功能,效果圖暫時(shí)還在本地) 4. 網(wǎng)絡(luò)聊天室 服務(wù)端 UDPServer.py代碼 客戶端 UDPClient.py代碼 運(yùn)

    2024年02月01日
    瀏覽(33)
  • 計(jì)算機(jī)網(wǎng)絡(luò)---網(wǎng)絡(luò)編程套接字(一)

    計(jì)算機(jī)網(wǎng)絡(luò)---網(wǎng)絡(luò)編程套接字(一)

    ? 計(jì)算機(jī)網(wǎng)絡(luò)—網(wǎng)絡(luò)編程套接字之UDP數(shù)據(jù)報(bào)套接字編程 作者介紹: ??作者:偷偷敲代碼的青花瓷????? ??作者的Gitee:代碼倉庫 ??系列文章推薦:計(jì)算機(jī)網(wǎng)絡(luò) ——網(wǎng)絡(luò)原理之初識(shí) ??我和大家一樣都是熱愛編程?,很高興能在此和大家分享知識(shí),希望在分享知識(shí)的同時(shí),能和大

    2023年04月09日
    瀏覽(79)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(一)

    【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(一)

    目錄 1.預(yù)備知識(shí) 1.1.理解源IP地址和目的IP地址 1.2.認(rèn)識(shí)端口號(hào) 1.2.1.理解\\\"端口號(hào)\\\"和\\\"進(jìn)程ID\\\" 1.2.2.理解源端口號(hào)和目的端口號(hào) 1.3.認(rèn)識(shí)TCP/UDP協(xié)議 1.3.1.TCP協(xié)議 1.3.2.UDP協(xié)議 1.4.網(wǎng)絡(luò)字節(jié)序 網(wǎng)絡(luò)字節(jié)序和主機(jī)字節(jié)序的轉(zhuǎn)換 2.socket編程接口 2.1.sockaddr結(jié)構(gòu) struct sockaddr_in 的具體結(jié)構(gòu): 2.

    2024年02月08日
    瀏覽(34)
  • 【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(二)

    【計(jì)算機(jī)網(wǎng)絡(luò)】網(wǎng)絡(luò)編程套接字(二)

    簡(jiǎn)單TCP服務(wù)器實(shí)現(xiàn) 我們將會(huì)使用到的頭文件放在 comm.h 文件中 創(chuàng)建套接字 創(chuàng)建過程和UDP服務(wù)器幾乎完全一樣,除了使用的是TCP服務(wù)器使用的是流式服務(wù)(SOCK_STREAM),UDP使用的是數(shù)據(jù)包服務(wù)(SOCK_DGRAM) 服務(wù)器綁定 綁定的過程和UDP服務(wù)器也是相同的,可以看著復(fù)習(xí)一下 定義好 st

    2024年02月13日
    瀏覽(34)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包