Linux-網絡編程-學習筆記(20):網絡基礎與編程實踐
1、網絡基礎
數據庫
- 網絡通訊概述
網絡是用物理鏈路將各個孤立的工做站或主機相連在一塊兒,組成數據鏈路,從而達到資源共享和通訊的目的。通訊是人與人之間經過某種媒體進行的信息交流與傳遞。網絡通訊是經過網絡將各個孤立的設備進行鏈接,經過信息交換實現人與人,人與計算機,計算機與計算機之間的通訊。
站在進程的層面來講,網絡之間的通訊其實就是位於網絡中不一樣主機上面的2個進程之間的通訊。
以2臺設備的QQ之間通訊爲例:
在這裏插入圖片描述
從圖中能夠看出,網絡通訊是分層的:
(1)硬件部分:網卡(負責經過網線或者WIFI的方式與外部網絡進行通訊)
(2)操做系統底層:網卡驅動(負責驅動網卡以及打包數據的操做)
(3)操做系統API:socket接口(應用軟件去操做網卡驅動的API)
(4)應用層:低級(直接基於socket接口編程)
(5)應用層:高級(基於網絡通訊應用框架庫)
(6)應用層:更高級(http、網絡控件等)
編程
- 網絡通訊基礎知識
2.1 OSI7層網絡模型
在這裏插入圖片描述
2.2 網卡
(1)網卡是計算機用來上網的必備硬件設備,CPU靠網卡來鏈接外部網絡。
(2)網卡是一個串轉並的設備。網卡芯片和CPU之間的通訊是並行通訊,網絡通訊是一種串行、全雙工、差分的通訊方式。
(3)網卡用來進行數據幀的封包和拆包。網絡的發送數據的時候不單純是發送數據,而是將必定大小的數據進行打包(64kb或其餘大小)發送,包包含三部分,包頭、數據和包尾(其中包頭包含了IP信息等)。
(4)網卡可以實現網絡數據緩存和速率適配(兩個電腦的傳輸速率不相同)。
2.3 集線器
(1)信號中繼放大,至關於中繼器。
(2)組成局域網絡,用廣播方式工做。(多臺設備插到一個集線器上)
(3)注意集線器是不能用來鏈接外網的。
瀏覽器
2.4 交換機
(1)包含集線器功能,但更高級。
(2)交換機中有地址表,數據包查表後直達目的通訊口而不是廣播。
(3)找不到目的口時廣播並學習。
緩存
2.5 路由器
在這裏插入圖片描述
(1)路由器是局域網和外部網絡通訊的出入口。(跨局域網進行通訊須要通過網關才能出去,路由器就至關於一個網關)
(2)路由器將整個internet劃分紅一個個的局域網,卻又互相聯通。(兩個路由器鏈接下的電腦構成了兩個局域網,經過路由器實現局域網間接鏈接)
(3)路由器對內管理子網(局域網),能夠在路由器中設置子網的網段,設置有線端口的IP地址,設置dhcp功能等,所以局域網的IP地址是路由器決定的。
(4)路由器對外實現聯網,聯網方式取決於外部網絡(如ADSL撥號上網、寬帶賬號、局域網等)。這時候路由器又至關因而更高層級網絡的其中一個節點而已。
路由器的WAN是對外的口,LAN是對內的口
(5)路由器至關於有2個網卡,一個對內作網關、一個對外作節點。
(6)路由器的主要功能是爲通過路由器的每一個數據包尋找一條最佳路徑(路由)並轉發出去。其實就是局域網內電腦要發到外網的數據包,和外網回覆給局域網內電腦的數據包。(路由器的好壞決定路徑選的好壞,即收發速度)
(7)路由器技術是網絡中最重要技術,決定了網絡的穩定性和速度。
服務器
2.6 DNS(Domain Name Service 域名服務)
(1)網絡世界的門牌號:IP地址(例如百度的IP地址爲61.135.169.125)。IP地址的缺點:難記、不直觀。
(2)IP地址的替代品:域名(例如www.baidu.com)。
(3)DNS服務器就是專門提供域名和IP地址之間的轉換的服務的,所以域名要購買的.
(4)咱們訪問一個網站的流程是:先使用IP地址(譬如谷歌的DNS服務器IP地址爲8.8.8.8)訪問DNS服務器(DNS服務器不能是域名,只能是直接的IP地址),查詢咱們要訪問的域名的IP地址,而後再使用該IP地址訪問咱們真正要訪問的網站。這個過程被瀏覽器封裝屏蔽,其中使用的就是DNS協議。
(5)瀏覽器須要DNS服務,而QQ這樣的客戶端卻不須要(由於QQ軟件編程時已經知道了騰訊的服務器的IP地址,所以能夠直接IP方式訪問服務器)
網絡
2.7 DHCP(dynamic host configuration protocl,動態主機配置協議)
(1)每臺計算機都須要一個IP地址,且局域網內各電腦IP地址不能重複,不然會地址衝突(同一個局域網內,兩臺設備的IP地址重複,好比都設爲了192.168.1.1)。
(2)計算機的IP地址能夠靜態設定(本身制定IP地址,可是管理起來很麻煩),也能夠動態分配(由管理員路由器給自動分配)
(3)動態分配是局域網內的DHCP服務器來協調的,不少設備都能提供DHCP功能,譬如路由器。
(4)動態分配的優點:方便接入和斷開、有限的IP地址獲得充分利用。
架構
2.8 NAT(network address translation,網絡地址轉換協議)
(1)IP地址分爲公網IP(internet範圍內惟一的IP地址)和私網IP(內網IP),局域網內的電腦使用的都是私網IP(經常使用的就是192.168.1.xx)
(2)網絡通訊的數據包中包含有目的地址的IP地址。
這裏以獲取百度某張圖片爲例:首先子網中的某臺設備的IP地址爲192.168.1.1,它所鏈接的路由器的IP地址爲172.1.1.1,那麼設備想要從百度獲取一張圖片,必定是要向百度網站發送一個請求命令,這個命令就是一個數據,那麼在發送前網卡會將數據進行打包(包頭、數據、包尾),其中包頭保存了公網IP(路由器)和私網IP(設備)和目的地IP(百度服務器),而後經過路由器規劃路徑後發送到百度的服務器上,服務器進行數據的解析,得知是要獲取某張圖片,因而將圖片數據進行打包(仍然是3部分),其中包頭中的目的地址和本地地址取反(發送地變爲接收地,接收地變爲發送地),將圖片發送回網卡,路由器進行判斷,知道該圖片應該發送給192.168.1.1對應的設備,最終該設備收到了圖片。
(3)當局域網中的主機要發送數據包給外網時,路由器要負責將數據包頭中的局域網主機的內網IP替換爲當前局域網的對外外網IP。這個過程就叫NAT。
(4)NAT的做用是緩解IPv4的IP地址不夠用問題,但只是相似於打補丁的形式,最終的解決方案仍是要靠IPv6。
(6)NAT穿透:P2P下載方式叫作一種穿透,服務器做爲中介,讓兩臺內網相連的技術叫作穿透。
這裏以迅雷下載爲例:假設我要下載一張圖片(局域網A的設備1),若是從百度上下載這張圖片時,須要前一個例子那樣,走很長一段距離才能到達百度服務器,這無疑會浪費不少時間。可是P2P下載方式爲咱們提供了一種點對點的方式下載,也就是若是這張圖片在另一臺設備上有(局域網B的設備1),同時個人設備和那臺設備都鏈接了訓練服務器,那麼迅雷服務器會爲咱們兩個局域網之間構成了一條通路(原本兩個局域網互相不知道IP
是沒法進行鏈接的,可是若是2臺設備都鏈接到了迅雷服務器,那麼迅雷服務器會自動安排一種鏈接通道),這樣我就能夠直接到那臺設備上下載圖片。經過縮短了距離來提升了下載速度。若是同時有100臺設備上都有這張圖片,那麼個人設備就與這100臺設備都構成了通路,從而實現了一種並行下載,極大程度地提升了下載速度。這就好像原本兩個局域網之間有一堵牆隔着,P2P的下載方式穿透了這堵牆,因此稱爲NAT穿透。
框架
2.9 IP地址分類(IPv4)
(1)IP地址實際是一個32位二進制構成,在網絡通訊數據包中就是32位二進制,而在人機交互中使用點分十進制方式顯示。
異步
二進制方式 0xffffffff 0xC0A80166/0x6601A8C0 本質
點分十進制方式 255.255.255.255 192.168.1.102 方便人看的
(2)IP地址中32位實際包含2部分,分別爲:網絡地址和主機地址。子網掩碼用來講明網絡地址和主機地址各自佔多少位。
能夠8位表示網絡,24位表示主機;也能夠16位表示網絡,16位表示主機;14爲表示網絡,18位表示主機。下面表格爲用子網掩碼錶示的2種:
socket
子網掩碼:255.255.255.0 前24位爲網絡地址,後8位爲主機地址
子網掩碼:255.255.0.0 前16位爲網絡地址,後16位爲主機地址
網絡地址決定了這種網絡中必定能夠有多少個網絡,主機地址決定了該子網下最多能有多少主機。譬如子網掩碼爲255.255.255.0時表示咱們這一種網絡一共最多能夠有224個,每一個這種網絡中能夠有28個主機。
若是子網掩碼爲255.255.0.0時,表示咱們這種網絡能夠有216個網絡,每一個這種網絡中最多能夠有216個主機。
網絡地址用來表示子網,主機地址是用來表示子網中的具體某一臺主機的。
(3)由網絡地址和主機地址分別佔多少位的不一樣,將IP地址分爲5類,最經常使用的有3類(A類、B類和C類)
(4)127.0.0.0用來作迴環測試loopback
(5)判斷2個IP地址是否在同一子網內的方法是:查看2個IP地址的網絡標識同樣,那麼就處於同一網絡。
網絡標識 = IP地址 & 子網掩碼
例如:192.168.1.4和192.168.12.5,若是子網掩碼是255.255.255.0那麼不在同一網段,若是子網掩碼是255.255.0.0那麼就在同一個網段。
2、網絡編程
- 網絡編程框架
1.1 網絡的分層結構
由於網絡是一種很是複雜的通訊方式,因此要經過分層來進行開發難度的下降。所以咱們在研究網絡通訊時,必定要在同一個層次進行研究,不能跨層次研究,好比分析客戶端和服務器的收發時,要分析API層次時,兩部分都要統一在這個層次進行分析,而不能是一端分析API接口,另外一端卻去分析驅動了。通常狀況下,咱們在網絡編程時最關注的是應用層,傳輸層只須要了解便可。
1.2 BS和CS
(1)CS架構介紹(client server,客戶端服務器架構)。好比QQ,360網盤之類的(在電腦上或手機上用軟件登陸的)。
(2)BS架構介紹(broswer server,瀏覽器服務器架構)。好比在線版的QQ,網頁版360網盤(用瀏覽器打開的)。
- TCP協議
傳輸控制協議(TCP,Transmission Control Protocol)是一種面向鏈接的、可靠的、基於字節流的傳輸層通訊協議。
2.1 TCP協議的做用
(1)TCP協議工做在傳輸層,對上服務socket接口(API),對下調用IP層。(咱們只須要經過調用socket接口實現數據收發,其內部安排由TCP來完成)
(2)TCP協議面向鏈接,通訊前必須先3次握手創建鏈接關係後才能開始通訊。(好比打電話必須你撥號,對面接聽纔可以進行雙向的語音通訊)
(3)TCP協議(像是一個快遞公司)提供可靠傳輸,不怕丟包、亂序等。
2.2 TCP如何保證可靠傳輸
(1)TCP在傳輸有效信息前要求通訊雙方必須先握手,創建鏈接才能通訊(好比經過打電話聯繫一我的時,經過收到了對方的迴應從而肯定對方收到了消息;而經過QQ只是發送了消息過去,對方是否看到這裏不清楚)
(2)TCP的接收方收到數據包後會ack給發送方,若發送方未收到ack會丟包重傳(每一次發送都要有迴應,從而確保發送信息的被收到)
(3)TCP的有效數據內容會附帶校驗,以防止內容在傳遞過程當中損壞(就好像快遞公司給包裹加上了某種保護措施)
(4)TCP會根據網絡帶寬來自動調節適配速率,自動調整發送包的大小和一次發多少個包等……(滑動窗口技術)
(5)發送方會給各分割報文編號,接收方會校驗編號,一旦順序錯誤即會重傳(傳的數據順序不能亂)
2.3 TCP的三次握手
在這裏插入圖片描述
TCP創建鏈接須要三次握手,這是TCP協議內部自動完成的,咱們只須要調用對應的API進行收發便可。
創建鏈接的條件:服務器listen時客戶端主動發起connect。
創建過程:SYN是一個同步信號,客戶端發起完這個SYN信號 [第一次] 後就主動進入到了SYN-SENT(請求鏈接)狀態,服務器收到信號後,就會進入到SYN-RCVD(同步收到)狀態而且回覆一個SYN+ACK信號 [第二次] ,客戶端在SYN-SENT接收到SYN+ACK信號後會迴應一個ACK信號 [第三次] ,而且將自身狀態變爲ESTAB-LISHED(創建服務)。服務器收到了ACK信號,也會進入到ESTAB-LISHED,從而創建鏈接。客戶端和服務器之間能夠進行雙向通訊。
2.4 TCP的四次揮手
在這裏插入圖片描述
TCP斷開鏈接須要四次揮手。
斷開鏈接的條件:服務器或者客戶端均可以主動發起關閉。
斷開過程:假設客戶端先向其TCP發出鏈接釋放報文段,並中止再發送數據,主動關閉TCP鏈接。客戶端發送釋放報文FIN [第一次] ,此時客戶端進入FIN-WAIT-1(終止等待1)狀態,等待服務器的確認。服務器收到釋放報文後發出確認報文ACK [第二次] ,而後服務器就進入CLOSE-WAIT(關閉等待)狀態。TCP服務器進程這時應通知高層進程,於是從客戶端到服務器這個方向的鏈接就釋放了,這時的TCP鏈接處於半關閉狀態,即客戶端已經沒有數據要發送了,但服務器若發送數據,客戶端仍要接收。也就是說,從服務器到客戶端這個方向的鏈接並未關閉。這個狀態可能會持續一些時間。客戶端收到來自服務器的確認後,就進入FIN-WAIT-2(終止等待2)狀態,等待服務器發出的鏈接釋放報文段。若服務器已經沒有要向客戶端發送的數據,其應用進程就通知TCP釋放鏈接。這時服務器發出的鏈接釋放報文FIN,而且還附帶上次已發送過的確認號ACK [第三次] 。這時服務器就進入了LAST-ACK(最後確認)狀態,等待客戶端的確認。客戶端在收到服務器的鏈接釋放報文段後,發送確認報文ACK [第四次] 。而後進入到TIME-WAIT(時間等待)狀態(請注意:如今TCP鏈接尚未釋放掉。必須通過時間等待計時器設置的時間2MSL(MSL:最長報文段壽命)後,客戶端才進入到CLOSED狀態)。服務器收到ACK也就如到CLOSED狀態。
- 根據TCP協議搭建網絡連接
3.1 基於TCP通訊的服務模式
(1)首先搭建的網絡鏈接主要分爲兩部分:客戶端和服務器。
客戶端:搭建socket接口,經過connect去向服務器發起鏈接。
服務器:搭建socket接口,經過bind綁定IP,而後調用listen來進入監聽狀態。
(2)服務器收到並贊成客戶端接入後會創建TCP鏈接,而後雙方開始收發數據,收發時是雙向的,並且雙方都可發起,同時雙方都可發起關閉鏈接。
(3)常見的使用了TCP協議的網絡應用:http(至關於一個應用程序,用來傳輸文本信息)、ftp、QQ服務器和mail服務器。這些須要很高可靠的應用,底層都是基於TCP協議的。
3.2 經常使用的網絡編程函數
(1)socket:socket函數相似於open,用來打開一個網絡鏈接,若是成功則返回一個網絡文件描述符(int類型),以後咱們操做這個網絡鏈接都經過這個網絡文件描述符。
(2)bind:用來進行綁定的函數,把本地的IP地址和socket進行綁定。功能相似於fctrl函數,是用來改變屬性的函數。
(3)listen:監聽一個端口,監聽的是在bind時綁定的那個地址。
PS:端口號,實質就是一個數字編號,用來在咱們一臺主機中(主機的操做系統中)惟一的標識一個能上網的進程。端口號(精確到電腦中的某個進程)和IP地址(精確到某個電腦)一塊兒會被打包到當前進程發出或者接收到的每個數據包中。每個數據包未來在網絡上傳遞的時候,內部都包含了發送方和接收方的信息(就是IP地址和端口號),因此IP地址和端口號這兩個每每是打包在一塊兒不分家的。
(4)accept:返回值是一個fd,accept正確返回就表示咱們已經和前來鏈接個人客戶端之間創建了一個TCP鏈接了,之後咱們就要經過這個鏈接來和客戶端進行讀寫操做,讀寫操做就須要一個fd,這個fd就由accept來返回了。(阻塞的位置)
PS:socket返回的fd叫作監聽fd,是用來監聽客戶端的,不能用來和任何客戶端進行讀寫;accept返回的fd叫作鏈接fd,用來和鏈接那端的客戶端程序進行讀寫。
(5)connect:用來鏈接服務器的(客戶端那邊用)。
(6)send/write:發送數據。(send比write就多了一個flag,只有支持一些特殊協議時會用到flag,普通狀況下用0便可)
(7)recv/read:接收數據。(在網絡中發送有點像是寫文件,在網絡中接收有點像是收文件)
(8)inet_aton:點分十進制轉換爲32位二進制形式。(inet_pton原理相同,只是支持IPv6)
(9)inet_ntoa:32位二進制轉換爲點分十進制。(inet_ntop原理相同,支持IPv6)
(10)inet_addr:先檢測本設備是大端仍是小端,而後自動轉爲大端模式。(在網絡編程中,默認都使用大端模式)
- 實現網絡通訊
(1)設計網絡通訊主要包括2個部分,一個是客戶端:負責去鏈接服務器。另外一個是服務器:負責監聽客戶端的鏈接並配合它。
(2)客戶端和服務器原則上均可以任意的發和收,可是實際上雙方必須配合:client發的時候server就收,而server發的時候client就收。可是client和server之間的通訊是異步的,因此須要依靠應用層協議來解決。
(3)規定鏈接創建後由客戶端主動向服務器發出1個請求數據包,而後服務器收到數據包後回覆客戶端一個迴應數據包,這就是一個通訊回合,整個鏈接的通訊就是由N多個回合組成的。同時雙發發送的數據包格式也要有必定要求。
下面以一個例子展現網絡編程:客戶端向服務器註冊學生的基本信息(發送一個數據包),服務器迴應一個數據包表示接收完成(展現學生的基本信息)。
客戶端代碼:client.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h> / See NOTES /
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#define SERADDR "192.168.1.104" // 服務器開放給咱們的IP地址和端口號
#define SERPORT 9003
//發送、接收緩衝區
char sendbuf[100];
char recvbuf[100];
#define CMD_REGISTER 1001 // 註冊學生信息
#define CMD_CHECK 1002 // 檢驗學生信息
#define CMD_GETINFO 1003 // 獲取學生信息
#define STAT_OK 30 // 回覆ok
#define STAT_ERR 31 // 回覆出錯了
typedef struct commu
{
char name[20]; // 學生姓名
int age; // 學生年齡
int cmd; // 命令碼
int stat; // 狀態信息,用來回復
}info;
int main(void)
{
int sockfd = -1, ret = -1;
//這個結構體是網絡編程接口中用來表示一個IP地址的,
//這個IP地址是兼容IPv4和IPv6的
struct sockaddr_in seraddr = {0};
struct sockaddr_in cliaddr = {0};
// 第1步:建立socket(AF_INET:使用IPv4進行通訊,SOCK_STREAM:TCP) sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("socket"); return -1; } printf("socketfd = %d.\n", sockfd); // 第2步:connect連接服務器,向結構體填充服務器信息 seraddr.sin_family = AF_INET; // 設置地址族爲IPv4 seraddr.sin_port = htons(SERPORT); // 設置地址的端口號信息(檢測大小端並調整) seraddr.sin_addr.s_addr = inet_addr(SERADDR); // 設置IP地址 ret = connect(sockfd, (const struct sockaddr *)&seraddr, sizeof(seraddr)); if (ret < 0) { perror("connect"); return -1; } printf("成功創建鏈接\n"); while (1) { // 回合中第1步:客戶端給服務器發送信息 info st1; printf("請輸入學生姓名\n"); scanf("%s", st1.name); printf("請輸入學生年齡"); scanf("%d", &st1.age); st1.cmd = CMD_REGISTER; ret = send(sockfd, &st1, sizeof(info), 0); printf("已發送%s學生的信息\n",st1.name); // 回合中第2步:客戶端接收服務器的回覆 memset(&st1, 0, sizeof(st1)); ret = recv(sockfd, &st1, sizeof(st1), 0); // 回合中第3步:客戶端解析服務器的回覆,再作下一步定奪 if (st1.stat == STAT_OK) { printf("註冊學生信息成功\n"); } else { printf("註冊學生信息失敗\n"); } } return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
服務器端代碼:server.c
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h> / See NOTES /
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#define SERPORT 9003
#define SERADDR "192.168.1.104" // ifconfig看到的
#define BACKLOG 100 //貌似是最大能容納的鏈接數
char recvbuf[100];
#define CMD_REGISTER 1001 // 註冊學生信息
#define CMD_CHECK 1002 // 檢驗學生信息
#define CMD_GETINFO 1003 // 獲取學生信息
#define STAT_OK 30 // 回覆ok
#define STAT_ERR 31 // 回覆出錯了
typedef struct commu
{
char name[20]; // 學生姓名
int age; // 學生年齡
int cmd; // 命令碼
int stat; // 狀態信息,用來回復
}info;
int main(void)
{
int sockfd = -1, ret = -1, clifd = -1;
socklen_t len = 0;
//這裏的結構爲sockaddr_in結構體包含sin_port和sin_addr結構體,sin_addr結構體包含s_addr
struct sockaddr_in seraddr = {0};
struct sockaddr_in cliaddr = {0};
// 第1步:先socket打開文件描述符 sockfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == sockfd) { perror("socket"); return -1; } printf("socketfd = %d.\n", sockfd); // 第2步:bind綁定sockefd和當前電腦的ip地址&端口號 seraddr.sin_family = AF_INET; // 設置地址族爲IPv4 seraddr.sin_port = htons(SERPORT); // 設置地址的端口號信息 seraddr.sin_addr.s_addr = inet_addr(SERADDR); // 設置IP地址 ret = bind(sockfd, (const struct sockaddr *)&seraddr, sizeof(seraddr)); if (ret < 0) { perror("bind"); return -1; } printf("bind success.\n"); // 第3步:listen監聽端口 ret = listen(sockfd, BACKLOG); // 阻塞等待客戶端來鏈接服務器 if (ret < 0) { perror("listen"); return -1; } // 第4步:accept阻塞等待客戶端接入 clifd = accept(sockfd, (struct sockaddr *)&cliaddr, &len); printf("鏈接已經創建,client fd = %d.\n", clifd); // 客戶端反覆給服務器發 while (1) { info st; // 回合中第1步:服務器收 ret = recv(clifd, &st, sizeof(info), 0); // 回合中第2步:服務器解析客戶端數據包,而後幹活, if (st.cmd == CMD_REGISTER) { printf("用戶要註冊學生信息\n"); printf("學生姓名:%s,學生年齡:%d\n", st.name, st.age); // 在這裏服務器要進行真正的註冊動做,通常是插入數據庫一條信息 // 回合中第3步:回覆客戶端 st.stat = STAT_OK; ret = send(clifd, &st, sizeof(info), 0); } } return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
在這裏插入圖片描述
關注博主便可閱讀全文
點贊
2
評論
3
分享
收藏
7
打賞
舉報
關注
一鍵三連
Python-深度學習-學習筆記(13):keras搭建卷積神經網絡(對二維數據進行一維卷積)qq_42826337的博客1萬+Python-深度學習-學習筆記(13):keras搭建卷積神經網絡(對二維數據進行一維卷積) 卷積神經網絡進行圖像分類是深度學習關於圖像處理的一個應用,卷積神經網絡的優勢是可以直接與圖像像素進行卷積,從圖像像素中提取圖