環境資訊中心綜合外電;姜唯 編譯;林大利 審校
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※台北網頁設計公司全省服務真心推薦
※想知道最厲害的網頁設計公司"嚨底家"!
※推薦評價好的iphone維修中心
※網頁設計最專業,超強功能平台可客製化
※別再煩惱如何寫文案,掌握八大原則!
摘錄自2020年5月27日中央社報導
「每日晨報」(Daily Sabah)報導,博斯普魯斯海峽(Bosporus)水色自26日起轉變成「土耳其藍」。伊斯坦堡科技大學(Istanbul Technical University)教授托羅斯(Huseyin Toros)認為,東北風是導致「海水變色」主要原因。
托羅斯指出:「單細胞生物被東北風曳引進入博斯普魯斯海峽,海水表面經過折射,轉變成土耳其藍色。在此一大氣環境下的氣流、海平面下的活動、不同微生物、白天陽光變化等因素也可能導致海水顏色產生變化。」他表示,海水將於幾天內恢復「本色」。
美國國家航空暨太空總署(NASA)的衛星於當年5月29日首度補捉到黑海浮游生物激增的圖像。漁夫們相信,海中出現大量浮游生物意味當年鯷魚產量將會大增。但是浮游生物也會消耗水中大量氧氣,從而對其他海洋生物造成傷害。
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
※回頭車貨運收費標準
摘錄自2020年5月27日中央社報導
印度北部最近出現熱浪,首都新德里昨(26日)測得攝氏47.5度,是10年來5月的最高溫;拉吉斯坦省楚魯鎮(Churu)昨天甚至出現印度最高溫,高達攝氏50度。
根據新德里氣象局資料顯示,新德里昨天出現溫度最高的是英蒂拉.甘地國際機場(Indira Gandhi International Airport)附近的巴拉姆(Palam)氣象站,測得攝氏47.5度,已被列入嚴重熱浪等級,至少是10年來新德里在5月的最高溫。
根據氣象資料,拉吉斯坦省西部、馬德雅省(Madhya Pradesh)西部和北部、哈雅納省(Haryana)南部、德里、北方省(Utter Prades)南部等都出現熱浪。
印度斯坦時報(Hindustan Times)引述氣象官員指出,高溫可能持續到本週末,之後可能有從西方來的高空擾動帶來降雨,才能在高溫下提供一些喘息。
生活環境
全球變遷
氣候變遷
國際新聞
印度
熱浪
歷史高溫
全球暖化
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※Google地圖已可更新顯示潭子電動車充電站設置地點!!
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※別再煩惱如何寫文案,掌握八大原則!
※網頁設計最專業,超強功能平台可客製化
※回頭車貨運收費標準
摘錄自2020年5月27日中央社報導
國際能源總署(IEA)今(27日)表示,因為疫情影響,能源業將面臨投資降幅創紀錄的窘境,其中再生能源的遭遇可能比石油好,但經濟快速復甦恐造成全球燃料短缺。
由於企業減支導致能源需求大減,國際能源總署在能源投資年度報告中預估,今年全球能源投資額恐比2019年大減1/5,相當於少了將近4000億美元。
國際能源總署執行董事比羅爾(Fatih Birol)接受法新社訪問時說:「石油、天然氣、再生能源等所有能源業都受到影響,但頁岩油受到的衝擊最大。」
國際能源總署預期,今年再生能源項目投資僅減少約10%。國際能源總署表示:「儘管2020年『乾淨能源』投資將減少,能源投資總額的占比卻上升。」
本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※想知道最厲害的網頁設計公司"嚨底家"!
※別再煩惱如何寫文案,掌握八大原則!
※產品缺大量曝光嗎?你需要的是一流包裝設計!
※回頭車貨運收費標準
※台中搬家公司費用怎麼算?
當我們寫printf("%d\n", 1);的時候,printf函數並不能通過C語言語法得知第二個參數是int類型。printf是一個變參函數(variadic function):
int printf(const char *restrict format, ...);
參數的類型都是通過格式串format推導出的。如果參數類型與格式串中指定的不匹配,或提供的參數數量少於需要的,將導致未定義行為。
由於參數類型是動態的,printf和scanf比靜態類型的std::cout和std::cin慢,前提是後者的眾多overhead被手動消除。
C為可變參數提供了va_start、va_arg、va_copy、va_end、va_list等工具,定義在頭文件<stdarg.h>中。va_arg用於取出參數,va_copy用於拷貝參數供多次使用。引用cppreference上的例子:
#include <stdio.h>
#include <stdarg.h>
#include <math.h>
double sample_stddev(int count, ...)
{
/* Compute the mean with args1. */
double sum = 0;
va_list args1;
va_start(args1, count);
va_list args2;
va_copy(args2, args1); /* copy va_list object */
for (int i = 0; i < count; ++i) {
double num = va_arg(args1, double);
sum += num;
}
va_end(args1);
double mean = sum / count;
/* Compute standard deviation with args2 and mean. */
double sum_sq_diff = 0;
for (int i = 0; i < count; ++i) {
double num = va_arg(args2, double);
sum_sq_diff += (num-mean) * (num-mean);
}
va_end(args2);
return sqrt(sum_sq_diff / count);
}
int main(void)
{
printf("%f\n", sample_stddev(4, 25.0, 27.3, 26.9, 25.7));
}
<stdio.h>還定義了vprintf系列函數,與不帶v的相比,可變參數...都換成了va_list的實例:
int vprintf(const char *format, va_list vlist);
可以藉此實現自己的printf。
可變參數在傳遞的過程中會被執行默認參數提升(default argument promotion),對於整數類型執行整數提升(提升為int或unsigned int),對於float類型提升成double。
格式串format中的普通字符直接拷貝到輸出流,由%引導的稱為轉換格式(conversion specification),在%和轉換說明符(conversion specifier)之間可以有若干修飾符,實現對齊、精度等功能,轉換說明符有c、s、d、f等,詳見cppreference。
單片機開發板並沒有可以用於輸出的控制台,printf調用最後都會歸結為_write函數:
int _write(int file, char* ptr, int len);
_write函數需要把ptr指向的len字節的數據以想要的形式發送,在此就沿用上一篇中的UART異步IO,於是printf就可以打印在串口上了。
為了方便日後使用,我把USART相關的代碼抽離出來放在一個新的源文件里,IDE生成的代碼去掉MX_USART1_UART_Init和USART1_IRQHandler兩個函數,再加上這一對文件就可以使用了。
usart1.h:
#include <stdio.h>
void MX_USART1_UART_Init();
void usart1_transmit(char c);
char usart1_receive();
usart1.c:
#include "usart1.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdlib.h>
#include "cmsis_gcc.h"
#include "stm32f4xx_hal.h"
typedef char queue_element_t;
typedef struct
{
uint16_t mask;
uint16_t head;
uint16_t tail;
queue_element_t data[0];
} queue_t;
static inline queue_t* queue_create(uint16_t _size)
{
if (_size & (_size - 1))
_size = 256;
queue_t* q = malloc(sizeof(queue_t) + _size * sizeof(queue_element_t));
if (q)
{
q->mask = _size - 1;
q->head = q->tail = 0;
}
return q;
}
static inline bool queue_empty(const queue_t* _queue)
{
return _queue->head == _queue->tail;
}
static inline uint16_t queue_size(const queue_t* _queue)
{
return (_queue->tail - _queue->head) & _queue->mask;
}
static inline uint16_t queue_capacity(const queue_t* _queue)
{
return _queue->mask;
}
static inline queue_element_t queue_peek(const queue_t* _queue)
{
return _queue->data[_queue->head];
}
static inline void queue_push(queue_t* _queue, const queue_element_t _ele)
{
_queue->data[_queue->tail] = _ele;
_queue->tail = (_queue->tail + 1) & _queue->mask;
}
static inline void queue_pop(queue_t* _queue)
{
_queue->head = (_queue->head + 1) & _queue->mask;
}
extern UART_HandleTypeDef huart1;
extern void Error_Handler();
queue_t* tx_buffer;
queue_t* rx_buffer;
void USART1_IRQHandler()
{
uint32_t isrflags = USART1->SR;
uint32_t cr1its = USART1->CR1;
uint32_t errorflags = 0x00U;
errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
if (errorflags == RESET)
{
if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
{
queue_push(rx_buffer, USART1->DR);
return;
}
if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
{
USART1->DR = queue_peek(tx_buffer);
queue_pop(tx_buffer);
if (queue_empty(tx_buffer))
USART1->CR1 &= ~USART_CR1_TXEIE & UART_IT_MASK;
return;
}
}
HAL_UART_IRQHandler(&huart1);
}
void MX_USART1_UART_Init()
{
tx_buffer = queue_create(1024);
rx_buffer = queue_create(1024);
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
USART1->CR1 |= USART_CR1_RXNEIE & UART_IT_MASK;
}
void usart1_transmit(char c)
{
uint16_t capacity = queue_capacity(tx_buffer);
bool ok = false;
while (1)
{
__disable_irq();
ok = capacity - queue_size(tx_buffer) >= 1;
if (ok)
break;
__enable_irq();
__NOP();
}
queue_push(tx_buffer, c);
USART1->CR1 |= USART_CR1_TXEIE & UART_IT_MASK;
__enable_irq();
}
char usart1_receive()
{
bool ok = false;
while (1)
{
__disable_irq();
ok = !queue_empty(rx_buffer);
if (ok)
break;
__enable_irq();
__NOP();
}
char c = queue_peek(rx_buffer);
queue_pop(rx_buffer);
__enable_irq();
return c;
}
int _write(int file, char* ptr, int len)
{
for (int i = 0; i != len; ++i)
usart1_transmit(*ptr++);
return len;
}
main.c(部分):
#include "main.h"
#include "usart1.h"
UART_HandleTypeDef huart1;
uint8_t count = 0;
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_USART1_UART_Init();
while (1)
{
printf("Hello world: %d\n", count);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
++count;
HAL_Delay(500);
}
}
明明已經用調試器連接了開發板和電腦,還要加個USB轉串口工具就顯得很累贅;IDE和串口監視器兩個窗口的頻繁切換也讓Alt和Tab鍵損壞的幾率增加了幾成。有沒有辦法讓開發板通過調試器和IDE就能輸出呢?
可以用ARM的ITM(Instrumentation Trace Macroblock),通過TRACESWO發送。SWO與JTAG的JTDIO是同一個引腳,用標準ST-LINK的20-pin排線可以連接,但是10-pin的簡版ST-LINK沒有引出SWO,因此要使用ITM調試不能用簡版的4線接法。
ITM無需初始化,直接調用ITM_SendChar函數即可發送,該函數定義在\Drivers\CMSIS\Include\core_cmx.h中。ITM版的_write函數,不過是把usart1_transmit換成ITM_SendChar而已。
#include "main.h"
#include <stdio.h>
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int _write(int file, char* ptr, int len)
{
for (int i = 0; i != len; ++i)
ITM_SendChar(*ptr++);
return len;
}
uint8_t count = 0;
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
while (1)
{
printf("Hello world: %d\n", count);
HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
++count;
HAL_Delay(500);
}
}
為了在IDE中看到printf輸出的內容,需要做幾步配置。首先進入Debug模式,在調試選項的Debugger頁啟用SWV:
找到SWV ITM Data Console窗口:
窗口右上角Configure trace,勾選Port 0:
點擊Start Trace。這樣就可以看見printf的輸出了:
好久沒更博客了。這兩周一直在做搖搖棒,硬件軟件交替着改,總算是做出一個比較穩定的显示效果了。計劃本月再更兩篇。
有一次下載器與搖搖棒的連接有鬆動,數據傳輸錯誤,導致熔絲位被修改,時鐘源選擇了不存在的,程序無法啟動,也無法下載新的程序。還好我帶着這塊STM32開發板,在一個引腳上產生一個較高頻率的方波,連接到單片機的晶振引腳,改回熔絲位,算是把單片機救活了。本來STM32開發板帶着是要寫這篇printf的,博客沒寫,倒是有救場的用途。
與printf相對的scanf,我也嘗試過實現,但是有兩個問題,一是我沒有找到在STM32CubeIDE中如何通過ITM向單片機發送,二是_read函數的len參數總是1024,這是想讓我一次性讀1024個字節再返回嗎?
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!
※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※教你寫出一流的銷售文案?
※別再煩惱如何寫文案,掌握八大原則!
文件和路徑有什麼關係?文件和路徑又隱藏了什麼秘密?在文件系統的管理下,創建路徑的方式又有哪些?今天F師兄帶小師妹再給大家來一場精彩的表演。
小師妹:F師兄我有一個問題,java中的文件File是一個類可以理解,因為文件裡面包含了很多其他的信息,但是路徑Path為什麼也要單獨一個類出來?只用一個String表示不是更簡單?
更多精彩內容且看:
更多內容請訪問www.flydean.com
萬物皆有因,沒有無緣無故的愛,也沒有無緣無故的恨。一切真的是妙不可言啊。
我們來看下File和path的定義:
public class File
implements Serializable, Comparable<File>
public interface Path
extends Comparable<Path>, Iterable<Path>, Watchable
首先,File是一個類,它表示的是所有的文件系統都擁有的屬性和功能,不管你是windows還是linux,他們中的File對象都應該是一樣的。
File中包含了Path,小師妹你且看,Path是一個interface,為什麼是一個interface呢?因為Path根據不同的情況可以分為JrtPath,UnixPath和ZipPath。三個Path所對應的FileSystem我們在上一篇文章中已經討論過了。所以Path的實現是不同的,但是包含Path的File是相同的。
小師妹:F師兄,這個怎麼這麼拗口,給我來一個直白通俗的解釋吧。
既然這樣,且聽我解釋:愛國版的,或許我們屬於不同的民族,但是我們都是中國人。通俗版的,大家都是文化人兒,為啥就你這麼拽。文化版的,同九年,汝何秀?
再看兩者的實現接口,File實現了Serializable表示可以被序列化,實現了Comparable,表示可以被排序。
Path繼承Comparable,表示可以被排序。繼承Iterable表示可以被遍歷,可以被遍歷是因為Path可以表示目錄。繼承Watchable,表示可以被註冊到WatchService中,進行監控。
小師妹:F師兄,File中有好幾個關於Path的get方法,能講一下他們的不同之處嗎?
直接上代碼:
public void getFilePath() throws IOException {
File file= new File("../../www.flydean.com.txt");
log.info("name is : {}",file.getName());
log.info("path is : {}",file.getPath());
log.info("absolutePath is : {}",file.getAbsolutePath());
log.info("canonicalPath is : {}",file.getCanonicalPath());
}
File中有三個跟Path有關的方法,分別是getPath,getAbsolutePath和getCanonicalPath。
getPath返回的結果就是new File的時候傳入的路徑,輸入什麼返回什麼。
getAbsolutePath返回的是絕對路徑,就是在getPath前面加上了當前的路徑。
getCanonicalPath返回的是精簡后的AbsolutePath,就是去掉了.或者..之類的指代符號。
看下輸出結果:
INFO com.flydean.FilePathUsage - name is : www.flydean.com.txt
INFO com.flydean.FilePathUsage - path is : ../../www.flydean.com.txt
INFO com.flydean.FilePathUsage - absolutePath is : /Users/flydean/learn-java-io-nio/file-path/../../www.flydean.com.txt
INFO com.flydean.FilePathUsage - canonicalPath is : /Users/flydean/www.flydean.com.txt
小師妹:F師兄,我記得路徑有相對路徑,絕對路徑等,是不是也有相應的創建Path的方法呢?
當然有的,先看下絕對路徑的創建:
public void getAbsolutePath(){
Path absolutePath = Paths.get("/data/flydean/learn-java-io-nio/file-path", "src/resource","www.flydean.com.txt");
log.info("absolutePath {}",absolutePath );
}
我們可以使用Paths.get方法傳入絕對路徑的地址來構建絕對路徑。
同樣使用Paths.get方法,傳入非絕對路徑可以構建相對路徑。
public void getRelativePath(){
Path RelativePath = Paths.get("src", "resource","www.flydean.com.txt");
log.info("absolutePath {}",RelativePath.toAbsolutePath() );
}
我們還可以從URI中構建Path:
public void getPathfromURI(){
URI uri = URI.create("file:///data/flydean/learn-java-io-nio/file-path/src/resource/www.flydean.com.txt");
log.info("schema {}",uri.getScheme());
log.info("default provider absolutePath {}",FileSystems.getDefault().provider().getPath(uri).toAbsolutePath().toString());
}
也可以從FileSystem構建Path:
public void getPathWithFileSystem(){
Path path1 = FileSystems.getDefault().getPath(System.getProperty("user.home"), "flydean", "flydean.txt");
log.info(path1.toAbsolutePath().toString());
Path path2 = FileSystems.getDefault().getPath("/Users", "flydean", "flydean.txt");
log.info(path2.toAbsolutePath().toString());
}
好多好多Path的創建方法,總有一款適合你。快來挑選吧。
本文的例子https://github.com/ddean2009/learn-java-io-nio
本文作者:flydean程序那些事
本文鏈接:http://www.flydean.com/java-io-file-path/
本文來源:flydean的博客
歡迎關注我的公眾號:程序那些事,更多精彩等着您!
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※台北網頁設計公司全省服務真心推薦
※想知道最厲害的網頁設計公司"嚨底家"!
※推薦評價好的iphone維修中心
※網頁設計最專業,超強功能平台可客製化
※別再煩惱如何寫文案,掌握八大原則!
《SpringBoot-2.3容器化技術》系列,旨在和大家一起學習實踐2.3版本帶來的最新容器化技術,讓咱們的Java應用更加適應容器化環境,在雲計算時代依舊緊跟主流,保持競爭力;
全系列文章分為主題和輔助兩部分,主題部分如下:
為了讓應用更適應容器化環境,SpringBoot2.3版本推出了新的探針技術,《掌握SpringBoot-2.3的容器探針》系列旨在與您一起學習和實踐這些新技術,分為三個階段:
如下圖紅框所示,2.3版本的容器探針特性早在預覽版(v2.3.0.M4)就已經發布:
如今v2.3.0.RELEASE已發布,可以放心的學習和使用該特性了,首先把基礎知識點列出來,確保準備工作OK;
下面是掌握探針技術所需的基礎知識,也是本文的主要內容:
接下來逐個學習,有了這些知識積累,我們才能更好的閱讀官方資料,開發適合自己業務場景的探針;
首先,SpringBoot為kubernetes提供了兩個actuator項,但是那些並未部署在kubernetes的SringBoot應用呢?用不上這兩項也要對外暴露這兩個服務地址嗎?
其次,就緒探針是什麼時候開始返回200返回碼的?應用啟動階段,業務服務可能需要一段時間才能正常工作,就緒探針要是提前返回了200,那k8s就認為容器可以正常工作了,這時候把外部請求調度過來是無法正常響應的,所以搞清楚就緒探針的狀態變化邏輯很重要;
最後,也是最重要的一點:有的場景下,例如外部依賴服務異常、本地全局異常等情況下,業務不想對外提供服務,等到問題解決后業務又可以對外提供服務了,如果此時我們能自己寫代碼控制就緒探針的返回碼,那就做到了控制kubernetes是否將外部請求調度到此容器上,這可是個很實用的功能!
面對上述三個問題您是否會感慨:看似簡單的容器探針技術,想要用好還需掌握更多知識,接下來的文章中咱們一起努力吧,從知識覆蓋到實戰操練,終究會掌握這門實用技術;
https://github.com/zq2599/blog_demos
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※想知道購買電動車哪裡補助最多?台中電動車補助資訊懶人包彙整
※南投搬家公司費用,距離,噸數怎麼算?達人教你簡易估價知識!
※教你寫出一流的銷售文案?
※超省錢租車方案
※回頭車貨運收費標準
少點代碼,多點頭髮
本文已經收錄至我的GitHub,歡迎大家踴躍star 和 issues。
https://github.com/midou-tech/articles
看文章有兩點需要注意:
本公號講解的Elasticsearch是基於7.7.0版本,你們在閱讀一些相關書籍和博客注意版本,不同版本很多概念會有出入。
文章寫作過程中會經常將Elasticsearch簡寫為Es,閱讀過程中需要注意。
一般學習一個新的技術或者產品,第一步就是用起來。什麼設計理論,框架源碼,都別和我談,先run起來。這也是在公司看別人項目的絕招。
用起來,有一個很明顯的點,是你能感受到他,不然天天看理論知識,看源碼會讓你覺得你好像懂了,但又心裏沒底,最終會導致你走火入魔。
今天龍叔的主題就是 學Es,先run起來,用起來之後在去探索內部更多問題和原理。
Elasticsearch
Elasticsearch 的底層是開源庫 Lucene。但是,你沒法直接用 Lucene,必須自己寫代碼去調用它的接口。Elasticsearch 是 Lucene 的封裝,提供了 REST API 的操作接口,開箱即用。
Elasticsearch 需要 Java 8 環境。如果你的機器還沒安裝 Java,可以在網上找個教程安裝,注意要保證環境變量JAVA_HOME正確設置。
安裝完 Java,就可以跟着 官方文檔:https://www.elastic.co/guide/en/elasticsearch/reference/current/zip-targz.html 安裝 Elasticsearch。我這裏就直接下載壓縮包比較簡單。
#mac和linux上安裝教程一樣的
# 下載
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.7.0-darwin-x86_64.tar.gz
$ wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.7.0-darwin-x86_64.tar.gz.sha512
$ shasum -a 512 -c elasticsearch-7.7.0-darwin-x86_64.tar.gz.sha512
#解壓
$ tar -xzf elasticsearch-7.7.0-darwin-x86_64.tar.gz
$ cd elasticsearch-7.7.0/
接着,進入解壓后的目錄,運行下面的命令,啟動 Elasticsearch。
$ ./bin/elasticsearch
如果一切正常,那可能是run起來了,Es默認打開9200端口。測試下是否啟動成功,用 curl 工具測試(這個工具後面會寫一篇文章介紹,還有上面用的wget),也可以在瀏覽器訪問。
$ curl localhost:9200 #測試命令
{
"name" : "MacBook-Pro.local",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "Z1NxCjE4T6CgTjZmpAVe_A",
"version" : {
"number" : "7.7.0",
"build_flavor" : "default",
"build_type" : "tar",
"build_hash" : "81a1e9eda8e6183f5237786246f6dced26a10eaf",
"build_date" : "2020-05-12T02:01:37.602180Z",
"build_snapshot" : false,
"lucene_version" : "8.5.1",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}
請求9200端口,Elastic 返回一個 JSON 對象,包含當前節點、集群、版本等信息。
收到這樣一個JSON對象,說明啟動成功。
安裝整體沒什麼壓力,java環境裝好,基本就是開箱即用。程序員最喜歡使用這樣的中間件,開箱即用,從不管箱子裏面是啥。
本來run起來就準備說搞點數據進去,在和Es進行交互起來,但是正在準備寫數據進索引的時候,發現不對勁。
可能有人根本不知道什麼是索引?什麼Document。於是 就來了,先普及下基本概念。
Elastic 本質上是一個分佈式數據庫,允許多台服務器協同工作,每台服務器可以運行多個 Elastic 實例。
單個 Elastic 實例稱為一個節點(node)。一組節點構成一個集群(cluster)。
Elastic 會索引所有字段,經過處理后寫入一個反向索引(Inverted Index),也經常稱之為倒排索引。查找數據的時候,直接查找該索引。
Elastic 數據管理的頂層單位就叫做 Index(索引)。它是單個數據庫的同義詞。每個 Index (即數據庫)的名字必須是小寫。
Index 裏面單條的記錄稱為 Document(文檔)。許多條 Document 構成了一個 Index。
基本概念已經有了,知道查找是通過倒排索引進行的,所以數據肯定是存放在索引裏面的。
我們現在要寫數據進Es,其實就是把數據寫到Es的索引(index)中,前面已經把Es啟動起來了,並沒有創建索引。
今天寫數據就不寫代碼了,利用ES的一些封裝很好的接口,直接命令行操作,後期在用代碼寫數據進Es。
先創建一個index ,使用curl 工具在命令行操作,這是一個put請求。
$curl -X PUT 'localhost:9200/user'
查看索引是否以及創建成功
$ curl -X GET 'http://localhost:9200/_cat/indices?v'
這個get請求可以查看當前節點的所有索引
妥妥的已經創建成功
順便說下,刪除一個索引的命令,DELETE參數表示刪除
$curl -X DELETE 'localhost:9200/user'
到這裏索引已經創建好了,可以寫點數據進去了。使用接口 /index/_doc/id ,/索引名/_doc/doc_id
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/1' -d ' { "name": "龍躍十二", "title": "工程師", "desc": "一個分享互聯網技術和心路歷程的star" }'
查看當前索引下的所有數據
$ curl 'localhost:9200/user/_search?pretty=true
到這裏基本我們已經可以寫數據到指定索引了,生產場景不會這麼寫數據的,都是用代碼寫海量數據進ES的,這就幾條數據也沒什麼搜索性能可談的。
我之前工作中日誌數據都是TB級別的寫到Es中,當遇到這種數據量的搜索時才會感受到搜索引擎的魅力,才會意識到Es的重要性。
這裏主要是練手和跑通流程,所以造了一些數據到Es中
其實寫數據進Es已經是一種交互了,在講一些其他的交互接口
目前講的交互方式主要是通過原生的請求的方式,還沒有上升到界面操作,後期在學習的過程中會展現出來。
使用 GET 方法,直接請求/Index/_search,就會返回所有記錄。
$ curl 'localhost:9200/user/_search?pretty=true'
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 3,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "user",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "龍躍十二",
"title" : "工程師",
"desc" : "一個分享互聯網技術和心路歷程的star"
}
},
{
"_index" : "user",
"_type" : "_doc",
"_id" : "3",
"_score" : 1.0,
"_source" : {
"name" : "三y",
"title" : "工程師",
"desc" : "只有光頭才能變得更強"
}
},
{
"_index" : "user",
"_type" : "_doc",
"_id" : "2",
"_score" : 1.0,
"_source" : {
"name" : "敖丙",
"title" : "工程師",
"desc" : "一個互聯網苟且偷生的工具人"
}
}
]
}
}
上面代碼中,返回結果的 took字段表示該操作的耗時(單位為毫秒),timed_out字段表示是否超時,hits字段表示命中的記錄,裏面子字段的含義如下。
返回的記錄中,每條記錄都有一個_score字段,表示匹配的程序,默認是按照這個字段降序排列。
Es的查詢語法還有很多,後面在結合實戰項目的時候會講解其他語法,你也可以看下官網語法介紹 官網查詢語法。
新增一條doc記錄的語法示例如下,可以不用指定doc_id的,Es會默認有一個doc_id。
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/2' -d ' { "name": "敖丙", "title": "工程師", "desc": "一個互聯網苟且偷生的工具人" }'
刪除一條doc記錄的語法是 /Index/_doc/doc_id
$ curl -X DELETE 'localhost:9200/user/_doc/1'
更新一條記錄的語法示例
$ curl -X PUT -H 'Content-Type: application/json' 'localhost:9200/user/_doc/2' -d ' { "name": "三太子敖丙", "title": "工程師", "desc": "一個互聯網苟且偷生的工具人" }'
本篇文章,我們把Es從官網下載下來,可以run起來,可以寫數據進去,可以查詢,學習了一些簡單的交互語法。
當然Es的魅力不在於此,Es的魅力之一在於可以對海量數據進行高效的檢索。
下篇文章出一個關於Es的寫作大綱,方便大家在看的過程中有一個整理的輪廓。
Es整個知識點我也是邊學邊寫,有什麼不對的地方,還希望大佬們儘管指出來。
龍躍十二
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※Google地圖已可更新顯示潭子電動車充電站設置地點!!
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※別再煩惱如何寫文案,掌握八大原則!
※網頁設計最專業,超強功能平台可客製化
※回頭車貨運收費標準
網絡層的目的是實現兩個端系統之間的數據透明傳送,具體功能包括尋址和路由選擇、連接的建立、保持和終止等。它提供的服務使傳輸層不需要了解網絡中的數據傳輸和交換技術。如果您想用盡量少的詞來記住網絡層,那就是”路徑選擇、路由及邏輯尋址”。
網絡層中涉及眾多的協議,其中包括最重要的協議,也是TCP/IP的核心協議——IP協議。IP協議非常簡單,僅僅提供不可靠、無連接的傳送服務。IP協議的主要功能有:無連接數據報傳輸、數據報路由選擇和差錯控制。與IP協議配套使用實現其功能的還有地址解析協議ARP、逆地址解析協議RARP、因特網報文協議ICMP、因特網組管理協議IGMP。
實際的計算機網絡是錯綜複雜的,物理設備通過使用IP協議,屏蔽了物理網絡之間的差異,當網絡中的主機使用IP協議連接時,則無需關注網絡細節。IP協議使得複雜的實際網絡變為一個虛擬互連的網絡,還使得網絡層可以屏蔽底層細節而專註網絡層的數據轉發,IP協議解決了在虛擬網絡中數據報傳輸路徑的問題。
IP地址長度為32位,常分成4個8位,IP地址常使用點分十進制來表示(0~255.0~255.0~255.0~255),也就是共有\(2^{32} = 4294961296\)個IP地址。下圖是IP協議的格式:
我們來看看IP協議的首部:
| 4位版本 | 4位首部長度 | 8位服務類型(TOS) | 16位總長度(字節) | ||||
| 16位標識 | 3位標誌 | 13位片偏移 | |||||
| 8位生存時間(TTL) | 8位協議 | 16位首部校驗和 | |||||
| 32位源IP地址 | |||||||
| 32位目的IP地址 | |||||||
| 選項options(若有) | |||||||
| IP數據 | |||||||
版本:佔4位,指的是IP協議的版本,通信雙方的版本必須一致,當前主流版本是4,即IPv4,也有IPv6
首部位長度:佔4位,最大數值為15,表示的是IP首部長度,單位是“32位字”(4個字節),也即是IP首部最大長度為60字節
總長度:佔16位,最大數值為65535,表示的是IP數據報總長度(IP首部+IP數據)
TTL:佔8位,表明IP數據報文在網絡中的壽命,每經過一個設備,TTL減1,當TTL=0時,網絡設備必須丟棄該報文。作用:避免數據在網絡中無限傳輸,當這個網絡報文找不到目的機器時,而進行無限傳輸,來浪費帶寬資源
協議:佔8位,表明IP數據所攜帶的具體數據是什麼協議的(如:TCP、UDP等)
| 協議名 | ICMP | IGMP | IP | TCP | UDP | OSPF | … |
|---|---|---|---|---|---|---|---|
| 字段值 | 1 | 2 | 4 | 6 | 17 | 89 | … |
首部校驗和:佔16位,校驗IP首部是否有出錯
在數據鏈路層的學習中我們知道了MAC地址表,由於IP協議的轉發是通過逐跳(hop-by-hop)來實現的,所以在網絡層中,存在一個類似於MAC地址表的路由表,路由表是存儲的目的IP地址和下一跳IP地址的映射,計算機或者路由器都擁有路由表。路由表如下:
| 目的IP地址 | 下一跳IP地址 |
|---|---|
| IP1 | IP4 |
| IP2 | IP5 |
| IP3 | IP6 |
| … | … |
A設備是如何跨設備將數據發送給C設備的呢?
A設備向C設備在網絡層中傳輸數據的過程如下:
現在結合數據鏈路層和網絡層,再來看一下跨設備傳輸數據的過程:
從IP協議的轉發流程中我們可以看到:數據幀每一跳的MAC地址都在變化,但IP數據報每一跳的IP地址始終不變。但我們會發現一個問題,在網絡層中將數據報交給數據鏈路層,並且需要告知目的MAC地址,但是在網絡層中只知道IP地址,我們是如何知道目的MAC地址的呢?這就是ARP協議做的事情了。
ARP(Address Resolution Protocol)地址解析協議,將網絡層中的32位IP地址,通過ARP協議解析為數據鏈路層中的48位MAC地址。這個映射關係是存儲在ARP緩存表中的。arp -a命令:查看ARP緩存表
| IP地址 | MAC地址 |
|---|---|
| 192.168.83.254 | 00-50-56-e0-33-40 |
| 192.168.83.255 | 01-00-5e-00-00-16 |
| 224.0.0.251 | 01-00-5e-00-00-fc |
| 239.1.2.3 | 01-00-5e-40-98-8f |
| 255.255.255.255 | 01-00-5e-7f-ff-fa |
ARP緩存表是ARP協議和RARP協議運行的關鍵,ARP緩存表緩存了IP地址到硬件地址之間的映射關係,ARP緩存表中的記錄並不是永久有效的,有一定的期限。這是因為當你的網絡設備,換個網絡環境,網絡設備的IP地址就可能會發生改變,ARP緩存表中的原來的記錄就失效了。當ARP緩存表中有映射關係,就直接查詢ARP緩存表;如果沒有這個映射關係,ARP協議就會廣播,並記錄回應得地址信息。
RARP(Reverse Address Resolution Protocol)逆地址解析協議,其作用與ARP協議相反,即把數據鏈路層中48位MAC地址,解析位網絡層中的32位IP地址。(R)ARP協議是TCP/IP協議棧裏面基礎的協議,ARP和RARP的操作對程序員是透明的,理解(R)ARP協議有助於理解網絡分層的細節。
| 最小網絡號 | 最大網絡號 | 子網數量 | 最小主機號 | 最大主機號 | 主機數量 | |
|---|---|---|---|---|---|---|
| A | 0(00000000) | 127(01111111) | \(2^7\) | 0.0.0 | 255.255.255 | \(2^{24}\) |
| B | 128.0 | 191.255 | \(2^{14}\) | 0.0 | 255.255 | \(2^{16}\) |
| C | 192.0.0 | 223.255.255 | \(2^{21}\) | 0 | 255 | \(2^{8}\) |
特殊的主機號:主機號全0表示當前網絡段,不可分配為特定主機;主機號為全1表示廣播地址,向當前網絡段所有主機發消息
實際可使用各類IP地址如下:
| 最小網絡號 | 最大網絡號 | 子網數量 | 最小主機號 | 最大主機號 | 主機數量 | |
|---|---|---|---|---|---|---|
| A | 1 | 127(01111111) | \(2^7\)-2 | 0.0.1 | 255.255.254 | \(2^{24}\)-2 |
| B | 128.1 | 191.255 | \(2^{14}\)-1 | 0.1 | 255.254 | \(2^{16}\)-2 |
| C | 192.0.1 | 223.255.255 | \(2^{21}\)-1 | 1 | 254 | \(2^{8}\)-2 |
127.0.0.1,通常被稱為本地迴環地址(Loopback Address),不屬於任何一個有類別地址類。它代表設備的本地虛擬接口,所以默認被看作是永遠不會宕掉的接口。在Windows操作系統中也有相似的定義,所以通常在安裝網卡前就可以ping通這個本地迴環地址。一般都會用來檢查本地網絡協議、基本數據接口等是否正常的。
隨着互連網應用的不斷擴大,原先的IPv4的弊端也逐漸暴露出來,即網絡號佔位太多,而主機號位太少,所以其能提供的主機地址也越來越稀缺,目前除了使用NAT在企業內部利用保留地址自行分配以外,通常都對一個高類別的IP地址進行再劃分,以形成多個子網,提供給不同規模的用戶群使用。這裏主要是為了在網絡分段情況下有效地利用IP地址,通過對主機號的高位部分取作為子網號,從通常的網絡位界限中擴展或壓縮子網掩碼,用來創建某類地址的更多子網。但創建更多的子網時,在每個子網上的可用主機地址數目會比原先減少。
上圖就把原來的C類地址劃分成了兩個子網。
但子網號這麼多,有沒有辦法快速判斷某個IP的網絡號?這就是子網掩碼的作用了,子網掩碼是標誌兩個IP地址是否同屬於一個子網的,也是32位二進制地址,其每一個為1代表該位是網絡位,為0代表主機位。它和IP地址一樣也是使用點式十進制來表示的。如果兩個IP地址在子網掩碼的按位與的計算下所得結果相同,即表明它們共屬於同一子網中。
子網掩碼由連續的1和連續的0組成,某一個子網的子網掩碼具備網絡號位數個連續的1
在計算子網掩碼時,我們要注意IP地址中的保留地址,即” 0″地址和廣播地址,它們是指主機地址或網絡地址全為” 0″或” 1″時的IP地址,它們代表着本網絡地址和廣播地址,一般是不能被計算在內的。
CIDR中沒有A、B、C類網絡號、和子網劃分的概念,CIDR將網絡前綴相同的IP地址稱為一個“CIDR地址塊”,注意網絡前綴是任意位數的。
| 網絡前綴 | 主機號 |
|---|
斜線記法:193.10.10.129/25 使用二進製表示:11000001.00001010.00001010.10000001
無分類地址CIDR相比原來的子網劃分更加 靈活:
| CIDR前綴長度 | 掩碼點分十進制 | 地址數 |
|---|---|---|
| /13 | 255.248.0.0 | 512K |
| /14 | 255.252.0.0 | 256K |
| /15 | 255.254.0.0 | 128K |
| /16 | 255.255.0.0 | 64K |
| /17 | 255.255.128.0 | 32K |
| /18 | 255.255.192.0 | 16K |
| /19 | 255.255.224.0 | 8K |
IPv4最多只有40+億個IP地址,早期IP地址的不合理規劃導致IP號浪費。在介紹NAT技術之前,首先要知道內網地址和外網地址。
網絡地址轉換技術是發生在本地路由器的,主要功能就是把內網的IP地址轉成外網的IP地址來進行外部的通信,並且在接收到數據之後,再把外網IP地址映射成內網IP地址,轉發到具體的某個設備上面去。
內網多個設備使用同一個外網IP請求外網的服務,外部怎麼知道具體是哪個設備在請求的?網絡地址轉換NAT的英文全稱是Network Address Translation,NAT技術用於多個主機通過一個公有IP訪問互聯網的私有網絡中,外部主要是通過端口號來區分到底是內網的哪一個設備進行請求的,這其中有一個NA(P)T表表:示例如下:
| 方向 | 舊的地址和端口號 | 新的地址與端口號 |
|---|---|---|
| 出 | 192.168.2.11:6666 | 173.21.59.10:16666 |
| 出 | 192.168.2.10:7777 | 173.21.59.10:17777 |
| 入 | 173.21.59.10:16666 | 192.168.2.11:6666 |
| 入 | 173.21.59.10:17777 | 192.168.2.10:7777 |
NAT減緩了IP地址的消耗,但是增加了網絡通信的複雜度
ICMP協議全稱是網際控制報文協議(Internet Control Message Protocol),ICMP協議可以報告錯誤信息或者異常情況
ICMP協議首部:
| 8位類型 | 8位代碼 | 16位校驗和 |
| ICMP報文數據 | ||
ICMP報文分為:差錯報告報文和詢問報文:
| ICMP報文種類 | 類型的值 | 報文類型 | 具體代碼 |
| 差錯報告報文 | 3(終點不可達) | 網絡不可達 | 0 |
| 主機不可達 | 1 | ||
| 5(重定向) | 對網絡重定向 | 0 | |
| 對主機重定向 | 1 | ||
| 11 | 傳輸超時 | – | |
| 12 | 壞的IP頭 | 0 | |
| 缺少其他必要參數 | 1 | ||
| 詢問報文 | 0或8 | 回送(Echo)請求或應答 | – |
| 13或14 | 時間戳(Timestamp)請求或應答 | – |
ping應用:我們可以通過ping命令進行簡單的網絡故障排查:
Traceroute應用:Traceroute可以探測IP數據報在網絡中走過的路徑
思考:路由表中的下一跳地址是怎麼來的?下一跳地址是唯一的嗎?下一跳地址是最佳的嗎?路由器怎麼多,他們是怎麼協同工作的?為了解決這些問題,路由表需要一個好的算法去解決這些事情。路由算法實際上是圖論的算法,由於網絡環境複雜,使得路由算法要比圖論的算法更複雜。
由於互聯網的規模是非常大的,互聯網環境是非常複雜的,所以我們需要對互聯網進行劃分。自治系統(Autonomous System)是指處於一個管理機構下的網絡設備群,AS內部網絡自行管理,AS對外提供一個或者多個出(入)口。自治系統內部路由的協議稱為:內部網關協議(RIP、OSPF), 自治系統外部路由的協議稱為:外部網關協議(BGP)。
路由算法的本質是距離矢量(DV)算法, 距離矢量(DV)算法介紹如下:
現在假設有A的距離矢量信息,收到的距離矢量信息如下圖:
A通過B到各個節點得距離矢量信息如下:
A通過C到各個節點得距離矢量:並更新下一條的節點
A通過D到各個節點得距離矢量:並更新下一條的節點
A通過F到各個節點得距離矢量:並更新下一條的節點
RIP(Routing Information Protocol)協議,RIP協議是使用DV算法的一種路由協議。RIP協議把網絡的跳數(hop)作為DV算法的距離,每隔30s交換一次路由信息,認為跳數>15的路由則為不可達路由。
RIP協議的過程
RIP協議的優缺點:
鏈路狀態(LS)協議:向所有的路由器發送消息,也就是一傳十、十傳百,只和相鄰的路由器交換信息。消息描述該路由器與相鄰路由器的鏈路狀態,每隔30s交換路由信息,只有鏈路狀態發生變化時,才發送更新信息。
Dijkstra算法是著名的圖算法,Dijkstra算法解決有權圖從一個節點到其他節點的最短路徑問題,“以起始點為中心,向外層層擴展”。
Dijkstra(迪傑斯特拉)算法定義:
OSPF(Open Shortest Path First:開放最短路徑優先),OSPF協議的核心是Dijkstra算法。OSPF協議的過程:路由器接入網絡,路由器向鄰居發出問候信息,與鄰居交流鏈路狀態數據庫,廣播和更新未知路由。
| RIP協議 | OSPF協議 |
|---|---|
| 從鄰居看網絡 | 整個網絡的拓撲 |
| 在路由器之間累加距離 | Dijkstra算法計算最短路徑 |
| 頻繁、周期更新,收斂很慢 | 狀態變化更新,收斂很快 |
| 路由間拷貝路由信息 | 路由間傳遞鏈路狀態,自行計算路徑 |
BGP(Border Gateway Protocol: 邊際網關協議),BGP協議是運行在AS之間的一種協議。由於互聯網的規模很大,AS內部使用不同的路由協議。
AS之間需要考慮除網絡特性以外的一些因素(政治、安全…),BGP(Border Gateway Protocol,邊界網關協議),BGP協議能夠找到一條到達目的比較好的路由,AS之間通過BGP發言人來進行路由信息的交換。BGP發言人(speaker):BGP並不關心內部網絡拓撲,AS之間通過BGP發言人交流信息,BGP Speaker可以人為配置策略。
總結:網絡層負責對子網間的數據包進行路由選擇。此外,網絡層還可以實現擁塞控制、網際互連等功能;網絡層的基本數據單位為IP數據報;包含的主要協議:IP協議(Internet Protocol,因特網互聯協議)、ICMP協議(Internet Control Message Protocol,因特網控制報文協議)、ARP協議(Address Resolution Protocol,地址解析協議)以及RARP協議(Reverse Address Resolution Protocol,逆地址解析協議)。網絡層重要的設備是路由器。常見的路由選擇協議有:RIP協議、OSPF協議。RIP協議 :底層是貝爾曼福特算法,它選擇路由的度量標準(metric)是跳數,最大跳數是15跳,如果大於15跳,它就會丟棄數據包;OSPF協議 :Open Shortest Path First開放式最短路徑優先,底層是迪傑斯特拉算法,是鏈路狀態路由選擇協議,它選擇路由的度量標準是帶寬,延遲。
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※網頁設計公司推薦不同的風格,搶佔消費者視覺第一線
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面
※南投搬家公司費用需注意的眉眉角角,別等搬了再說!
※教你寫出一流的銷售文案?
※回頭車貨運收費標準
※別再煩惱如何寫文案,掌握八大原則!