精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

OpenHarmony TCP 通信編程實戰(zhàn)

系統(tǒng) OpenHarmony
本文旨在探討TCP(Transmission Control Protocol,傳輸控制協(xié)議)通訊的相關(guān)知識。通過本文,您將了解TCP協(xié)議的工作原理,以及如何運(yùn)用這一協(xié)議進(jìn)行通訊程序設(shè)計與實現(xiàn)。

想了解更多關(guān)于開源的內(nèi)容,請訪問:

51CTO 鴻蒙開發(fā)者社區(qū)

https://ost.51cto.com

前言

本人是一名大一學(xué)生,有幸被選拔進(jìn)了深圳技術(shù)大學(xué)第一屆開源鴻蒙菁英班,并在暑期培訓(xùn)進(jìn)行線上分享,故將講解的內(nèi)容也制作成帖子發(fā)上來作為學(xué)習(xí)筆記。在準(zhǔn)備分享的過程中,我基于學(xué)長們的先前成果,結(jié)合開源鴻蒙源碼的最新版本進(jìn)行了相應(yīng)的調(diào)整和優(yōu)化,幫助大家更好地理解和應(yīng)用開源鴻蒙技術(shù)。本文旨在探討TCP(Transmission Control Protocol,傳輸控制協(xié)議)通訊的相關(guān)知識。通過本文,您將了解TCP協(xié)議的工作原理,以及如何運(yùn)用這一協(xié)議進(jìn)行通訊程序設(shè)計與實現(xiàn)。

環(huán)境

  • OpenHarmony - 4.0 源碼
  • 九聯(lián) unionpi_whale 開發(fā)板

一、TCP 通信介紹

1.概念

傳輸控制協(xié)議(TCP,Transmission Control Protocol)是為了在不可靠的互聯(lián)網(wǎng)絡(luò)上提供可靠的端到端字節(jié)流而專門設(shè)計的一個傳輸協(xié)議。

2.特性

  • OpenHarmony是一個分布式操作系統(tǒng),它允許設(shè)備之間相互通信和協(xié)作。TCP是一種可靠的通信協(xié)議,適用于跨網(wǎng)絡(luò)的設(shè)備間通信。通過實現(xiàn)TCP通信,設(shè)備可以安全、可靠地進(jìn)行數(shù)據(jù)傳輸,實現(xiàn)各種協(xié)作功能。
  • 廣泛的支持:TCP是互聯(lián)網(wǎng)上使用最廣泛的通信協(xié)議之一,幾乎所有的網(wǎng)絡(luò)設(shè)備和操作系統(tǒng)都支持TCP協(xié)議。這意味著使用TCP作為通信協(xié)議可以提高OpenHarmony與其他設(shè)備和系統(tǒng)的兼容性,降低了集成和交互的復(fù)雜性。
  • 成熟的實現(xiàn)和開發(fā)工具:TCP協(xié)議的實現(xiàn)和開發(fā)工具已經(jīng)非常成熟,有許多可用的庫和工具可以用于快速開發(fā)和部署TCP通信功能。這可以節(jié)省開發(fā)時間和資源,并且降低了開發(fā)過程中的風(fēng)險。
  • 支持面向連接的通信模式:TCP是一種面向連接的通信協(xié)議,它建立了可靠的雙向通信通道,適合于需要長時間持續(xù)通信的場景,如客戶端和服務(wù)器之間的通信。這種連接導(dǎo)向的通信模式可以滿足許多應(yīng)用場景的需求,包括實時數(shù)據(jù)傳輸、遠(yuǎn)程控制等。
  • 通用性:TCP協(xié)議是傳輸層協(xié)議,與網(wǎng)絡(luò)類型無關(guān),因此它可以在各種類型的網(wǎng)絡(luò)中使用,包括有線網(wǎng)絡(luò)(如以太網(wǎng))和無線網(wǎng)絡(luò)(如Wi-Fi、蜂窩網(wǎng)絡(luò))。

3.兩個重要概念:客戶端與服務(wù)端

  • 服務(wù)器被動連接,客戶端主動連接:在TCP連接中,服務(wù)器通常處于被動狀態(tài),等待客戶端的連接請求。而客戶端則處于主動狀態(tài),負(fù)責(zé)發(fā)起連接請求。一旦連接建立成功,雙方就可以進(jìn)行數(shù)據(jù)傳輸。

4.指令認(rèn)識

  • 以下是幾個網(wǎng)絡(luò)調(diào)試常用的指令:
ifconfig		# 用于Linux和OpenHarmony,常用于查看IP
ipconfig		# 用于Windows,常用于查看IP
ping <IP>		# 測試網(wǎng)絡(luò)連通性

5.本節(jié)課使用工具 – NetAssist

  • 一個網(wǎng)絡(luò)調(diào)試工具:下載鏈接

二、Socket 編程(套接字編程)

1.socket()

socket() 函數(shù)是用于創(chuàng)建一個新的套接字(socket)的系統(tǒng)調(diào)用函數(shù)。套接字是一種通信機(jī)制,允許進(jìn)程通過網(wǎng)絡(luò)進(jìn)行通信。在網(wǎng)絡(luò)編程中,socket() 函數(shù)是一種創(chuàng)建套接字的標(biāo)準(zhǔn)方法,它通常在客戶端和服務(wù)器端代碼中都會用到。

  • 函數(shù)原型:int socket(int domain, int type, int protocol);
  • domain:指定套接字的地址族(Address Family),常見的包括:
  • AF_INET:IPv4地址族
  • AF_INET6:IPv6地址族
  • AF_UNIX:UNIX本地域套接字
  • type:指定套接字的類型,常見的包括:
  • SOCK_STREAM:流套接字,用于面向連接的可靠數(shù)據(jù)傳輸,常用于TCP通信。
  • SOCK_DGRAM:數(shù)據(jù)報套接字,用于無連接的不可靠數(shù)據(jù)傳輸,常用于UDP通信。
  • protocol:指定協(xié)議,通常為0,表示使用默認(rèn)協(xié)議。

2.close()

  • close()函數(shù)用于關(guān)閉一個已經(jīng)建立的TCP連接。關(guān)閉連接的目的是釋放資源并告知對方連接的結(jié)束。
  • 函數(shù)原型:close(int fd)
  • fd:表示待綁定的套接字的文件描述符。

3.sockaddr_in

  • sockaddr_in 結(jié)構(gòu)體通常在網(wǎng)絡(luò)編程中用于指定套接字的地址信息。
  • 包含在頭文件include <netinet/in.h>中
  • 結(jié)構(gòu)體成員:.
struct sockaddr_in{
	sa_family_t sin_family; /* 指定地址族,即網(wǎng)絡(luò)通信所使用的協(xié)議類型。*/
	in_port_t sin_port; /* 表示端口號*/
	struct in_addr sin_addr; /* 通配地址*/
	unint8_t sin_zero[8]; /* 指定套接字的通信地址,從而確立通信的目標(biāo)。通常未使用
};
  • sin_addr 用于表示 IPv4 地址,可以是特定的 IP 地址,也可以是通配地址INADDR_ANY;
  • sin_port 則表示端口號,用于標(biāo)識一個網(wǎng)絡(luò)服務(wù)。
  • sin_family用于指定地址族,即網(wǎng)絡(luò)通信所使用的協(xié)議類型。在IPv4的上下文中,它的值通常是AF_INET。
  • sin_zero是一個長度為8的字節(jié)數(shù)組,通常未使用通過填充字段,可以指定套接字的通信地址,從而確立通信的目標(biāo)。
  • 與系統(tǒng)調(diào)用交互:在進(jìn)行套接字編程時,常常需要將sockaddr_in結(jié)構(gòu)體作為參數(shù)傳遞給一些系統(tǒng)調(diào)用函數(shù),例如bind()、connect()、accept()等。這些函數(shù)通過讀取sockaddr_in結(jié)構(gòu)體中的地址信息,可以確定套接字的本地或遠(yuǎn)程地址,從而進(jìn)行相應(yīng)的操作,如綁定、連接或接受連接。

4.bind()

  • bind() 函數(shù)是用于將一個套接字(socket)與一個特定的地址(通常是 IP 地址和端口號)綁定在一起的系統(tǒng)調(diào)用。在網(wǎng)絡(luò)編程中,bind() 函數(shù)通常用于服務(wù)器端程序,在其創(chuàng)建套接字后,將該套接字綁定到一個特定的端口上,以便監(jiān)聽該端口并接受客戶端的連接請求。
  • 函數(shù)原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:指定要綁定的套接字文件描述符。
  • addr:指向 sockaddr 結(jié)構(gòu)體的指針,該結(jié)構(gòu)體包含了要綁定的地址信息。
  • addrlen:指定地址結(jié)構(gòu)體的長度。
  • 如果綁定成功,bind() 函數(shù)返回 0,否則返回 -1。
  • 示例:
if (bind(sockfd,(struct sockaddr *)&server_addr,sizeof(server_addr)) == -1) 
{
	perror("Error binding socket");
	close(sockfd);
}

5.listen()

  • listen() 函數(shù)用于將指定的套接字設(shè)置為監(jiān)聽狀態(tài),開始接受客戶端的連接請求。在服務(wù)器端編程中,通常在調(diào)用 bind() 函數(shù)綁定地址之后,使用 listen() 函數(shù)來準(zhǔn)備套接字接受連接請求。
  • 函數(shù)原型:int listen(int sockfd, in MAX_CLIENTS);
  • sockfd:表示待綁定的套接字的文件描述符,即通過 socket() 函數(shù)創(chuàng)建的套接字。
  • MAX_CLIENTS:參數(shù)指定了內(nèi)核允許在套接字隊列中等待的連接的最大數(shù)量。如果隊列已滿,后續(xù)的連接請求將被拒絕,直到有連接被接受或隊列中的連接被處理。這個參數(shù)通常設(shè)置為一個適當(dāng)?shù)闹担源_保服務(wù)器能夠處理所有傳入的連接請求。
  • 如果綁定成功,listen() 函數(shù)返回 0,否則返回 -1。
  • 示例:
if (listen(server_sock, MAX_CLIENTS) == -1)
{
	perror("Failed to listen");
	close(server_sock);
}

6.accept()

  • accept() 函數(shù)是在服務(wù)器端套接字上調(diào)用的系統(tǒng)調(diào)用,用于接受客戶端的連接請求,并創(chuàng)建一個新的套接字用于與客戶端進(jìn)行通信。這個函數(shù)通常在調(diào)用了 listen() 函數(shù)之后,用于實際接受傳入的連接。
  • 函數(shù)原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen)。
  • sockfd:指定要接受連接請求的監(jiān)聽套接字文件描述符。
  • addr:用于存儲客戶端地址信息的結(jié)構(gòu)體指針。如果不需要獲取客戶端地址信息,可以傳入 NULL。
  • addrlen:指向一個整數(shù)的指針,表示客戶端地址信息結(jié)構(gòu)體的長度。在調(diào)用 accept() 函數(shù)之前,應(yīng)該將其初始化為 sizeof(struct sockaddr)。
  • 當(dāng)調(diào)用 accept() 函數(shù)時,它會阻塞程序的執(zhí)行,直到有客戶端連接請求到達(dá)服務(wù)器套接字 sockfd。一旦有連接請求到達(dá),accept() 函數(shù)會從服務(wù)器的待處理連接隊列中取出一個連接請求,并創(chuàng)建一個新的套接字來處理該連接。這個新的套接字將用于與客戶端進(jìn)行通信,而服務(wù)器原始的套接字繼續(xù)監(jiān)聽其他連接請求。
  • 如果綁定成功,bind() 函數(shù)返回 0,否則返回 -1。
  • 示例:
if (accept(sockfd,(struct sockaddr *)&client_addr,&client_len) == -1) 
{
	perror("Error accepting connection");
	close(sockfd);
}

7.connect()

  • connect() 函數(shù)用于客戶端套接字向服務(wù)器發(fā)起連接請求。當(dāng)客戶端需要與遠(yuǎn)程服務(wù)器建立連接時,就可以使用 connect() 函數(shù)。
  • 函數(shù)原型: connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • sockfd:表示客戶端套接字的文件描述符。
  • addr:是一個指向 sockaddr 結(jié)構(gòu)體(或其子結(jié)構(gòu)體,如 sockaddr_in)的指針,其中包含要連接的服務(wù)器地址信息。
  • addrlen:表示地址結(jié)構(gòu)體的長度。
  • 如果連接請求成功建立,則 connect() 函數(shù)返回 0,并客戶端套接字就可以開始與服務(wù)器進(jìn)行通信了,如果連接請求失敗,則 connect() 函數(shù)返回 -1。
  • 在 connect() 函數(shù)調(diào)用期間,通常會發(fā)生阻塞。這意味著當(dāng) connect() 函數(shù)在建立連接時,程序會暫停執(zhí)行,直到連接成功建立或者發(fā)生錯誤。
  • 需要注意的是,connect() 函數(shù)只能在套接字類型為流套接字(如 SOCK_STREAM)的情況下使用,因為它是用于建立可靠的、面向連接的連接。對于數(shù)據(jù)報套接字(如 SOCK_DGRAM),應(yīng)該使用 sendto() 函數(shù)進(jìn)行發(fā)送,而不是 connect()。
  • 示例:
if (connect(client_sock,(struct sockaddr *)&server_addr,sizeof(server_addr)) < 0) 
{
	perror("Failed to connect to server");
}

8.recv() 與 read()

在TCP通信中,recv和read函數(shù)都是用來從socket接收數(shù)據(jù)的,但它們在不同的編程語言和平臺上有一些細(xì)微的區(qū)別。

(1)recv()

  • 函數(shù)原型:recv(int sockfd, void *buf, size_t len, int flags);
  • recv是通用的socket接收函數(shù),在許多編程語言和操作系統(tǒng)中都有實現(xiàn)。它的作用是從已連接的socket中接收數(shù)據(jù),并將接收到的數(shù)據(jù)存儲到指定的緩沖區(qū)中。
  • recv函數(shù)通常可以設(shè)置一些參數(shù),比如要接收的最大字節(jié)數(shù)、接收數(shù)據(jù)的起始位置等。
  • 其中sockfd是socket文件描述符,buf是接收數(shù)據(jù)的緩沖區(qū),len是要接收的最大字節(jié)數(shù),flags是一些控制接收行為的選項。

(2)read()

  • 函數(shù)原型:read(int fd, void *buf, size_t count);
  • read函數(shù)在OpenHarmony系統(tǒng)中用于從文件描述符(包括socket)中讀取數(shù)據(jù)。它的作用也是從socket接收數(shù)據(jù),類似于recv,但是read函數(shù)更多地用于文件I/O。
  • read函數(shù)的用法與recv類似,也需要指定接收數(shù)據(jù)的緩沖區(qū)和最大字節(jié)數(shù)。
  • buf是接收數(shù)據(jù)的緩沖區(qū),count是要讀取的最大字節(jié)數(shù)。

9.send() 與 write()

在TCP通信中,send()和write()函數(shù)在TCP通信中都起著發(fā)送數(shù)據(jù)的作用。

(1)send()

  • 函數(shù)原型:ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • send函數(shù)是通用的socket發(fā)送函數(shù),在許多編程語言和操作系統(tǒng)中都有實現(xiàn),它的作用是將數(shù)據(jù)從指定的緩沖區(qū)發(fā)送到已連接的socket 。
  • send()函數(shù)通常可以設(shè)置一些參數(shù),比如要發(fā)送的數(shù)據(jù)長度、發(fā)送數(shù)據(jù)的起始位置等。
  • sockfd是套接字文件描述符,buf是要發(fā)送數(shù)據(jù)的緩沖區(qū),len是要發(fā)送的數(shù)據(jù)長度,flags是一些控制發(fā)送行為的選項。如果不需要特定的控制選項,可以將flags參數(shù)設(shè)置為0,以便使用默認(rèn)的行為。

(2)write()

  • 函數(shù)原型:ssize_t write(int fd, const void *buf, size_t count);
  • write函數(shù)在OpenHarmony系統(tǒng)中用于向文件描述符(包括socket)寫入數(shù)據(jù)。它的作用也是將數(shù)據(jù)從指定的緩沖區(qū)發(fā)送到文件描述符所代表的對象(可能是socket)。
  • write函數(shù)的用法與send類似,也需要指定要發(fā)送的數(shù)據(jù)的緩沖區(qū)和數(shù)據(jù)長度。
  • fd是文件描述符,可以是socket文件描述符,buf是要發(fā)送數(shù)據(jù)的緩沖區(qū),count是要發(fā)送的數(shù)據(jù)長度。

10.網(wǎng)絡(luò)編程中可能用到的幾個函數(shù)

  • htons()函數(shù):用于將一個 16 位的無符號短整型數(shù)據(jù)從主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序。在網(wǎng)絡(luò)通信中,不同的計算機(jī)可能具有不同的字節(jié)序,為了確保數(shù)據(jù)在網(wǎng)絡(luò)中的正確傳輸,需要進(jìn)行字節(jié)序的轉(zhuǎn)換。例如,如果主機(jī)是小端字節(jié)序,而網(wǎng)絡(luò)使用大端字節(jié)序,那么通過 htons()可以將主機(jī)上存儲的短整型數(shù)據(jù)轉(zhuǎn)換為適合在網(wǎng)絡(luò)上傳輸?shù)拇蠖俗止?jié)序形式。
  • inet_ntoa()函數(shù):用于將一個 32 位的網(wǎng)絡(luò)字節(jié)序的 IPv4 地址轉(zhuǎn)換為點分十進(jìn)制的字符串形式。例如,如果有一個 IPv4 地址以網(wǎng)絡(luò)字節(jié)序存儲在一個 in_addr 結(jié)構(gòu)體中,可以使用 inet_ntoa() 將其轉(zhuǎn)換為人們常見的點分十進(jìn)制表示,如 “192.168.0.1” 。
  • ntohs()函數(shù):功能與 htons() 相反,它將一個 16 位的網(wǎng)絡(luò)字節(jié)序無符號短整型數(shù)據(jù)轉(zhuǎn)換為主機(jī)字節(jié)序。
  • inet_pton()函數(shù):用于將一個點分十進(jìn)制表示的 IPv4 或 IPv6 地址轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序的二進(jìn)制形式,并存儲在指定的地址結(jié)構(gòu)中。舉例來說,如果你在使用C語言進(jìn)行網(wǎng)絡(luò)編程,你可能會在調(diào)用connect()函數(shù)連接到遠(yuǎn)程服務(wù)器之前,需要將字符串形式的IP地址轉(zhuǎn)換為套接字庫可以理解的形式,這時就需要使用inet_pton()函數(shù)。

三、TCP通信實例

本文文件結(jié)構(gòu)如下:

在OpenHarmony源碼根目錄下創(chuàng)建文件夾Mysample,下創(chuàng)文件夾tcp_demo:

1.服務(wù)端實例

(1)實現(xiàn)流程

  • 初始化:
    創(chuàng)建一個socket對象,通常使用socket(AF_INET, SOCK_STREAM, 0)創(chuàng)建一個面向連接的socket。設(shè)置socket的端點信息,包括IP地址和端口號,通常使用bind()函數(shù)。啟動監(jiān)聽,使用listen()函數(shù)設(shè)置監(jiān)聽隊列大小。
  • 等待連接:使用accept()函數(shù)等待客戶端連接。accept()會返回一個新的socket對象,用于與客戶端進(jìn)行通信。
  • 接收數(shù)據(jù):使用read()函數(shù)接收客戶端發(fā)送的數(shù)據(jù)。
  • 發(fā)送數(shù)據(jù):使用send()函數(shù)將數(shù)據(jù)發(fā)送給客戶端。
  • 關(guān)閉連接:完成數(shù)據(jù)交換后,使用close()函數(shù)關(guān)閉socket,釋放資源。

(2)代碼實現(xiàn)

"Mysample\tcp_demo\src\tcp_demo.cpp"

#include <iostream> // 引入標(biāo)準(zhǔn)輸入輸出流庫
#include <stdio.h>  // 引入標(biāo)準(zhǔn)輸入輸出庫
#include <string.h> // 引入字符串處理庫
#include <netinet/in.h> // 引入IP網(wǎng)絡(luò)庫
#include <arpa/inet.h> // 引入地址轉(zhuǎn)換庫
#include <sys/socket.h> // 引入套接字庫
#include <unistd.h>    // 引入Unix系統(tǒng)調(diào)用庫

// 服務(wù)器端口號
#define SERVER_PORT 4567
// 最大客戶端數(shù)量
#define MAX_CLIENTS 5
// 緩沖區(qū)大小
#define TCP_BUFFER_SIZE 1024

int main()
{
    // 創(chuàng)建服務(wù)器套接字和客戶端套接字
    int server_sock, client_sock;
    struct sockaddr_in server_addr, client_addr;
    socklen_t client_addr_len = sizeof(client_addr);

    // 創(chuàng)建一個服務(wù)端TCP套接字
    server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(server_sock == -1)
    {
        perror("Failed to create socket"); // 創(chuàng)建套接字失敗,打印錯誤信息
        exit(EXIT_FAILURE); // 退出程序
    }

    // 設(shè)置服務(wù)端地址
    server_addr.sin_family = AF_INET; // 設(shè)置地址族為IPv4
    server_addr.sin_port = htons(SERVER_PORT); // 設(shè)置端口號,htons確保端口號為網(wǎng)絡(luò)字節(jié)序
    server_addr.sin_addr.s_addr = INADDR_ANY; // 設(shè)置IP地址為INADDR_ANY,表示接受任何接口的連接

    // 綁定套接字
    if (bind(server_sock, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
    {
        perror("Failed to bind socket"); // 綁定套接字失敗,打印錯誤信息
        close(server_sock); // 關(guān)閉套接字
        exit(EXIT_FAILURE); // 退出程序
    }

    // 開始監(jiān)聽客戶端連接請求
    if (listen(server_sock, MAX_CLIENTS) == -1)
    {
        perror("Failed to listen"); // 監(jiān)聽失敗,打印錯誤信息
        close(server_sock); // 關(guān)閉套接字
        exit(EXIT_FAILURE); // 退出程序
    }
    std::cout << "Server is listening on port " << SERVER_PORT << std::endl; // 打印服務(wù)器監(jiān)聽端口信息

    // 主循環(huán),等待客戶端連接
    while(true)
    {
        // 接受客戶端連接請求
        client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len);
        if (client_sock == -1)
        {
            perror("Failed to accept connection"); // 接受連接失敗,打印錯誤信息
            continue; // 繼續(xù)下一次循環(huán)
        }

        // 打印出連接成功的客戶端的IP地址和端口號
        std::cout << "Accepted connection from " << inet_ntoa(client_addr.sin_addr) << ":" << ntohs(client_addr.sin_port) << std::endl;

        // 發(fā)送數(shù)據(jù)給客戶端
        char request[] = "Hello, here is server!"; // 定義要發(fā)送的字符串
        size_t bytes_write = write(client_sock, request, strlen(request)); // 發(fā)送數(shù)據(jù),并返回發(fā)送的字節(jié)數(shù)
        if (bytes_write == -1)
        {
            perror("Failed to write data"); // 發(fā)送數(shù)據(jù)失敗,打印錯誤信息
            close(client_sock); // 關(guān)閉客戶端套接字
            exit(EXIT_FAILURE); // 退出程序
        }

        // 接受客戶端發(fā)送的數(shù)據(jù)
        char buffer[TCP_BUFFER_SIZE]; // 定義緩沖區(qū)用于接收數(shù)據(jù)
        size_t bytes_read = read(client_sock, buffer, TCP_BUFFER_SIZE); // 從客戶端讀取數(shù)據(jù),并返回讀取的字節(jié)數(shù)
        if (bytes_read == -1)
        {
            perror("Failed to read data"); // 讀取數(shù)據(jù)失敗,打印錯誤信息
            close(client_sock); // 關(guān)閉客戶端套接字
            exit(EXIT_FAILURE); // 退出程序
        }
        else
        {
            std::cout << "Received data from client: " << buffer << std::endl; // 打印接收到的數(shù)據(jù)
            break; // 退出循環(huán)
        }
    }

    // 關(guān)閉服務(wù)器套接字
    close(server_sock);

    return 0;
}

2.客戶端實例

(1)實現(xiàn)流程

  • 創(chuàng)建套接字:使用socket函數(shù)創(chuàng)建一個TCP套接字。參數(shù)通常包括地址族(AF_INET表示IPv4)、套接字類型(SOCK_STREAM表示TCP流式套接字)和協(xié)議(通常為0,表示使用默認(rèn)的TCP協(xié)議)。
  • 設(shè)置服務(wù)器地址:創(chuàng)建一個sockaddr_in結(jié)構(gòu)體,用于存儲服務(wù)器的IP地址和端口號。
  • 連接到服務(wù)器:使用connect函數(shù)將客戶端套接字連接到服務(wù)器。
  • 發(fā)送數(shù)據(jù):使用write系統(tǒng)函數(shù)調(diào)用來發(fā)送數(shù)據(jù)到服務(wù)器。
  • 接收數(shù)據(jù):使用read系統(tǒng)函數(shù)調(diào)用來從服務(wù)器接收數(shù)據(jù)。
  • 關(guān)閉連接:當(dāng)數(shù)據(jù)傳輸完成后,使用close函數(shù)關(guān)閉套接字。

(2)代碼實現(xiàn)

"Mysample\tcp_demo\src\tcp_demo.cpp"

#include <iostream>          // 引入輸入輸出流庫
#include <stdio.h>           // 引入標(biāo)準(zhǔn)輸入輸出庫
#include <string.h>          // 引入字符串處理庫
#include <cstring>           // 引入C風(fēng)格字符串處理庫
#include <sys/socket.h>      // 引入socket編程庫
#include <netinet/in.h>      // 引入網(wǎng)絡(luò)地址結(jié)構(gòu)定義庫
#include <arpa/inet.h>       // 引入網(wǎng)絡(luò)地址轉(zhuǎn)換庫
#include <unistd.h>          // 引入Unix標(biāo)準(zhǔn)庫,提供close函數(shù)

#define TCP_BUFFER_SIZE 1024 // 定義TCP緩沖區(qū)大小為1024字節(jié)

int main()
{
    int client_sock = socket(AF_INET, SOCK_STREAM, 0); // 創(chuàng)建一個IPv4的TCP socket
    if (client_sock == -1) // 如果socket創(chuàng)建失敗
    {
        perror("Failed to create socket"); // 輸出錯誤信息
        exit(EXIT_FAILURE); // 退出程序
    }

    struct sockaddr_in server_addr; // 創(chuàng)建一個服務(wù)器地址結(jié)構(gòu)體

    int SERVER_PORT; // 服務(wù)器端口變量
    std::string SERVER_ADDR; // 服務(wù)器地址變量
    std::cout << "Input server address: "; // 輸出提示信息
    std::cin >> SERVER_ADDR; // 從標(biāo)準(zhǔn)輸入讀取服務(wù)器地址
    std::cout << "Input server port: "; // 輸出提示信息
    std::cin >> SERVER_PORT; // 從標(biāo)準(zhǔn)輸入讀取服務(wù)器端口

    server_addr.sin_family = AF_INET; // 設(shè)置地址族為IPv4
    server_addr.sin_port = htons(SERVER_PORT); // 設(shè)置端口,網(wǎng)絡(luò)字節(jié)序
    if (inet_pton(AF_INET, SERVER_ADDR.c_str(), &server_addr.sin_addr) <= 0) // 如果地址轉(zhuǎn)換失敗
    {
        std::cerr << "Invalid address/ Address not supported" << std::endl; // 輸出錯誤信息
        return -1; // 返回錯誤
    }

    while (true) // 無限循環(huán)嘗試連接
    {
        if (connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) // 如果連接失敗
        {
            perror("Failed to connect to server"); // 輸出錯誤信息
            close(client_sock); // 關(guān)閉socket
            exit(EXIT_FAILURE); // 退出程序
        }
        std::cout << "Connected to server " << inet_ntoa(server_addr.sin_addr) << ":" << ntohs(server_addr.sin_port) << std::endl; // 輸出連接成功信息

        // 向服務(wù)器發(fā)送數(shù)據(jù)
        char request[] = "Hello, here is client!"; // 創(chuàng)建請求字符串
        size_t bytes_write = write(client_sock, request, strlen(request)); // 發(fā)送數(shù)據(jù)
        if (bytes_write == -1) // 如果發(fā)送失敗
        {
            perror("Failed to write data"); // 輸出錯誤信息
            close(client_sock); // 關(guān)閉socket
            exit(EXIT_FAILURE); // 退出程序
        }

        // 從服務(wù)器接收數(shù)據(jù)
        char buffer[TCP_BUFFER_SIZE]; // 創(chuàng)建緩沖區(qū)
        size_t bytes_read = read(client_sock, buffer, TCP_BUFFER_SIZE); // 讀取數(shù)據(jù)
        if (bytes_read == -1) // 如果接收失敗
        {
            perror("Failed to read data"); // 輸出錯誤信息
            close(client_sock); // 關(guān)閉socket
            exit(EXIT_FAILURE); // 退出程序
        }
        else // 如果接收成功
        {
            std::cout << "Received data from server: " << buffer << std::endl; // 輸出接收到的數(shù)據(jù)
            break; // 退出循環(huán)
        }
    }

    // 關(guān)閉
    close(client_sock); // 關(guān)閉socket

    return 0; // 程序成功結(jié)束
}

3.編譯構(gòu)建文件

"C:\Users\LIGANG\Desktop\Mysample\tcp_demo\BUILD.gn"

import("http://build/ohos.gni") # 導(dǎo)入編譯模板
    ohos_executable("tcp") { # 可執(zhí)行模塊
    sources = [ # 模塊源碼
        "src/tcp_demo.cpp"
    ]
    cflags = []
    cflags_c = []
    cflags_cc = []
    ldflags = []
    configs = []
    deps =[] # 部件內(nèi)部依賴
    part_name = "tcp_demo" # 所屬部件名稱,必選
    install_enable = true # 是否默認(rèn)安裝(缺省默認(rèn)不安裝),可選
}

"C:\Users\LIGANG\Desktop\Mysample\tcp_demo\bundle.json"

{
    "name": "@ohos/tcp_demo",
    "description": "",
    "version": "3.1",
    "license": "Apache License 2.0",
    "publishAs": "code-segment",
    "segment": {
        "destPath": "Mysample/tcp_demo"
    },
    "dirs": {},
    "scripts": {},
    "component": {
        "name": "tcp_demo",
        "subsystem": "Mysample",
        "syscap": [],
        "features": [],
        "adapted_system_type": [
            "standard"
        ],
        "rom": "10KB",
        "ram": "10KB",
        "deps": {
            "components": [],
            "third_party": []
        },
        "build": {
            "sub_component": [
                "http://Mysample/tcp_demo:tcp"
            ],
            "inner_kits": [],
            "test": []
        }
    }
}

4.編譯

  • 命令行方式
./build.sh --product-name {product_name} #全量編譯
./build.sh --product-name {product_name}  --build-target {target_name} #單獨編譯部件
./build.sh --product-name {product_name}  --build-target {target_name} --fast-rebuild #快速重建
  • hb方式
hb set #設(shè)置編譯參數(shù)
hb build #全量編譯
hb build -T {target_name} #單獨編譯部件
hb build -T {target_name} --fast-rebuild #快速重建
  • 我們這里使用hb方式來進(jìn)行編譯。在終端輸入命令hb set,選擇standard和unionpi_whale,在終端輸入命令hb build -T tcp_demo。

  • 對編譯有疑問的讀者可查看筆者另外一篇文章【FFH】OpenHarmony構(gòu)建編譯實戰(zhàn),此處不做贅述。
  • 編譯產(chǎn)物在out/board/product目錄下。

5.燒錄

  • 全量燒錄: 適合更新版本或者代碼大變動打包鏡像->RKDevTool燒錄。
  • HDC工具:適合代碼更新時單獨發(fā)送所需文件。
  • 找到可執(zhí)行文件tcp,并將其放置到電腦hdc.exe同級目錄下。
  • 連接設(shè)備:將開發(fā)板上電,并連接電腦。
  • whale開發(fā)板燒錄口為藍(lán)色USB口上層口,使用USBtoUSB線燒錄。

  • 從hdc文件夾下進(jìn)入終端,輸入hdc list targets檢查是否連接好,檢測到設(shè)備后輸-入hdc smode授予進(jìn)程root權(quán)限,再輸入hdc shell mount -o rw,remount /掛載分區(qū),并且賦予可寫權(quán)限。
  • 輸入hdc shell進(jìn)入開發(fā)板終端,mkdir sample創(chuàng)建文件夾,exit退出終端。
  • hdc file send ./tcp /sample/傳輸文件。(將當(dāng)前目錄下的hello文件傳輸?shù)介_發(fā)板的sample目錄下)
  • hdc shell再次進(jìn)入開發(fā)板終端,cd sample進(jìn)入文件夾,chmod 777 *給程序賦予可執(zhí)行權(quán)限。

6.測試并執(zhí)行

  • 服務(wù)端程序測試:

將開發(fā)板連接上網(wǎng)絡(luò),通過hdc.exe工具執(zhí)行命令ifconfig查看開發(fā)板IP地址:

  • 通過netassist模擬客戶端,選擇TCP Client,填入開發(fā)板地址與端口號:

  • 在sample目錄下執(zhí)行./tcp_demo命令,啟動程序,終端打印提示信息:

  • 點擊netassist模擬客戶端連接按鈕,可以看到與開發(fā)板服務(wù)端連接成功,并接受到開發(fā)板發(fā)來的Hello, here is server!消息,終端也打印連接成功的提示信息。

  • 點擊發(fā)送按鈕發(fā)送Welcome to NetAssist給開發(fā)板服務(wù)端,終端也打印相對應(yīng)提示信息:

  • 程序結(jié)束,測試成功。

客戶端程序測試:

  • 將開發(fā)板連接上網(wǎng)絡(luò)。
  • 使用ipconfig查看PC主機(jī)IP地址:

  • 通過netassist模擬服務(wù)端,選擇TCP Server,填入開發(fā)板地址與端口號,單擊打開按鈕開啟監(jiān)聽:

  • 在sample目錄下執(zhí)行./tcp_demo命令,啟動程序,輸入服務(wù)端IP與端口號:

  • 可見終端打印連接成功的提示信息,主機(jī)收到了開發(fā)板客戶端發(fā)來的Hello, here is client!消息:

  • 點擊發(fā)送按鈕發(fā)送Welcome to NetAssist給開發(fā)板客戶端,終端也打印相對應(yīng)提示信息:

  • 程序結(jié)束,測試成功。

7.番外

此程序意在說明一臺設(shè)備既可以作為客戶端也可以作為服務(wù)端,程序?qū)崿F(xiàn)了本機(jī)先作為服務(wù)端與PC主機(jī)進(jìn)行TCP通信,后兩者交換身份,本機(jī)作為客戶端。筆者測試過,程序無誤可以正常運(yùn)行,在此不做贅述。有興趣的讀者可以作嘗試,

"C:\Users\LIGANG\Desktop\Mysample\tcp_demo\src\tcp_demo.cpp"

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#define SERVER_PORT1 4567 // 服務(wù)器端口號
#define SERVER_PORT2 7654 // 服務(wù)器端口號
#define MAX_CLIENTS 5 // 最大客戶端數(shù)量
#define TCP_BUFFER_SIZE 1024 // 緩沖區(qū)大小

int main()
{
    // ------------------------------------本機(jī)作為服務(wù)端--------------------------------------------


    int server_sock, client_sock; // 服務(wù)器套接字和客戶端套接字
    struct sockaddr_in server_addr, client_addr; // 服務(wù)器地址和客戶端地址
    socklen_t client_addr_len = sizeof(client_addr); // 客戶端地址長度

    // 創(chuàng)建一個服務(wù)端TCP套接字
    server_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(server_sock == -1)
    {
        perror("Failed to create socket");
        exit(EXIT_FAILURE);
    }

    // 設(shè)置服務(wù)端地址
    server_addr.sin_family = AF_INET; // 使用IPv4協(xié)議
    server_addr.sin_port = htons(SERVER_PORT1); // 端口號
    server_addr.sin_addr.s_addr = INADDR_ANY; // 監(jiān)聽所有可用的IP地址

    // 綁定套接字
    if (bind(server_sock, (struct sockaddr *)&server_addr,sizeof(server_addr)) == -1)
    {
        perror("Failed to bind socket");
        close(server_sock);
        exit(EXIT_FAILURE);
    }

    // 開始監(jiān)聽客戶端連接請求
    if (listen(server_sock, MAX_CLIENTS) == -1)
    {
        perror("Failed to listen");
        close(server_sock);
        exit(EXIT_FAILURE);
    }
    std::cout << "Server is listening on port " << SERVER_PORT1 << std::endl;

    while(true)
    {
        // 接受客戶端連接請求
        client_sock = accept(server_sock, (struct sockaddr *)&client_addr, &client_addr_len);
        if (client_sock == -1)
        {
            perror("Failed to accept connection");
            continue;
        }

        // 打印出連接成功的客戶端的IP地址和端口號
        std::cout<<"Accepted connection from "<<inet_ntoa(client_addr.sin_addr)<<":"<<ntohs(client_addr.sin_port)<<std::endl;

        // 發(fā)送數(shù)據(jù)給客戶端
        char request[] = "Hello, here is server!";
        size_t bytes_write = write(client_sock, request, strlen(request));
        if (bytes_write == -1)
        {
            perror("Failed to write data");
            close(client_sock);
            exit(EXIT_FAILURE);
        }

        // 接受客戶端發(fā)送的數(shù)據(jù)
        char buffer[TCP_BUFFER_SIZE];
        size_t bytes_read = read(client_sock, buffer, TCP_BUFFER_SIZE);
        if (bytes_read == -1)
        {
            perror("Failed to read data");
            close(client_sock);
            exit(EXIT_FAILURE);
        }
        else
        {
            std::cout<<"Received data from client: "<<buffer<<std::endl;
            break;
        }
    }

    // 關(guān)閉
    close(server_sock);

    // ------------------------------------本機(jī)作為客戶端--------------------------------------------


    // 配置服務(wù)器地址信息
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(SERVER_PORT2);
    // 原來的客戶端地址作為服務(wù)端地址
    server_addr.sin_addr.s_addr = client_addr.sin_addr.s_addr;

    // 創(chuàng)建客戶端套接字
    client_sock = socket(AF_INET, SOCK_STREAM, 0);
    if(client_sock == -1)
    {
        perror("Failed to create socket");
        exit(EXIT_FAILURE);
    }

    // 連接服務(wù)器
    while(true)
    {
        // 連接服務(wù)器
        if (connect(client_sock, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) 
        {
            perror("Failed to connect to server");
            close(client_sock);
            exit(EXIT_FAILURE);
        }

        // 打印出連接成功的服務(wù)器的IP地址和端口號
        std::cout<<"Connected to server "<<inet_ntoa(server_addr.sin_addr)<<":"<<ntohs(server_addr.sin_port)<<std::endl;

        // 向服務(wù)器發(fā)送數(shù)據(jù)
        char request[] = "Hello, here is client!";
        size_t bytes_write = write(client_sock, request, strlen(request));
        if (bytes_write == -1)
        {
            perror("Failed to write data");
            close(client_sock);
            exit(EXIT_FAILURE);
        }

        // 從服務(wù)器接收數(shù)據(jù)
        char buffer[TCP_BUFFER_SIZE];
        size_t bytes_read = read(client_sock, buffer, TCP_BUFFER_SIZE);
        if (bytes_read == -1)
        {
            perror("Failed to read data");
            close(client_sock);
            exit(EXIT_FAILURE);
        }
        else
        {
            std::cout<<"Received data from server: "<<buffer<<std::endl;
            break;
        }
    }
    
    // 關(guān)閉
    close(client_sock);

    return 0;
}

想了解更多關(guān)于開源的內(nèi)容,請訪問:

51CTO 鴻蒙開發(fā)者社區(qū)

https://ost.51cto.com

責(zé)任編輯:jianghua 來源: 51CTO 鴻蒙開發(fā)者社區(qū)
相關(guān)推薦

2019-11-08 14:47:49

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

2024-08-13 08:27:24

PythonTCP協(xié)議網(wǎng)絡(luò)編程

2024-07-26 16:39:33

鴻蒙系統(tǒng)開源構(gòu)建系統(tǒng)

2023-04-03 15:51:47

2022-02-17 16:47:40

OpenharmonIPC通信鴻蒙

2011-12-15 09:40:06

Javanio

2022-09-07 15:35:49

設(shè)備開發(fā)鴻蒙

2024-07-09 08:15:26

鴻蒙PythonC++

2016-11-04 21:37:16

PythonSocket

2012-09-24 15:13:50

C#網(wǎng)絡(luò)協(xié)議TCP

2015-04-24 09:48:59

TCPsocketsocket編程

2020-08-03 08:10:52

UDPTCP通信

2009-08-24 17:20:13

C#網(wǎng)絡(luò)通信TCP連接

2019-04-29 10:26:49

TCP網(wǎng)絡(luò)協(xié)議網(wǎng)絡(luò)通信

2022-11-02 15:49:45

應(yīng)用開發(fā)鴻蒙

2022-11-07 15:40:22

數(shù)據(jù)轉(zhuǎn)碼應(yīng)用應(yīng)用開發(fā)

2022-11-11 09:37:58

數(shù)據(jù)轉(zhuǎn)碼應(yīng)用開發(fā)

2012-03-19 11:41:30

JavaSocket

2014-12-11 09:20:30

TCP

2019-09-18 20:07:06

AndroidTCP協(xié)議
點贊
收藏

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

国产精品97| 成人网ww555视频免费看| 风流少妇一区二区| 91福利视频网| 国产又色又爽又高潮免费| 大胆国模一区二区三区| 午夜视频在线观看一区| 日本一区不卡| 亚洲精品久久久狠狠狠爱| 久久人人超碰| 久久久久久久久久久人体| 亚洲精品成人无码| 99久久香蕉| 欧美日韩一区久久| 欧美a在线视频| 在线观看av免费| 欧美国产精品一区二区| 国产一区二区自拍| 国产精品一级二级| 首页国产欧美久久| 欧美精品第一页在线播放| 国产1区2区在线观看| 欧美福利在线播放网址导航| 91精品国产一区二区人妖| 青青草av网站| 亚洲精品mv| 亚洲国产美国国产综合一区二区| 亚洲欧美日本国产有色| 免费动漫网站在线观看| 激情深爱一区二区| 日韩美女视频免费在线观看| 日韩成人av毛片| 欧美~级网站不卡| 色婷婷综合久久久久| 精品人妻互换一区二区三区| 91综合精品国产丝袜长腿久久| 欧美久久久久中文字幕| 黄色国产小视频| 日韩免费小视频| 色综合色综合色综合| 霍思燕三级露全乳照| 亚洲丝袜一区| 亚洲激情欧美激情| 视色,视色影院,视色影库,视色网 日韩精品福利片午夜免费观看 | 国产中文日韩欧美| 波多野结衣家庭主妇| 久久国产成人| 国产精品成人久久久久| 五月婷婷激情五月| 老司机亚洲精品| 国产精品88a∨| 一区精品在线观看| 久久 天天综合| 亚洲伊人久久综合| xxxx18国产| 国产成人综合在线观看| 99精品国产一区二区| 国产suv一区二区| 成人深夜在线观看| 国产一区二区三区四区五区加勒比| 亚洲精品国产一区二| 99re热这里只有精品视频| 国产一区二区不卡视频在线观看| 污污网站在线免费观看| 久久久久久久网| 午夜欧美性电影| 在线h片观看| 午夜国产一区二区| proumb性欧美在线观看| 精品乱码一区| 国产日本在线视频| 国产精品激情偷乱一区二区∴| 正在播放一区二区三区| caoporn免费在线视频| 一区二区三区在线播放| 人妻久久久一区二区三区| 亚洲国产欧美日本视频| 欧美日韩亚洲综合一区二区三区| 九九热精品国产| 粉嫩一区二区三区四区公司1| 日韩第一页在线| 日韩女同一区二区三区| 欧美aⅴ99久久黑人专区| 97色在线视频观看| 一级aaaa毛片| 99re8在线精品视频免费播放| 日韩av在线电影观看| 精品国产丝袜高跟鞋| 五月天亚洲精品| 中文字幕视频在线免费观看| 国产精品亚洲欧美日韩一区在线| 亚洲成人精品在线| 粉嫩精品久久99综合一区| 欧美在线免费| 国产精品久久久久久久久久久久久久| 国产又大又粗又长| 成人av综合在线| 欧美激情免费视频| 亚洲欧洲国产精品| 欧美老熟妇乱大交xxxxx| 婷婷综合网站| 国产999在线| 性欧美一区二区三区| 久久久精品2019中文字幕之3| 日本在线视频www色| 成人性生交大片免费网站| 日韩一级欧美一级| 男女男精品视频网站| aⅴ色国产欧美| 91精品国产高清久久久久久91裸体| 四虎精品在线| 一个色妞综合视频在线观看| 欧美亚洲日本在线观看| 私拍精品福利视频在线一区| 美女久久久久久久| 中日韩在线观看视频| 99re这里都是精品| 久久综合久久网| 久久九九精品视频| xxxxx91麻豆| 无码人妻丰满熟妇奶水区码| 成人18视频日本| 久久国产精品免费观看| 黄色精品视频| 亚洲人午夜精品免费| 日韩精品视频免费播放| 国内成人自拍视频| 亚洲精品8mav| 国产精品一区二区免费福利视频 | 热99在线视频| 五月天婷婷在线观看| 亚洲综合久久久久| 无码国产精品一区二区高潮| 亚欧美无遮挡hd高清在线视频| 日韩女优在线播放| 五月天久久久久久| 欧美日韩国内自拍| 51调教丨国产调教视频| 一本久久综合| 黄色国产精品一区二区三区| 国产深夜视频在线观看| 欧美大片日本大片免费观看| 欧美激情图片小说| 国产真实乱子伦精品视频| 亚洲综合五月天| 伊人久久精品| 九九精品在线观看| 性生活免费网站| 亚洲国产日韩av| yy1111111| 亚洲欧美日本视频在线观看| 久久精品人成| 成人黄色免费短视频| 亚洲欧美日韩成人| 国产污视频网站| 国产亚洲女人久久久久毛片| 精品国产污网站| 国产精品入口芒果| 日韩欧美四区| 国产精品户外野外| 日本www在线| 91精品国产高清一区二区三区蜜臀| 亚洲精品国产精品乱码在线观看| 激情综合一区二区三区| 国产资源第一页| 黄色欧美网站| 日韩av电影院| 在线观看h片| 日韩一区二区三区免费观看| 久久久全国免费视频| aa级大片欧美| 久久99999| 欧美va亚洲va日韩∨a综合色| 成人黄动漫网站免费| 蜜桃视频m3u8在线观看| 中文字幕欧美精品在线| 精品人妻一区二区三区含羞草 | 日韩免费av片| 久久精品欧美日韩| 手机精品视频在线| 一区二区黄色| 在线观看福利一区| 精品网站aaa| 国产精品高清免费在线观看| 黄色网页在线观看| 日韩av一区在线观看| 中文字幕免费视频观看| 一区二区三区四区精品在线视频 | 国产精品少妇自拍| 久久久久久久久久久久国产精品| 噜噜噜久久亚洲精品国产品小说| 在线免费一区| 一本久久青青| 99久久无色码| 高清av一区| 午夜精品一区二区三区在线播放 | 一本久道中文无码字幕av| 最新国产精品| 日韩中文不卡| 开心激情综合| 91精品啪在线观看麻豆免费| 亚洲妇女成熟| 欧美乱大交xxxxx| 啊v在线视频| 精品偷拍各种wc美女嘘嘘| 97超碰人人模人人人爽人人爱| 天天操天天色综合| 丝袜美腿小色网| 国产欧美日韩一区二区三区在线观看 | 一区二区三区短视频| 久久成人一区二区| 第一福利在线| 精品一区电影国产| 日本高清视频www| 91精品国产一区二区三区香蕉| 午夜一区二区三区四区| 舔着乳尖日韩一区| 国产五月天婷婷| 亚洲男女一区二区三区| wwwww黄色| 久久久777精品电影网影网| 亚洲天堂2024| 成人精品小蝌蚪| 少妇极品熟妇人妻无码| 精品一区二区三区av| 欧美伦理片在线看| 久久在线精品| 国产成人久久婷婷精品流白浆| 亚洲第一区色| 妺妺窝人体色777777| 欧美精品网站| 免费看污污视频| 亚洲精品二区三区| 亚洲免费av网| 小小影院久久| 潘金莲一级淫片aaaaa免费看| 日韩精品永久网址| 亚洲免费视频一区| 999国产精品视频| 久久久一二三四| 羞羞答答成人影院www| 性欧美18一19内谢| 午夜片欧美伦| 91传媒免费视频| 欧美午夜国产| 九九爱精品视频| 亚洲精选一区| 成人免费观看毛片| 日韩av一区二区三区| www.激情小说.com| 精品制服美女久久| 日本高清免费观看| 国产精品白丝jk黑袜喷水| 免费av不卡在线| 国产乱淫av一区二区三区| 国产chinesehd精品露脸| 粉嫩av一区二区三区粉嫩 | 这里视频有精品| 黄色99视频| 奇米狠狠一区二区三区| 亚洲春色在线视频| 亚洲乱码精品| 日韩中文字幕在线免费| 免费日韩av片| 99热手机在线| 国产精品中文字幕一区二区三区| 国产精久久久久| 91美女视频网站| 国产又粗又猛又爽又黄的视频小说| 亚洲男同性视频| 日本午夜精品理论片a级app发布| 欧美日韩国产精品一区| 在线观看亚洲黄色| 欧美一级高清片在线观看| 男人天堂一区二区| 在线视频免费一区二区| 操你啦在线视频| 日本国产一区二区三区| 色婷婷成人网| 久久久久高清| 午夜久久免费观看| 91国视频在线| 国产一区高清在线| 亚洲av无码一区二区三区人| 亚洲天堂久久久久久久| 91久久国产视频| 欧美丰满少妇xxxxx高潮对白| 亚洲欧美国产高清va在线播放| 精品香蕉一区二区三区| 免费在线看黄网站| 欧洲成人免费视频| 久久一级大片| 欧美一区二区三区四区在线观看地址 | 天天爽夜夜爽夜夜爽精品| 欧美视频一区在线观看| 丰满人妻一区二区三区四区53| 亚洲性线免费观看视频成熟| 调教一区二区| 国产精品麻豆va在线播放| 亚洲3区在线| 亚洲午夜精品久久久中文影院av | 香蕉成人伊视频在线观看| 中文字幕男人天堂| 日韩电影视频免费| av网站免费在线观看| 国产精品久久久久77777| 黄色欧美在线| 日本男女交配视频| 麻豆精品一区二区av白丝在线| 中文在线永久免费观看| 日韩美女视频一区| 亚洲无码精品在线观看| 亚洲深夜福利视频| av男人的天堂在线观看| 51国偷自产一区二区三区 | 精品国产一区二区三区不卡蜜臂 | 国产毛片久久久久久久| 亚洲mv大片欧洲mv大片精品| 国产丝袜在线视频| 日韩一区视频在线| 日韩久久一区二区三区| 久久99精品国产一区二区三区| 午夜精品久久99蜜桃的功能介绍| 一级片视频免费观看| 日本一区二区三区高清不卡| 日本va欧美va国产激情| 亚洲成人av在线播放| 欧美卡一卡二| 99久久久精品免费观看国产| 国产精品黑丝在线播放| 成人午夜激情av| 国产日产欧美一区二区视频| 五月天婷婷丁香| 亚洲国产精品中文| 国内在线视频| 国语精品中文字幕| 亚洲黄色天堂| avtt香蕉久久| 一本大道av伊人久久综合| 日本韩国一区| 日韩美女视频免费在线观看| 香蕉久久精品| 亚洲精品无码久久久久久| 91丨porny丨国产入口| 国产成人在线免费观看视频| 亚洲精品在线免费观看视频| 色呦呦视频在线观看| 国产精品theporn88| 雨宫琴音一区二区在线| 中文文字幕文字幕高清| 精品免费在线视频| 激情综合闲人网| 国产精品免费小视频| 色婷婷亚洲mv天堂mv在影片| 成人性生交免费看| 亚洲视频在线一区二区| 国产av无码专区亚洲av麻豆| 欧美剧在线观看| 久久悠悠精品综合网| 日韩激情免费视频| 国产精品女上位| 国产99对白在线播放| 高清一区二区三区日本久| 偷拍精品福利视频导航| 国产三级日本三级在线播放| 一区免费观看视频| 黄色片一区二区三区| 日本久久中文字幕| 欧美高清在线| 麻豆精品国产传媒av| 色欧美日韩亚洲| 国产黄a三级三级三级av在线看| 成人自拍网站| 久久九九99| 成年人一级黄色片| 日韩电影网在线| 日韩电影精品| 欧美a v在线播放| 国产精品人妖ts系列视频| 国产浮力第一页| 人妖精品videosex性欧美| 99久久99久久精品国产片桃花| 日本成人在线免费| 91国产成人在线| 高清电影在线免费观看| 视频一区二区在线观看| 粉嫩绯色av一区二区在线观看| 在线永久看片免费的视频| 欧美大胆在线视频| 欧美精品羞羞答答| 丰满少妇xbxb毛片日本| 欧美在线观看一区二区| 日本在线视频网址| 亚洲精品一区二| 91丨porny丨国产入口| 国产91视频在线| 国产精品女人久久久久久| 亚洲五月婷婷| 97精品在线播放| 亚洲欧美另类自拍|