主頁 > 作業系統 > 你真的懂Linux內核中的阻塞和異步通知機制嗎?

你真的懂Linux內核中的阻塞和異步通知機制嗎?

2020-12-31 06:15:06 作業系統

@

目錄
  • 阻塞/非阻塞簡介
  • 阻塞/非阻塞例程
  • 等待佇列簡介
  • 等待佇列相關函式
    • 定義等待佇列
    • 初始化等待佇列頭
    • 定義并初始化一個等待佇列項
    • 將佇列項添加到等待佇列頭
    • 將佇列項從等待佇列頭移除
    • 等待喚醒
    • 等待事件
  • 輪詢
    • select
    • poll
    • epoll
  • 異步通知概念
  • Linux信號
  • 異步通知代碼
    • 驅動中的信號處理
      • fasync_struct結構體
      • fasync函式
      • kill_fasync函式
    • 應用程式對異步通知的處理

阻塞/非阻塞簡介

??阻塞操作是指在執行設備操作時,若不能獲得資源,則掛起行程直到滿足可操作的條件后再進行操作,被掛起的行程進入睡眠狀態,被從調度器的運行佇列移走,直到等待的條件被滿足,而非阻塞操作的行程在不能進行設備操作時,并不掛起,它要么放棄,要么不停地查詢,直至可以進行操作為止,

阻塞/非阻塞例程

??阻塞方式

int fd;
int data = https://www.cnblogs.com/dongxb/p/0;
fd = open("/dev/xxx_dev", O_RDWR); /* 阻塞方式打開 */
ret = read(fd, &data, sizeof(data)); /* 讀取資料 */

??非阻塞方式

int fd;
int data = https://www.cnblogs.com/dongxb/p/0; 
fd = open("/dev/xxx_dev", O_RDWR | O_NONBLOCK); /* 非阻塞方式打開 */ 
ret = read(fd, &data, sizeof(data)); /* 讀取資料 */

等待佇列簡介

??等待佇列是內核中一個重要的資料結構,阻塞方式訪問設備時,如果設備不可操作,那么行程就會進入休眠狀態,等待佇列就是來完成行程休眠操作的一種資料結構,

等待佇列相關函式

定義等待佇列

wait_queue_head_t my_queue;

??wait_queue_head_t是__wait_queue_head結構體的一個typedef,

初始化等待佇列頭

void init_waitqueue_head(wait_queue_head_t *q)

??引數q就是要初始化的等待佇列頭,也可以使用宏 DECLARE_WAIT_QUEUE_HEAD (name)來一次性完成等待佇列頭的定義的初始化,

定義并初始化一個等待佇列項

DECLARE_WAITQUEUE(name, tsk)

??name就是等待佇列項的名字,tsk表示這個等待佇列項屬于哪個任務行程,一般設定為current,在 Linux內核中 current相當于一個全域變數,表示當前行程,因此宏DECLARE_WAITQUEUE就是給當前正在運行的行程創建并初始化了一個等待佇列項,

將佇列項添加到等待佇列頭

void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

??q:等待佇列項要加入的等待佇列頭
??wait:要加入的等待佇列項
??回傳值:無

將佇列項從等待佇列頭移除

void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)

??q:要洗掉的等待佇列項所處的等待佇列頭
??wait:要洗掉的等待佇列項,
??回傳值:無

等待喚醒

void wake_up(wait_queue_head_t *q) 
void wake_up_interruptible(wait_queue_head_t *q)

??q:就是要喚醒的等待佇列頭,這兩個函式會將這個等待佇列頭中的所有行程都喚醒
??wake_up函式可以喚醒處于 TASK_INTERRUPTIBLE和 TASK_UNINTERRUPTIBLE狀態的行程,而wake_ up_ interruptible函式只能喚醒處于 TASK_INTERRUPTIBLE狀態的行程

等待事件

wait_event(wq, condition)

??等待以wq為等待佇列頭的等待佇列被喚醒,前提是 condition條件必須滿足(為真),否則一直阻塞,此函式會將行程設定為TASK _UNINTERRUPTIBLE狀態

wait_event_timeout(wq, condition, timeout)

??功能和 wait_event類似,但是此函式可以添加超時時間,以 jiffies為單位,此函式有回傳值,如果回傳0的話表示超時時間到,而且 condition為假,為1的話表示 condition為真,也就是條件滿足了,

wait_event_interruptible(wq, condition)

??與 wait event函式類似,但是此函式將行程設定為 TASK_INTERRUPTIBLE,就是可以被信號打斷

wait_event_interruptible_timeout(wq, condition, timeout)

??與 wait event timeout函式類似,此函式也將行程設定為 TASK_INTERRUPTIBLE,可以被信號打斷

輪詢

??當應用程式以非阻塞的方式訪問設備時,會一遍一遍的去查詢我們的設備是否可以訪問,這個查詢操作就叫做輪詢,內核中提供了poll,epoll,select函式來處理輪詢操作,當應用程式在上層通過poll,epoll,select函式來查詢設備時,驅動程式中的poll,epoll,select函式就要在底層實作查詢,如果可以操作的話,就會從讀取設備的資料或者向設備寫入資料,

select

??函式原型

int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)

??nfds:要操作的檔案描述符個數,
??readifds、 writefds和 exceptfds:這三個指標指向描述符集合,這三個引數指明了關心哪些描述符、需要滿足哪些條件等等,這三個引數都是fd_set型別的, fd_set型別變數的每一個位都代表了一個檔案描述符, readfds用于監視指定描述符集的讀變化,也就是監視這些檔案是否可以讀取,只要這些集合里面有一個檔案可以讀取,那么 seclect就會回傳一個大于0的值表示檔案可以讀取,如果沒有檔案可以讀取,那么就會根據 timeout引數來判斷是否超時,可以將 reads設定為NULL,表示不關心任何檔案的讀變化, writefds和 reads類似,只是 writers用于監視這些檔案是否可以進行寫操作, exceptfds用于監視這些檔案的例外
??timeout:超時時間,當我們呼叫 select函式等待某些檔案描述符可以設定超時時間,超時時間使用結構體 timeval表示,結構體定義如下所示:

struct timeval { 
long tv_sec; /* 秒 */
long tv_usec; /* 微妙 */ 
};

??當 timeout為NULL的時候就表示無限期的等待回傳值,0,表示的話就表示超時發生,但是沒有任何檔案描述符可以進行操作;-1,發生錯誤;其他值,可以進行操作的檔案描述符個數,
??操作fd_set變數的函式

void FD_ZERO(fd_set *set) 
void FD_SET(int fd, fd_set *set) 
void FD_CLR(int fd, fd_set *set) 
int FD_ISSET(int fd, fd_set *set)

??FD_ZERO用于將 fd set變數的所有位都清零, FD_SET用于將 fd_set變數的某個位置1,也就是向 fd_set添加一個檔案描述符,引數fd就是要加入的檔案描述符, FD_CLR用戶將 fd_set變數的某個位清零,也就是將一個檔案描述符從 fd_set中洗掉,引數fd就是要洗掉的檔案描述符, FD_ISSET用于測驗 fd_set的某個位是否置1,也就是判斷某個檔案是否可以進行操作,引數fd就是要判斷的檔案描述符,


void main(void) 
{  int ret, fd; /* 要監視的檔案描述符 */ 
    fd_set readfds; /* 讀操作檔案描述符集 */
    struct timeval timeout; /* 超時結構體 */ 
    fd = open("dev_xxx", O_RDWR | O_NONBLOCK); /* 非阻塞式訪問 */ 
    FD_ZERO(&readfds); /* 清除readfds */ 
    FD_SET(fd, &readfds); /* 將fd添加到readfds里面 */ 
     /* 構造超時時間 */ 
     timeout.tv_sec = 0; 
     timeout.tv_usec = 500000; /* 500ms */ 
     ret = select(fd + 1, &readfds, NULL, NULL, &timeout); 
     switch (ret) { 
        case 0: /* 超時 */ 
            printf("timeout!\r\n");
            break; 
        case -1: /* 錯誤 */ 
            printf("error!\r\n"); 
            break; 
        default: /* 可以讀取資料 */ 
        if(FD_ISSET(fd, &readfds))   /* 判斷是否為fd檔案描述符 */ 
          {
               /* 使用read函式讀取資料 */ 
          } 
         break; 
    } 
 }

poll

??在單個執行緒中, select函式能夠監視的檔案描述符數量有最大的限制,一般為1024,可以修改內核將監視的檔案描述符數量改大,但是這樣會降低效率!這個時候就可以使用poll函式, poll函式本質上和 select沒有太大的差別,但是poll函式沒有最大檔案描述符限制,Linx應用程式中poll函式原型如下所示:

int poll(struct pollfd *fds, nfds_t nfds, int timeout)

??函式引數和回傳值含義如下
??fds:要監視的檔案描述符集合以及要監視的事件,為一個陣列,陣列元素都是結構體 polled型別的, pollfd結構體如下所示

struct pollfd 
{ 
	int fd; /* 檔案描述符 檔案描述符 檔案描述符 */ 
	short events; /* 請求的事件 請求的事件 請求的事件 */
	short revents; /* 回傳的事件 回傳的事件 回傳的事件 */ 
};

??fd是要監視的檔案描述符,如果f無效的話那么 events監視事件也就無效,并且 revents回傳0, events是要監視的事件,可監視的事件型別如下所示

POLLIN		//有資料可以讀取,
POLLPRI		//有緊急的資料需要讀取,
POLLOUT		//可以寫資料POLLERR指定的檔案描述符發生錯誤POLLHUP指定的檔案描述符掛起POLLNVAL無效的請求POLLRDNORM等同于 POLLIN

??revents:回傳引數,也就是回傳的事件,有Linux內核設定具體的回傳事件,
??nfds:poll函式要監視的檔案描述符數量
??timeout:超時時間,單位為ms
??回傳值:回傳 revents域中不為0的 polled結構體個數,也就是發生事件或錯誤的檔案描述符數量;0,超時;-1,發生錯誤,并且設定errno為錯誤型別

void main(void)
{ 
   int ret; 
   int fd; /* 要監視的檔案描述符 */
   struct pollfd fds;
   fd = open(filename, O_RDWR | O_NONBLOCK); /* 非阻塞式訪問 */ 
    /* 構造結構體 */ 
   fds.fd = fd; 
   fds.events = POLLIN; /* 監視資料是否可以讀取 */
   ret = poll(&fds, 1, 500); /* 輪詢檔案是否可操作,超時500ms */ 
    if (ret)
     { /* 資料有效 */ 
      /* 讀取資料 */ 
     } else if (ret == 0) 
     { 
         /* 超時 */ 
     } else if (ret < 0) 
     {
          /* 錯誤 */ 
     } 
 }

epoll

??傳統的 selcet和poll函式都會隨著所監聽的fd數量的增加,出現效率低下的問題,而且poll函式每次必須遍歷所有的描述符來檢查就緒的描述符,這個程序很浪費時間,為此,epoll因運而生,epoll就是為處理大并發而準備的,一般常常在網路編程中使用epoll函式,應用程式需要先使用 epoll_create函式創建一個 epoll句柄, epoll create函式原至如下.

int epoll_create(int size)

??函式引數和回傳值含義如下:
??size;從 Linux2.6.8開始此引數已經沒有意義了,隨便填寫一個大于0的值就可以
??回傳值:epoll句柄,如果為-1的話表示創建失敗,epoll句柄創建成功以后使用,epoll ctl函式向其中添加要監視的檔案描述符以及監視的事ct函式原型如下所示

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)

??函式引數和回傳值含義如下
??epfd;要操作的epoll句柄,也就是使用 epoll_create函式創建的epoll句柄,
??p:表示要對epfd( epoll句柄)進行的操作,可以設定為

EPOLL CTL ADD		//向印fd添加檔案引數d表示的描述符EPOLL CTL MOD修改引數fd的 event事件,
EPOLL CTL DEL		//從f中洗掉過l描述符

??fd:要監視的檔案描述
??event:要監視的事件型別,為 epoll_event結構體型別指標, epoll_event結構體型別如下所

struct epoll_event 
{
 	uint32_t events; /* epoll事件 */ 
	epoll_data_t data; /* 用戶資料 用戶資料 */ 
};

??結構體 epoll_event的 events成員變數表示要監視的事件,可選的事件如下所示

EPOLLIN			//有資料可以讀取EPOLLOUT可以寫資料
EPOLLPRI		//有緊急的資料需要讀取EPOLLERI指定的檔案描述符發生錯誤,
EPOLLHUP		//指定的檔案描述符掛起POLLET設定epo為邊沿觸發,默認觸發模式為水平觸發王
POLLONESHOT		//一次性的監視,當監視完成以后還需要再次監視某個fd,那么就需要將fd重新添加到 epoll 里面

??上面這些事件可以進行“或”操作,也就是說可以設定監視多個事件回傳值:0,成功;-1,失敗,并且設定errno的值為相應的錯誤碼,一切都設定好以后應用程式就可以通過 epoll_wait函式來等待事件的發生,類似 select函式, epoll_wait函式原型如下所示

int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout)

??函式引數和回傳值含義如下
??epfd:要等待的 epoll
??events:指向 epoll_event結構體的陣列,當有事件發生的時候Iimx內核會填寫 events,呼叫者可以根據 events判斷發生了哪些事件,
??prevents:events陣列大小,必須大于0
??timeout:超時時間,單位為ms回傳值:0,超時;-1,錯誤;其他值,準備就緒的檔案描述符數量,
??epoll更多的是用在大規模的并發服務器上,因為在這種場合下 select和poll并不適合,當設計到的檔案描述符(fd比較少的時候就適合用 selcet和pl本章我們就使用 sellect和poll這兩個函式

異步通知概念

??阻塞與非阻塞訪問、poll函式提供了較好的解決設備訪問的機制,但是如果有了異步通知,整套機制則更加完整了,
??異步通知的意思是:一旦設備就緒,則主動通知應用程式,這樣應用程式根本就不需要查詢設備狀態,這一點非常類似于硬體上“中斷”的概念,比較準確的稱謂是“信號驅動的異步I/O”,信號是在軟體層次上對中斷機制的一種模擬,在原理上,一個行程收到一個信號與處理器收到一個中斷請求可以說是一樣的,信號是異步的,一個行程不必通過任何操作來等待信號的到達,事實上,行程也不知道信號到底什么時候到達,
??阻塞I/O意味著一直等待設備可訪問后再訪問,非阻塞I/O中使用poll()意味著查詢設備是否可訪問,而異步通知則意味著設備通知用戶自身可訪問,之后用戶再進行I/O處理,由此可見,這幾種I/O方式可以相互補充,

Linux信號

??異步通知的核心就是信號,在 arch/xtensa/include/uapi/asm/signal.h檔案中定義了Linux所支持的所有信號

#define SIGHUP      1/* 終端掛起或控制行程終止 */ 
#define SIGINT      2/* 終端中斷(Ctrl+C組合鍵) */ 
#define SIGQUIT     3 /* 終端退出(Ctrl+\組合鍵) */
#define SIGILL      4/* 非法指令 */ 
#define SIGTRAP     5/* debug使用,有斷點指令產生 */
#define SIGABRT     6/* 由abort(3)發出的退出指令 */ 
#define SIGIOT      6 /* IOT指令 */ 
#define SIGBUS      7 /* 總線錯誤 */ 
#define SIGFPE      8 /* 浮點運算錯誤 */ 
#define SIGKILL     9 /* 殺死、終止行程 */ 
#define SIGUSR1     10 /* 用戶自定義信號1 */ 
#define SIGSEGV     11 /* 段違例(無效的記憶體段) */
#define SIGUSR2     12 /* 用戶自定義信號2 */ 
#define SIGPIPE     13 /* 向非讀管道寫入資料 */ 
#define SIGALRM     14 /* 鬧鐘 */
#define SIGTERM     15 /* 軟體終止 */
#define SIGSTKFLT   16 /* 堆疊例外 */
#define SIGCHLD     17 /* 子行程結束 */
#define SIGCONT     18 /* 行程繼續 */
#define SIGSTOP     19 /* 停止行程的執行,只是暫停 */
#define SIGTSTP     20 /* 停止行程的運行(Ctrl+Z組合鍵) */ 
#define SIGTTIN     21 /* 后臺行程需要從終端讀取資料 */ 
#define SIGTTOU     22 /* 后臺行程需要向終端寫資料 */
#define SIGURG      23 /* 有"緊急"資料 */
#define SIGXCPU     24 /* 超過CPU資源限制 */ 
#define SIGXFSZ     25 /* 檔案大小超額 */ 
#define SIGVTALRM   26 /* 虛擬時鐘信號 */ 
#define SIGPROF     27 /* 時鐘信號描述 */
#define SIGWINCH    28 /* 視窗大小改變 */ 
#define SIGIO       29 /* 可以進行輸入/輸出操作 */
#define SIGPOLL SIGIO 
 /* #define SIGLOS 29 */ 
#define SIGPWR      30 /* 斷點重啟 */ 
#define SIGSYS      31 /* 非法的系統呼叫 */ 
#define SIGUNUSED   31 /* 未使用信號 */

異步通知代碼

??我們使用中斷的時候需要設定中斷處理函式,同樣的,如果要在應用程式中使用信號,那么就必須設定信號所使用的信號處理函式,在應用程式中使用 signal函式來設定指定信號的處理函式, signal函式原型如下所示

void (*signal(int signum, void (*handler))(int)))(int);

??該函式原型較難理解,它可以分解為:

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler));

??第一個引數指定信號的值,第二個引數指定針對前面信號值的處理函式,若為SIG_IGN,表示忽略該信號;若為SIG_DFL,表示采用系統默認方式處理信號;若為用戶自定義的函式,則信號被捕獲到后,該函式將被執行,
??如果signal呼叫成功,它回傳最后一次為信號signum系結的處理函式的handler值,失敗則回傳SIG_ERR,

驅動中的信號處理

fasync_struct結構體

??首先我們需要在驅動程式中定義個 fasync_struct結構體指標變數, fasync_struct結構體內容如下

struct fasync_struct 
{ spinlock_t fa_lock; 
int magic; 
int fa_fd; 
struct fasync_struct *fa_next; 
struct file *fa_file; 
struct rcu_head fa_rcu; 
};

??一般將 fasync_struct結構體指標變數定義到設備結構體中,比如在xxx_dev結構體中添加一個 fasync_struct結構體指標變數,結果如下所示

struct xxx_dev 
{ 
	struct device *dev; 
	struct class *cls;
	struct cdev cdev;
 ...... 
	 struct fasync_struct *async_queue; /* 異步相關結構體 */
 }; 

fasync函式

??如果要使用異步通知,需要在設備驅動中實作file_ operations操作集中的 fasync函式,此函式格式如下所示:

int (*fasync) (int fd, struct file *filp, int on)

??fasync函式里面一般通過呼叫 fasync_helper函式來初始化前面定義的 fasync_struct結構體指標, fasync_helper函式原型如下

int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fapp)

??fasync_helper函式的前三個引數就是 fasync函式的那三個引數,第四個引數就是要初始化的 fasync_ struct結構體指標變數,當應用程式通過結構體指標變數,當應用程式通過“ fcntl(fd, F_SETFL, flags | FASYNC)”改變fasync標記的時候,驅動程式 file_operations操作集中的 fasync函式就會執行,

struct xxx_dev 
{ 
	......
	struct fasync_struct *async_queue; /* 異步相關結構體 */ 
}; 
static int xxx_fasync(int fd, struct file *filp, int on)
{
	 struct xxx_dev *dev = (xxx_dev)filp->private_data; 
	 if (fasync_helper(fd, filp, on, &dev->async_queue) < 0) 
	 return -EIO; 
	 return 0; 
 } 
	 static struct file_operations xxx_ops =
 { 
   	...... 
  	.fasync = xxx_fasync,
	  ...... 
 };

??在關閉驅動檔案的時候需要在file_ operations操作集中的 release函式中釋放 fasyn_fasync struct的釋放函式同樣為 fasync_helper, release函式引數參考實體如下

static int xxx_release(struct inode *inode, struct file *filp) 
 { 
 	return xxx_fasync(-1, filp, 0); /* 洗掉異步通知 */
 }
static struct file_operations xxx_ops =
 { 
	...... 
	.release = xxx_release, 
 };

??第3行通過呼叫示例代碼 xxx_fasync函式來完成 fasync_struct的釋放作業,但是,其最侄訓是通過 fasync_helper函式完成釋放作業,

kill_fasync函式

??當設備可以訪問的時候,驅動程式需要向應用程式發出信號,相當于產生“中斷” kill_fasync函式負責發送指定的信號, kill_fasync函式原型如下所示

void kill_fasync(struct fasync_struct **fp, int sig, int band)

??函式引數和回傳值含義如下:
??fasync struct 要操作的檔案指標
??sig:要發送的信號
?? band:可讀時設定為 POLL IN,可寫時設定為 POLL OUT,
??回傳值:無,

應用程式對異步通知的處理

??應用程式對異步通知的處理包括以下三步
??1、注冊信號處理函式應用程式根據驅動程式所使用的信號來設定信號的處理函式,應用程式使用 signal函式來設定信號的處理函式,前面已經詳細的講過了,這里就不細講了,
??2、將本應用程式的行程號告訴給內核使用fcntl(fd, F_SETOWN, getpid)將本應用程式的行程號告訴給內核
??3、開啟異步通知使用如下兩行程式開啟異步通知:

flags = fcntl(fd, F_GETFL); /* 獲取當前的行程狀態*/ 
fcntl(fd, F_SETFL, flags | FASYNC); /* 開啟當前行程異步通知功能 */

??重點就是通過 fcntl函式設定行程狀態為 FASYNC,經過這一步,驅動程式中的 fasync函式就會執行,

大家的鼓勵是我繼續創作的動力,如果覺得寫的不錯,歡迎關注,點贊,收藏,轉發,謝謝!

有任何問題,均可通過公告中的二維碼聯系我

轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/242654.html

標籤:嵌入式

上一篇:Xftp 6 和Xshell 6 安裝(提供安裝包)

下一篇:Linux內核中斷頂半部和底半部的理解

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • CA和證書

    1、在 CentOS7 中使用 gpg 創建 RSA 非對稱密鑰對 gpg --gen-key #Centos上生成公鑰/密鑰對(存放在家目錄.gnupg/) 2、將 CentOS7 匯出的公鑰,拷貝到 CentOS8 中,在 CentOS8 中使用 CentOS7 的公鑰加密一個檔案 gpg -a ......

    uj5u.com 2020-09-10 00:09:53 more
  • Kubernetes K8S之資源控制器Job和CronJob詳解

    Kubernetes的資源控制器Job和CronJob詳解與示例 ......

    uj5u.com 2020-09-10 00:10:45 more
  • VMware下安裝CentOS

    VMware下安裝CentOS 一、軟硬體準備 1 Centos鏡像準備 1.1 CentOS鏡像下載地址 下載地址 1.2 CentOS鏡像下載程序 點擊下載地址進入如下圖的網站,選擇需要下載的版本,這里選擇的是Centos8,點擊如圖所示。 決定選擇Centos8后,選擇想要的鏡像源進行下載,此 ......

    uj5u.com 2020-09-10 00:12:10 more
  • 如何使用Grep命令查找多個字串

    如何使用Grep 命令查找多個字串 大家好,我是良許! 今天向大家介紹一個非常有用的技巧,那就是使用 grep 命令查找多個字串。 簡單介紹一下,grep 命令可以理解為是一個功能強大的命令列工具,可以用它在一個或多個輸入檔案中搜索與正則運算式相匹配的文本,然后再將每個匹配的文本用標準輸出的格式 ......

    uj5u.com 2020-09-10 00:12:28 more
  • git配置http代理

    git配置http代理 經常遇到克隆 github 慢的問題,這里記錄一下幾種配置 git 代理的方法,解決 clone github 過慢。 目錄 git配置代理 git單獨配置github代理 git配置全域代理 配置終端環境變數 git配置代理 主要使用 git config 命令 git單獨 ......

    uj5u.com 2020-09-10 00:12:33 more
  • Linux npm install 裝包時提示Error EACCES permission denied解

    npm install 裝包時提示Error EACCES permission denied解決辦法 ......

    uj5u.com 2020-09-10 00:12:53 more
  • Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包

    Centos 7下安裝nginx,使用yum install nginx,提示沒有可用的軟體包。 18 (flaskApi) [root@67 flaskDemo]# yum -y install nginx 19 已加載插件:fastestmirror, langpacks 20 Loading ......

    uj5u.com 2020-09-10 00:13:13 more
  • Linux查看服務器暴力破解ssh IP

    在公網的服務器上經常遇到別人爆破你服務器的22埠,用來挖礦或者干其他嘿嘿嘿的事情~ 這種情況下正確的做法是: 修改默認ssh的22埠 使用設定密鑰登錄或者白名單ip登錄 建議服務器密碼為復雜密碼 創建普通用戶登錄服務器(root權限過大) 建立堡壘機,實作統一管理服務器 統計爆破IP [root ......

    uj5u.com 2020-09-10 00:13:17 more
  • CentOS 7系統常見快捷鍵操作方式

    Linux系統中一些常見的快捷方式,可有效提高操作效率,在某些時刻也能避免操作失誤帶來的問題。 ......

    uj5u.com 2020-09-10 00:13:31 more
  • CentOS 7作業系統目錄結構介紹

    作業系統存在著大量的資料檔案資訊,相應檔案資訊會存在于系統相應目錄中,為了更好的管理資料資訊,會將系統進行一些目錄規劃,不同目錄存放不同的資源。 ......

    uj5u.com 2020-09-10 00:13:35 more
最新发布
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:43:21 more
  • vim的常用命令

    Vim的6種基本模式 1. 普通模式在普通模式中,用的編輯器命令,比如移動游標,洗掉文本等等。這也是Vim啟動后的默認模式。這正好和許多新用戶期待的操作方式相反(大多數編輯器默認模式為插入模式)。 2. 插入模式在這個模式中,大多數按鍵都會向文本緩沖中插入文本。大多數新用戶希望文本編輯器編輯程序中一 ......

    uj5u.com 2023-04-20 08:42:36 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:26:53 more
  • 設定Windows主機的瀏覽器為wls2的默認瀏覽器

    這里以Chrome為例。 1. 準備作業 wsl是可以使用Windows主機上安裝的exe程式,出于安全考慮,默認情況下改功能是無法使用。要使用的話,終端需要以管理員權限啟動。 我這里以Windows Terminal為例,介紹如何默認使用管理員權限打開終端,具體操作如下圖所示: 2. 操作 wsl ......

    uj5u.com 2023-04-19 09:25:49 more
  • docker學習

    ###Docker概述 真實專案部署環境可能非常復雜,傳統發布專案一個只需要一個jar包,運行環境需要單獨部署。而通過Docker可將jar包和相關環境(如jdk,redis,Hadoop...)等打包到docker鏡像里,將鏡像發布到Docker倉庫,部署時下載發布的鏡像,直接運行發布的鏡像即可。 ......

    uj5u.com 2023-04-19 09:19:04 more
  • Linux學習筆記

    IP地址和主機名 IP地址 ifconfig可以用來查詢本機的IP地址,如果不能使用,可以通過install net-tools安裝。 Centos系統下ens33表示主網卡;inet后表示IP地址;lo表示本地回環網卡; 127.0.0.1表示代指本機;0.0.0.0可以用于代指本機,同時在放行設 ......

    uj5u.com 2023-04-18 06:52:01 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:50 more
  • 解決linux系統的kdump服務無法啟動的問題

    問題:專案麒麟系統服務器的kdump服務無法啟動,沒有相關日志無法定位問題。 1、查看服務狀態是關閉的,重啟系統也無法啟動 systemctl status kdump 2、修改grub引數,修改“crashkernel”為“512M(有的機器數值太大太小都會導致報錯,建議從128M開始試,或者加個 ......

    uj5u.com 2023-04-12 09:59:01 more
  • 你是不是暴露了?

    作者:袁首京 原創文章,轉載時請保留此宣告,并給出原文連接。 如果您是計算機相關從業人員,那么應該經歷不止一次網路安全專項檢查了,你肯定是收到過資訊系統技術檢測報告,要求你加強風險監測,確保你提供的系統服務堅實可靠了。 沒檢測到問題還好,檢測到問題的話,有些處理起來還是挺麻煩的,尤其是線上正在運行的 ......

    uj5u.com 2023-04-05 16:52:56 more
  • 細節拉滿,80 張圖帶你一步一步推演 slab 記憶體池的設計與實作

    1. 前文回顧 在之前的幾篇記憶體管理系列文章中,筆者帶大家從宏觀角度完整地梳理了一遍 Linux 記憶體分配的整個鏈路,本文的主題依然是記憶體分配,這一次我們會從微觀的角度來探秘一下 Linux 內核中用于零散小記憶體塊分配的記憶體池 —— slab 分配器。 在本小節中,筆者還是按照以往的風格先帶大家簡單 ......

    uj5u.com 2023-04-05 16:44:11 more