網路編程圖
⑴ 網路編程(五)TCP詳解
考慮最簡單的情況:兩台主機之間的通信。這個時候只需要一條網線把兩者連起來,規定好彼此的硬體介面,如都用 USB、電壓 10v、頻率 2.4GHz 等, 這一層就是物理層,這些規定就是物理層協議 。
我們當然不滿足於只有兩台電腦連接,因此我們可以使用交換機把多個電腦連接起來,如下圖:
這樣連接起來的網路,稱為區域網,也可以稱為乙太網(乙太網是區域網的一種)。在這個網路中,我們需要標識每個機器,這樣才可以指定要和哪個機器通信。這個標識就是硬體地址 MAC。
硬體地址隨機器的生產就被確定,永久性唯一。在區域網中,我們需要和另外的機器通信時,只需要知道他的硬體地址,交換機就會把我們的消息發送到對應的機器。
這里我們可以不管底層的網線介面如何發送,把物理層抽離,在他之上創建一個新的層次,這就是 數據鏈路層 。
我們依然不滿足於區域網的規模,需要把所有的區域網聯系起來,這個時候就需要用到路由器來連接兩個區域網:
但是如果我們還是使用硬體地址來作為通信對象的唯一標識,那麼當網路規模越來越大,需要記住所有機器的硬體地址是不現實的;
同時,一個網路對象可能會頻繁更換設備,這個時候硬體地址表維護起來更加復雜。這里使用了一個新的地址來標記一個網路對象: IP 地址 。
通過一個簡單的寄信例子來理解 IP 地址。
我住在北京市,我朋友 A 住在上海市,我要給朋友 A 寫信:
因此,這里 IP 地址就是一個網路接入地址(朋友 A 的住址),我只需要知道目標 IP 地址,路由器就可以把消息給我帶到。 在區域網中,就可以動態維護一個 MAC 地址與 IP 地址的映射關系,根據目的 IP 地址就可以尋找到機器的 MAC 地址進行發送 。
這樣我們不需管理底層如何去選擇機器,我們只需要知道 IP 地址,就可以和我們的目標進行通信。這一層就是 網路層 。網路層的核心作用就是 提供主機之間的邏輯通信 。
這樣,在網路中的所有主機,在邏輯上都連接起來了,上層只需要提供目標 IP 地址和數據,網路層就可以把消息發送到對應的主機。
一個主機有多個進程,進程之間進行不同的網路通信,如邊和朋友開黑邊和女朋友聊微信。我的手機同時和兩個不同機器進行通信。
那麼當我的手機收到數據時,如何區分是微信的數據,還是王者的數據?那麼就必須在網路層之上再添加一層: 運輸層 :
運輸層通過 socket(套接字),將網路信息進行進一步的拆分,不同的應用進程可以獨立進行網路請求,互不幹擾。
這就是運輸層的最本質特點: 提供進程之間的邏輯通信 。這里的進程可以是主機之間,也可以是同個主機,所以在 android 中,socket 通信也是進程通信的一種方式。
現在不同的機器上的應用進程之間可以獨立通信了,那麼我們就可以在計算機網路上開發出形形式式的應用:如 web 網頁的 http,文件傳輸 ftp 等等。這一層稱為 應用層 。
應用層還可以進一步拆分出表示層、會話層,但他們的本質特點都沒有改變: 完成具體的業務需求 。和下面的四層相比,他們並不是必須的,可以歸屬到應用層中。
最後對計網分層進行小結:
這里需要注意的是,分層並不是在物理上的分層,而是邏輯上的分層。通過對底層邏輯的封裝,使得上層的開發可以直接依賴底層的功能而無需理會具體的實現,簡便了開發。
這種分層的思路,也就是責任鏈設計模式,通過層層封裝,把不同的職責獨立起來,更加方便開發、維護等等。
TCP 並不是把應用層傳輸過來的數據直接加上首部然後發送給目標,而是把數據看成一個位元組 流,給他們標上序號之後分部分發送。這就是 TCP 的 面向位元組流 特性:
面向位元組流的好處是無需一次存儲過大的數據佔用太多內存,壞處是無法知道這些位元組代表的意義,例如應用層發送一個音頻文件和一個文本文件,對於 TCP 來說就是一串位元組流,沒有意義可言,這會導致粘包以及拆包問題,後面講。
前面講到,TCP 是可靠傳輸協議,也就是,一個數據交給他,他肯定可以完整無誤地發送到目標地址,除非網路炸了。他實現的網路模型如下:
對於應用層來說,他就是一個可靠傳輸的底層支持服務;而運輸層底層採用了網路層的不可靠傳輸。雖然在網路層甚至數據鏈路層就可以使用協議來保證數據傳輸的可靠性,但這樣網路的設計會更加復雜、效率會隨之降低。把數據傳輸的可靠性保證放在運輸層,會更加合適。
可靠傳輸原理的重點總結一下有: 滑動窗口、超時重傳、累積確認、選擇確認、連續 ARQ 。
停止等待協議
要實現可靠傳輸,最簡便的方法就是:我發送一個數據包給你,然後你跟我回復收到,我繼續發送下一個數據包。傳輸模型如下:
這種「一來一去」的方法來保證傳輸可靠就是 停止等待協議 (stop-and-wait)。不知道還記不記得前面 TCP 首部有一個 ack 欄位,當他設置為 1 的時候,表示這個報文是一個確認收到報文。
然後再來考慮另一種情況:丟包。網路環境不可靠,導致每一次發送的數據包可能會丟失,如果機器 A 發送了數據包丟失了,那麼機器 B 永遠接收不到數據,機器 A 永遠在等待。
解決這個問題的方法是: 超時重傳 。當機器 A 發出一個數據包時便開始計時,時間到還沒收到確認回復,就可以認為是發生了丟包,便再次發送,也就是重傳。
但重傳會導致另一種問題:如果原先的數據包並沒有丟失,只是在網路中待的時間比較久,這個時候機器 B 會受到兩個數據包,那麼機器 B 是如何辨別這兩個數據包是屬於同一份數據還是不同的數據?
這就需要前面講過的方法: 給數據位元組進行編號 。這樣接收方就可以根據數據的位元組編號,得出這些數據是接下來的數據,還是重傳的數據。
在 TCP 首部有兩個欄位:序號和確認號,他們表示發送方數據第一個位元組的編號,和接收方期待的下一份數據的第一個位元組的編號。
停止等待協議的優點是簡單,但缺點是 信道利用率 太低。
假定AB之間有一條直通的信道來傳送分組
這里的TD是A發送分組所需要的時間(顯然TD = 分組長度 / 數據速率)再假定TA是B發送確認分組所需要的時間(A和B處理分組的時間都忽略不計)那麼A在經過TD+RTT+TA時間後才能發送下一個分組,這里的RTT是往返時間,因為只有TD是採用來傳輸有用的數據(這個數據包括了分組首部,如果可以知道傳輸更精確的數據的時間,可以計算的更精確),所有信道利用率為
為了提高傳輸效率,發送方可以不使用低效率的停止等待協議,而是採用 流水線傳輸 :就是發送方可以 連續的發送多個分組 ,不必每發完一個分組就停下來等待對方的確認。這樣可使信道上一直有數據不間斷地在傳送。顯然這種傳輸方式可以獲得很高的信道利用率
停止等待協議已經可以滿足可靠傳輸了,但有一個致命缺點: 效率太低 。發送方發送一個數據包之後便進入等待,這個期間並沒有干任何事,浪費了資源。解決的方法是: 連續發送數據包 。
也就是下面介紹的 連續ARQ協議 和 滑動窗口協議
連續 ARQ 協議
模型如下:
和停止等待最大的不同就是,他會源源不斷地發送,接收方源源不斷收到數據之後,逐一進行確認回復。這樣便極大地提高了效率。但同樣,帶來了一些額外的問題:
發送是否可以無限發送直到把緩沖區所有數據發送完?不可以。因為需要考慮接收方緩沖區以及讀取數據的能力。如果發送太快導致接收方無法接受,那麼只是會頻繁進行重傳,浪費了網路資源。所以發送方發送數據的范圍,需要考慮到接收方緩沖區的情況。這就是 TCP 的 流量控制 。
解決方法是: 滑動窗口 。基本模型如下:
在 TCP 的首部有一個窗口大小欄位,他表示接收方的剩餘緩沖區大小,讓發送方可以調整自己的發送窗口大小。通過滑動窗口,就可以實現 TCP 的流量控制,不至於發送太快,導致太多的數據丟失。
連續 ARQ 帶來的第二個問題是:網路中充斥著和發送數據包一樣數據量的確認回復報文,因為每一個發送數據包,必須得有一個確認回復。提高網路效率的方法是: 累積確認 。
接收方不需要逐個進行回復,而是累積到一定量的數據包之後,告訴發送方,在此數據包之前的數據全都收到。例如,收到 1234,接收方只需要告訴發送方我收到 4 了,那麼發送方就知道 1234 都收到了。
第三個問題是:如何處理丟包情況。在停止等待協議中很簡單,直接一個超時重傳就解決了。但,連續 ARQ 中不太一樣。
例如:接收方收到了 123 567,六個位元組,編號為 4 的位元組丟失了。按照累積確認的思路,只能發送 3 的確認回復,567 都必須丟掉,因為發送方會進行重傳。這就是 GBN(go-back-n) 思路。
但是我們會發現,只需要重傳 4 即可,這樣不是很浪費資源,所以就有了: 選擇確認 SACK 。在 TCP 報文的選項欄位,可以設置已經收到的報文段,每一個報文段需要兩個邊界來進行確定。這樣發送方,就可以根據這個選項欄位只重傳丟失的數據了。
第四個問題是:擁塞控制的問題
也是通過窗口的大小來控制的,但是檢測網路滿不滿是個挺難的事情,所以 TCP 發送包經常被比喻成往誰管理灌水,所以擁塞控制就是在不堵塞,不丟包的情況下盡可能的發揮帶寬。
水管有粗細,網路有帶寬,即每秒鍾能發送多少數據;水管有長度,端到端有時延。理想狀態下,水管裡面的水 = 水管粗細 * 水管長度。對於網路上,通道的容量 = 帶寬 * 往返時延。
如果我們設置發送窗口,使得發送但未確認的包為通道的容量,就能撐滿整個管道。
如圖所示,假設往返時間為 8 秒,去 4 秒,回 4 秒,每秒發送一個包,已經過去了 8 秒,則 8 個包都發出去了,其中前四個已經到達接收端,但是 ACK 還沒返回,不能算發送成功,5-8 後四個包還在路上,還沒被接收,這個時候,管道正好撐滿,在發送端,已發送未確認的 8 個包,正好等於帶寬,也即每秒發送一個包,也即每秒發送一個包,乘以來回時間 8 秒。
如果在這個基礎上調大窗口,使得單位時間可以發送更多的包,那麼會出現接收端處理不過來,多出來的包會被丟棄,這個時候,我們可以增加一個緩存,但是緩存裡面的包 4 秒內肯定達不到接收端課,它的缺點會增加時延,如果時延達到一定程度就會超時重傳
TCP 擁塞控制主要來避免兩種現象,包丟失和超時重傳,一旦出現了這些現象說明發送的太快了,要慢一點。
具體的方法就是發送端慢啟動,比如倒水,剛開始倒的很慢,漸漸變快。然後設置一個閾值,當超過這個值的時候就要慢下來
慢下來還是在增長,這時候就可能水滿則溢,出現擁塞,需要降低倒水的速度,等水慢慢滲下去。
擁塞的一種表現是丟包,需要超時重傳,這個時候,採用快速重傳演算法,將當前速度變為一半。所以速度還是在比較高的值,也沒有一夜回到解放前。
到這里關於 TCP 的可靠傳輸原理就已經介紹得差不多。最後進行一個小結:
當然,這只是可靠傳輸的冰山一角,感興趣可以再深入去研究
⑵ 基於matlab或C#的神經網路編程
1.人工神經元( Artificial Neuron )模型
人工神經元是神經網路的基本元素,其原理可以用下圖表示:

若神經元的凈激活net為正,稱該神經元處於激活狀態或興奮狀態(fire),若凈激活net為負,則稱神經元處於抑制狀態。
圖1中的這種「閾值加權和」的神經元模型稱為M-P模型( McCulloch-Pitts Model ),也稱為神經網路的一個處理單元( PE, Processing Element )。
⑶ 2018-04-23網路編程-概述-SOCKET-埠綁定-編碼解碼
計算機都遵守的網路通信協議叫做TCP/IP協議。
因為互聯網協議包含了上百種協議標准,但是最重要的兩個協議是TCP和IP協議,所以,大家把互聯網的協議簡稱TCP/IP協議。是一組協議族。完成通信的規范。
四種分類法和其中分類法:
埠號:用來標記唯一一個進程(范圍:0~65535)
為什麼不用pid?——在一個操作系統上,pid絕對不相同,而且進程pid唯一,但在不同系統上,獲取另一個系統的pid特別費勁;但是埠對應的程序是確定的,所以埠就是用來區分進程的
埠號只有整數,0~65535。能區分同一伺服器所有進程
知名埠:大家都知道的默認的埠,比如網路,0~1023
動態埠:1024~65535之間
查看埠信息的命令:netstat - an
IP地址的作用:用來標記一台電腦在網路中的數字。
同一區域網中,IP地址不能相同
網路號用來分辨不同網路,主機號用來區分不同主機
ip地址:用來在網路中標記一台電腦的一串數字,比如192.168.1.1;在本地區域網上是惟一的。
什麼是socket?
socket(簡稱 套接字 ) 是進程間通信的一種方式,它與其他進程間通信的一個主要不同是:
它能實現不同主機間的進程間通信,我們網路上各種各樣的服務大多都是基於 Socket 來完成通信的(能完成多個電腦進程間的通信)
例如我們每天瀏覽網頁、QQ 聊天、收發 email 等等。
UDP快,不穩定
TCP慢,穩定
會變的埠號
說明:
每重新運行一次網路程序,上圖中紅圈中的數字,不一樣的原因在於,這個數字標識這個網路程序,當重新運行時,如果沒有確定到底用哪個,系統默認會隨機分配
記住一點:這個網路程序在運行的過程中,這個就唯一標識這個程序,所以如果其他電腦上的網路程序如果想要向此程序發送數據,那麼就需要向這個數字(即埠)標識的程序發送即可。
UDP綁定信息
一般服務性的程序,往往需要一個固定的埠號,這就是所謂的埠綁定
綁定的意義是使其不變 。
*一個電腦可以有多個IP地址
*單工:收音機 半雙工:對講機 全雙工:電話
UDP和TPC(網路)都是全雙工,同一時間能發能收
一般,接收方都需要綁定,發送方不需要綁定
綁定示例:
總結
一個udp網路程序,可以不綁定,此時操作系統會隨機進行分配一個埠,如果重新運行次程序埠可能會發生變化
一個udp網路程序,也可以綁定信息(ip地址,埠號),如果綁定成功,那麼操作系統用這個埠號來進行區別收到的網路數據是否是此進程的
*解包:
⑷ 代碼編程——ping命令流程(圖)
不是我寫的,找的。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define WIN32_LEAN_AND_MEAN
#include <winsock.h>
#pragma comment(lib, "Wsock32.lib")
#define ICMP_ECHO 8
#define ICMP_ECHOREPLY 0
//#define ICMP_MIN 8 // minimum 8 byte icmp packet (just header)
#define ICMP_MIN (8 + 4) // minimum 8 byte icmp packet (just header + timestamp)
// IP header
typedef struct _tagX_iphdr
{
unsigned char h_len:4; // length of the header
unsigned char version:4; // Version of IP
unsigned char tos; // Type of service
unsigned short total_len; // total length of the packet
unsigned short ident; // unique identifier
unsigned short frag_and_flags; // flags
unsigned char ttl; // ttl
unsigned char proto; // protocol (TCP, UDP etc)
unsigned short checksum; // IP checksum
unsigned int sourceIP;
unsigned int destIP;
}XIpHeader;
// ICMP header
typedef struct _tagX_icmphdr
{
unsigned char i_type;
unsigned char i_code;
unsigned short i_cksum;
unsigned short i_id;
unsigned short i_seq;
unsigned long i_timestamp;
}XIcmpHeader;
//puclic code
//網際校驗和生產演算法
//網際校驗和是被校驗數據16位值的反碼和(ones-complement sum)
unsigned short in_cksum(unsigned short* addr, int len)
{
int nleft = len;
int sum = 0;
unsigned short* w = addr;
unsigned short answer = 0;
while(nleft > 1) {
sum += *w++;
nleft -= 2;
}
if(nleft == 1) {
*(unsigned char*)(&answer) = *(unsigned char*)w;
sum += answer;
}
sum = (sum >> 16) + (sum & 0xffff);
sum += (sum >> 16);
answer = ~sum;
return (answer);
}
void fill_IcmpData(char *buf, int datasize)
{
if (buf)
{
char ch = 0;
char* icmpdata = buf + sizeof(XIcmpHeader);
fprintf(stdout, "(IcmpData)\r\n");
for (int i = 0; i < datasize; i++)
{
ch = 'A' + i%('z' - 'A');
*(icmpdata + i) = ch;
fprintf(stdout, "%c", ch);
}
fprintf(stdout, "\r\n");
}
}
void fill_IcmpHeader(char *buf, int datasize)
{
static unsigned short seq_no = 0;
XIcmpHeader *icmp_hdr = (XIcmpHeader *)buf;
if (icmp_hdr)
{
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_cksum = 0;
icmp_hdr->i_id = (unsigned short)GetCurrentProcessId();
icmp_hdr->i_seq = seq_no++;
icmp_hdr->i_timestamp = (unsigned long)::GetTickCount();
icmp_hdr->i_cksum = in_cksum((unsigned short*)buf, sizeof(XIcmpHeader) + datasize);
fprintf(stdout, "(IcmpHeader)\r\n");
fprintf(stdout, "%02X%02X%04X\r\n", icmp_hdr->i_type, icmp_hdr->i_code, icmp_hdr->i_cksum);
fprintf(stdout, "%04X%04X\r\n", icmp_hdr->i_id, icmp_hdr->i_seq);
fprintf(stdout, "%08X\r\n", icmp_hdr->i_timestamp);
}
}
// decode
void decode_IpIcmp(char *buf, int size)
{
XIpHeader *ip_hdr = (XIpHeader *)buf;
unsigned short iphdrlen;
if (ip_hdr)
{
fprintf(stdout, "(IpHeader)\r\n");
fprintf(stdout, "%01X%01X%02X%04X\r\n", ip_hdr->version, ip_hdr->h_len, ip_hdr->tos, ip_hdr->total_len);
fprintf(stdout, "%04X%04X\r\n", ip_hdr->ident, ip_hdr->frag_and_flags);
fprintf(stdout, "%02X%02X%04X\r\n", ip_hdr->ttl, ip_hdr->proto, ip_hdr->checksum);
//iphdrlen = ip_hdr->h_len * 4; // number of 32-bit words *4 = bytes
iphdrlen = ip_hdr->h_len << 2; // number of 32-bit words *4 = bytes
fprintf(stdout, "(IcmpHeader)\r\n");
if (size < iphdrlen + ICMP_MIN)
{
fprintf(stdout, "Reply %d bytes Too few\r\n", size);
}
else
{
XIcmpHeader *icmp_hdr = (XIcmpHeader *)(buf + iphdrlen);
fprintf(stdout, "%02X%02X%04X\r\n", icmp_hdr->i_type, icmp_hdr->i_code, icmp_hdr->i_cksum);
fprintf(stdout, "%04X%04X\r\n", icmp_hdr->i_id, icmp_hdr->i_seq);
fprintf(stdout, "%08X\r\n", icmp_hdr->i_timestamp);
unsigned long timestamp = 0;
timestamp = (unsigned long)::GetTickCount();
timestamp -= icmp_hdr->i_timestamp;
struct sockaddr_in from;
from.sin_addr.s_addr = ip_hdr->sourceIP;
fprintf(stdout, "Reply %d bytes from: %s time<%d TTL=%d icmp_seq=%d\r\n",
size,
inet_ntoa(from.sin_addr),
timestamp,
ip_hdr->ttl,
icmp_hdr->i_seq
);
}
}
}
int main(int argc, char **argv)
{
int ret = 0;
WSADATA ws;
WSAStartup(0x0101,&ws);
int iIcmpDataSize = 0;
struct sockaddr_in dest,from;
unsigned int addr = 0;
struct hostent *hp;
char buffer[1024];
char recv_buffer[1024];
if(argc < 2)
{
fprintf(stderr, "Usage: %s [host|ip] [datasize]\r\n", argv[0]);
return 0;
}
if (argc > 2)
iIcmpDataSize = atoi(argv[2]);
if (iIcmpDataSize < 1 || iIcmpDataSize > 1024)
iIcmpDataSize = 10;
memset(&dest, 0, sizeof dest);
dest.sin_family = AF_INET;
hp = gethostbyname(argv[1]);
if (!hp)
addr = inet_addr(argv[1]);
if ((!hp) && (addr == INADDR_NONE))
{
fprintf(stderr,"Unable to resolve %s\r\n",argv[1]);
return 0;
}
if (hp != NULL)
memcpy(&(dest.sin_addr), hp->h_addr,hp->h_length);
else
dest.sin_addr.s_addr = addr;
int sockfd;
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
fprintf(stdout, "XPing...\r\n");
for (int i = 0; i < 3; i++)
{
fprintf(stdout, "Echo...\r\n");
memset(buffer, 0, 1024);
fill_IcmpData(buffer, iIcmpDataSize);
fill_IcmpHeader(buffer, iIcmpDataSize);
XIcmpHeader *icmp_hdr = (XIcmpHeader *)buffer;
int iSendSize = sendto(sockfd, buffer, sizeof(XIcmpHeader) + iIcmpDataSize, 0, (struct sockaddr*)&dest, sizeof(dest));
fprintf(stdout, "Reply...\r\n");
memset(&from, 0, sizeof from);
memset(recv_buffer, 0, 1024);
int fromlen = sizeof(from);
int iRecvSize = recvfrom(sockfd, recv_buffer, 1024, 0, (struct sockaddr*)&from, &fromlen);
if (iRecvSize > 0)
decode_IpIcmp(recv_buffer, iRecvSize);
}
WSACleanup();
return ret;
}
⑸ 網路編程(一)之HTML
這段時間學習了網頁的基礎知識,考慮到知識點內容比較多,為了方便記憶,我還是記下來,方便日後總結。
這里我學習的方式通過黑馬pink老師的教學視頻學習。
Web 標準是由 W3C 組織和其他標准化組織制定的 一系列標準的集合 。W3C(萬維網聯盟)是國際最著名的標准化組織。
Web標準的構成
主要包括 結構(Structure) , 表現(Presentation) , 行為(Behavior) 三個方面。
結構 : 結構用於對網頁元素進行整理和分類,現階段主要學的是HTML。
表現 : 表現用於設置網頁元素的版式,顏色、大小等外觀樣式,主要指的CSS
行為 :行為是指網頁模式的定義及交互的編寫,現階段主要學的是JavaScript
HTML分為雙標簽( <html> 和 </html> ),以及單標簽( <br/> ), 這種情況出現的概率不大。
這里主要分三個部分:
為了使網頁更具有語義化,我們經常會在頁面中用到標題標簽。HTML 提供了 6 個等級的網頁標題, 即 <h1> - <h6> , 數字越小字體越粗越大。
在網頁中,要把文字有條理地顯示出來,就需要將這些文字分段顯示。在 HTML 標簽中, <p> 標簽用於 定義段落 ,它可以將整個網頁分為若干個段落。
特點:
在 HTML 中,一個段落中的文字會從左到右依次排列,直到瀏覽器窗口的右端,然後才自動換行。如果希望 某段文本強制換行顯示,就需要使用換行標簽 <br /> 。
特點:
<div> 標簽用來布局,一行只能放一個 <div> ,大盒子
<span> 標簽用來布局, 一行可以放多個 <span> ,小盒子
當我們點擊某個連接可以快速定位頁面中的某個位置
列表標簽主要分為三個類別分別是: 無序標簽 , 有序標簽 和 自定義標簽 。
表單主要為了 收集用戶信息 , 在 HTML 中,一個完整的表單通常由 表單域 、 表單控制項(也稱為表單元素) 和 提示信息 3個部分構成。
(1) 表單域
表單域 是一個 包含表單元素的區域 , 在HTML標簽中, <form> 標簽用於定義表單域,以實現用戶信息收集和傳遞。
action 用於制定url地址
method 用於設置表單數據提交方式,是 get 還是 post
name 用於制定表單的名稱,以區分同一個頁面的多個表單域
(2)表單控制項
表單控制項分為三個 input , label , select , textarea
【1】 input (這里注意為單標簽)
<input type="屬性值" />
這里的type有一下屬性:
button 定義可點擊按鈕, 多數情況可通過JavaScript啟動腳本
checkbox 定義復選框
file 定義輸入欄位和瀏覽按鈕,供文件上傳, 可以有界面的選擇文件
hidden 定義隱藏的輸入欄位
image 定義圖像形式的提交按鈕
password 定義密碼欄位, 該欄位中的字元被掩碼
radio 定義單選按鈕
reset 定義重置按鈕, 重置按鈕會清除表單中的所有數據
submit 定義提交按鈕,提交按鈕會把表單數據發送給伺服器
text 定義單行的輸入欄位,用戶可在其中輸入文本,默認寬度為20個字元
這里除了 input 外還有其他標簽,如下所示:
name 定義input元素的名稱, 對於單選/復選框必須有相同的名字才能支持單選功能
value 規定input元素的值, 可以給value一個默認的值
checked 規定此input元素首次載入時應當被選中
maxmargin 規定在輸入欄位的字元最大長度
【2】label標簽
<label> 標簽用於綁定一個表單元素, 當點擊 <label> 標簽內的文本時,瀏覽器就會自動將焦點(游標)轉到或者
選擇對應的表單元素上,用來增加用戶體驗, 如下我滑鼠點擊 男 , 相當於 sex 這個單選按鈕
【3】select標簽
在頁面中,如果有多個選項讓用戶選擇,並且想要節約頁面空間時,我們可以使用 <select> 標簽控制項定義下拉列表( <option> 中定義 selected =「 selected " 時,當前項即為默認選中項。 )
【4】textarea標簽
在表單元素中, <textarea> 標簽是用於定義多行文本輸入的控制項。 使用多行文本輸入控制項,可以輸入更多的文字,該控制項常見於留言板,評論。( rows 表示行數, cols 表示列數)
頁是圖片、鏈接、文字、聲音、視頻等元素組成, 其實就是一個html文件(後綴名為html) 網頁生成製作: 有前端人員書寫 HTML 文件, 然後瀏覽器打開,就能看到了網頁.
HTML: 超文本標記語言, 用來製作網頁的一門語言. 有標簽組成的. 比如 圖片標簽 鏈接標簽 視頻標簽等...
⑹ Python網路編程6-使用Pysnmp實現簡單網管
簡單網路管理協議SNMP(Simple Network Management Protocol)用於網路設備的管理。SNMP作為廣泛應用於TCP/IP網路的網路管理標准協議,提供了統一的介面,從而實現了不同種類和廠商的網路設備之間的統一管理。
SNMP協議分為三個版本:SNMPv1、SNMPv2c和SNMPv3。
SNMP系統由網路管理系統NMS(Network Management System)、SNMP Agent、被管對象Management object和管理信息庫MIB(Management Information Base)四部分組成。
SNMP查詢是指NMS主動向SNMP Agent發送查詢請求,如圖1-3所示。SNMP Agent接收到查詢請求後,通過MIB表完成相應指令,並將結果反饋給NMS。SNMP查詢操作有三種:Get、GetNext和GetBulk。SNMPv1版本不支持GetBulk操作。
不同版本的SNMP查詢操作的工作原理基本一致,唯一的區別是SNMPv3版本增加了身份驗證和加密處理。下面以SNMPv2c版本的Get操作為例介紹SNMP查詢操作的工作原理。假定NMS想要獲取被管理設備MIB節點sysContact的值,使用可讀團體名為public,過程如下所示:
SNMP設置是指NMS主動向SNMP Agent發送對設備進行Set操作的請求,如下圖示。SNMP Agent接收到Set請求後,通過MIB表完成相應指令,並將結果反饋給NMS。
不同版本的SNMP Set操作的工作原理基本一致,唯一的區別是SNMPv3版本增加了身份驗證和加密處理。下面以SNMPv3版本的Set操作為例介紹SNMP Set操作的工作原理。
假定NMS想要設置被管理設備MIB節點sysName的值為HUAWEI,過程如下所示:
SNMPv1和SNMPv2c的Set操作報文格式如下圖所示。一般情況下,SNMPv3的Set操作信息是經過加密封裝在SNMP PDU中,其格式與SNMPv2c的Set操作報文格式一致。
SNMP Traps是指SNMP Agent主動將設備產生的告警或事件上報給NMS,以便網路管理員及時了解設備當前運行的狀態。
SNMP Agent上報SNMP Traps有兩種方式:Trap和Inform。SNMPv1版本不支持Inform。Trap和Inform的區別在於,SNMP Agent通過Inform向NMS發送告警或事件後,NMS需要回復InformResponse進行確認。
在Ensp中搭建網路環境,在R2上啟用SNMP作為SNMP agent,Linux主機作為NMS;為方便觀察SNMP報文格式,在R2使用SNMP的版本為v2c。
通過下面的Python腳本獲取R2的系統信息與當前的主機名
運行結果如下
在R2介面上抓包結果如下,Linux主機向R2的161埠發送SNMP get-request報文,可以看到SNMP使用的版本為v2c,設置的團體名為public,隨機生成了一個request-id,變數綁定列表(Variable bindings),即要查詢的OID,但Value為空;值得注意的是這些信息都是明文傳輸的,為了安全在實際環境中應使用SNMPv3。
通過下面的Python腳本獲取R2的介面信息。
運行結果如下:
在R2介面抓包結果如下,getBuikRequest相比get-request設置了一個max-repetitions欄位,表明最多執行get操作的次數。Variable bindings中請求的OID條目只有一條。
下面Python腳本用於設置R2的主機名為SNMPv2R2。
運行結果如下
在路由器上可以看到主機名有R2變為了SNMPv2R2。
get-response數據包內容與set-request中無異。
下面Python腳本用於接收,R2發送的Trap,並做簡單解析。
先運行該腳本,之後再R2上手動將一個介面shutdown,結果如下:
介面上抓包結果如下,此時團體名用的是public,data部分表明是trap。
由於Ensp中的通用路由器認證演算法只支持des56,而pysnmp不支持該演算法,因此使用AR路由器配置SNMPv3。
使用下面Python腳本發送snmpv3 get報文獲取設備系統信息。
抓包結果如下,首先發送get-resques進行SNMPv3認證請求,隨機生成一個msgID,認證模式為USM,msgflgs中Reportable置1要求對方發送report,其他為置0,表示不進行加密與鑒權;另外安全參數,認證參數、加密參數都為空,此時不攜帶get請求數據。
路由器給NMS回復report,msgID與resquest一致,Msgflgs中各位都置0,同時回復使用的安全引擎,認證與加密參數為空,不進行認證與加密,因此能看到data中的數據。
AR1收到請求後進行回復,數據包中msgflags標志位中除reportable外其他位都置1,表示不需要回復,同時進行加密與鑒權。同樣也可以看到認證用戶為testuser,認證參數與加密參數都有填充,data部分也是同樣加密。
參考:
什麼是SNMP - 華為 (huawei.com)
AR100-S V300R003 MIB參考 - 華為 (huawei.com)
SNMP library for Python — SNMP library for Python 4.4 documentation (pysnmp.readthedocs.io)
