主頁 > 作業系統 > 一、uart&tty驅動

一、uart&tty驅動

2020-09-11 17:55:28 作業系統

  1 一.I.MX6 UART驅動
  2 檔案路徑:\linux_IMX6_CoreC_3.0.35_for_Linux\drivers\tty\serial\imx.c
  3 1.驅動入口函式:imx_serial_init()
  4 1.1    static int __init imx_serial_init(void)
  5           ret = uart_register_driver(&imx_reg);                //驅動加載的時候呼叫了這個函式注冊串口驅動,將引數imx_reg注冊進了tty層
  6             struct tty_driver *normal;
  7             normal = alloc_tty_driver(drv->nr);                //申請tty驅動,串口設備套上了一層tty驅動的外殼
  8             ...
  9             tty_set_operations(normal, &uart_ops);
 10             //上面這段代碼可以得出一個結論,uart_driver的資料型別其實就是tty_driver,兩者進行資料轉換之后注冊進了tty層,
 11             //tty_set_operations(normal, &uart_ops);將uart的操作函式和tty關聯起來,應用層對于tty的操作都將對應到uart的操作
 12 
 13             retval = tty_register_driver(normal);            //向TTY核心層注冊一個TTY驅動,所以串口設備其實就是一個tty型別的設備
 14                 alloc_chrdev_region(&dev, driver->minor_start, driver->num, driver->name);
 15                 register_chrdev_region(dev, driver->num, driver->name);
 16                 cdev_init(&driver->cdev, &tty_fops);        //初始化設備,注意這里將指標呼叫關系賦給了cdev
 17 
 18         ret = platform_driver_register(&serial_imx_driver);    //注冊平臺驅動
 19             //serial_imx_driver變數型別如下
 20             static struct platform_driver serial_imx_driver = {
 21             .probe        = serial_imx_probe,                    //當匹配到設備之后,這句函式得到呼叫,轉去分析這個函式
 22             .remove        = serial_imx_remove,
 23 
 24             .suspend    = serial_imx_suspend,
 25             .resume        = serial_imx_resume,
 26             .driver        = {
 27             .name    = "imx-uart",
 28             .owner    = THIS_MODULE,
 29             },
 30         };
 31 1.2    serial_imx_probe
 32         static int serial_imx_probe(struct platform_device *pdev)
 33             sport->port.dev = &pdev->dev;
 34             //imx_pops是串口接收資料、發送資料的相關函式(注意這里要區別前面的串口操作函式)
 35             //我覺得前面的串口操作函式是從應用層或者tty的角度來看,使用者也僅僅是應用層(tty層)
 36             //這里的imx_pops里面眾多的操作函式是從底層的角度去看,也就是底層和硬體相關的中斷接收、發送相關,
 37             sport->port.ops = &imx_pops;
 38             sport->port.flags = UPF_BOOT_AUTOCONF;
 39             sport->port.line = pdev->id;
 40             init_timer(&sport->timer);
 41             sport->timer.function = imx_timeout;
 42             sport->timer.data     = https://www.cnblogs.com/timemachine213/p/(unsigned long)sport;    
 43             ...
 44             ...
 45             ...
 46             ret = uart_add_one_port(&imx_reg, &sport->port);    //關鍵:為uart_driver增加一個埠
 47             //列出imx_pops重要的幾個函式
 48             static struct uart_ops imx_pops = {
 49                 ...
 50                 .stop_tx    = imx_stop_tx,
 51                 .start_tx    = imx_start_tx,                        //串口發送
 52                 .stop_rx    = imx_stop_rx,
 53                 .startup    = imx_startup,                        //中斷發送相關的函式,接下來我們分析這個發送函式
 54                 ...
 55             };
 56 
 57 1.3 static int imx_startup(struct uart_port *port)                //做一些串口的初始化操作
 58     {
 59         struct imx_port *sport = (struct imx_port *)port;
 60         struct tty_struct *tty;
 61         ...
 62         clk_enable(sport->clk);                                    //使能時鐘
 63 
 64         /* disable the DREN bit (Data Ready interrupt enable) before
 65          * requesting IRQs
 66         */
 67         temp = readl(sport->port.membase + UCR4);
 68         ...
 69         writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
 70         ...
 71         /*
 72          * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
 73         * chips only have one interrupt.
 74         */
 75         retval = request_irq(sport->rxirq, imx_rxint, 0, DRIVER_NAME, sport);//關鍵:在這里申請了接收中斷函式(同時注冊了中斷接收函式imx_rxint)
 76         ...
 77         retval = request_irq(sport->txirq, imx_txint, 0, DRIVER_NAME, sport);//申請注冊發送中斷函式(這次分析我們不關心發送中斷)
 78         /* Enable the SDMA for uart. */
 79         if (sport->enable_dma)                //如果配置串口使用DMA
 80         {
 81             int ret;
 82             ret = imx_uart_dma_init(sport);    //DMA的初始化
 83                 //下面幾句代碼都是DMA初始化相關,平臺通用,不展開說明啦
 84                 sport->dma_data.priority = DMA_PRIO_HIGH;
 85                 sport->dma_data.dma_request = pdata->dma_req_rx;
 86                 sport->dma_data.peripheral_type = IMX_DMATYPE_UART;
 87                 sport->dma_chan_rx = dma_request_channel(mask, imx_uart_filter, sport);
 88                 ...
 89                 slave_config.direction = DMA_DEV_TO_MEM;
 90                 slave_config.src_addr = sport->port.mapbase + URXD0;
 91             //注意:如果配置串口使用DMA,這里初始化了一個作業佇列(中斷下半部的一種),來進行資料的接收和發送
 92             //聽說3.0.35版本的內核DMA驅動有問題,不知道是不是真的,待證實,實際使用的時候,確實是發現DMA在連續傳輸大量資料的時候會出現資料丟失的情況
 93             INIT_WORK(&sport->tsk_dma_tx, dma_tx_work);
 94             INIT_WORK(&sport->tsk_dma_rx, dma_rx_work);                            //基于DMA的串口中斷接收函式,也是在這里注冊了一個作業佇列
 95                 dma_rx_work(struct work_struct *w)
 96                     tty_insert_flip_string(tty, sport->rx_buf, sport->rx_bytes);//關鍵的函式呼叫:將資料放到tty資料緩沖區
 97                         tty_insert_flip_string_fixed_flag(tty, chars, TTY_NORMAL, size);
 98                             struct tty_buffer *tb = tty->buf.tail;
 99                                 memcpy(tb->char_buf_ptr + tb->used, chars, space);
100                                 memset(tb->flag_buf_ptr + tb->used, flag, space);
101                     //如果不呼叫下面的函式,只是將資料放到tty緩沖區,tty也是獲取不到資料的
102                     tty_flip_buffer_push(tty);            //將緩沖區的資料推到tty當中,其實內部是一個作業佇列的調度(在tty初始化的時候注冊了這個作業佇列),等于是通知tty的線路規程獲取資料的意思
103                         schedule_work(&tty->buf.work);    //作業調度,實際上呼叫了flush_to_ldisc函式(這個函式好像不能在中斷中呼叫
104                                                         //,但是我發現也有其他驅動直接在中斷呼叫了,實際上我在中斷中呼叫業一直沒發現有什么問題)
105             init_waitqueue_head(&sport->dma_wait);
106         }
107         ...
108         spin_lock_irqsave(&sport->port.lock, flags);
109         /*
110         * Finally, clear and enable interrupts
111         */
112         writel(USR1_RTSD, sport->port.membase + USR1);    //使能中斷
113 
114     }
115     
116 1.4    //在前面剛進入函式的時候,我們申請了串口中斷,同時注冊了imx_rxint接收函式,接下來分析這個函式
117     retval = request_irq(sport->rxirq, imx_rxint, 0, DRIVER_NAME, sport);
118             spin_lock_irqsave(&sport->port.lock,flags);                //先獲取自旋鎖
119             
120             while (readl(sport->port.membase + USR2) & USR2_RDR)    //判斷串口暫存器狀態,開始接收位元組資料
121             {
122                 flg = TTY_NORMAL;
123                 sport->port.icount.rx++;
124                 rx = readl(sport->port.membase + URXD0);
125                 temp = readl(sport->port.membase + USR2);
126                 ...
127                 if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
128                     continue;
129                 if (rx & URXD_BRK)
130                     flg = TTY_BREAK;
131                 else if (rx & URXD_PRERR)
132                     flg = TTY_PARITY;
133                 else if (rx & URXD_FRMERR)
134                     flg = TTY_FRAME;
135                 if (rx & URXD_OVRRUN)
136                     flg = TTY_OVERRUN;
137             }
138             tty_insert_flip_char(tty, rx, flg);
139                 tty_insert_flip_string_flags(tty, &ch, &flag, 1);
140                     struct tty_buffer *tb = tty->buf.tail;
141                     memcpy(tb->char_buf_ptr + tb->used, chars, space);
142                     memcpy(tb->flag_buf_ptr + tb->used, flags, space);
143 out:
144     spin_unlock_irqrestore(&sport->port.lock,flags);//釋放自旋鎖
145     tty_flip_buffer_push(tty);//里面有作業佇列的調度,將資料“重繪”到tty
146     return IRQ_HANDLED;
147 
148 2.uart操作函式結構體
149 static const struct tty_operations uart_ops = {
150     .open        = uart_open,
151     .close        = uart_close,
152     .write        = uart_write,
153     .put_char    = uart_put_char,
154     ...
155     ...
156     ...
157 };
158 //從結構體的型別我們知道,uart_ops的資料型別就是tty_operations 型別,對應tty的檔案操作函式
159 //所以tty的操作路徑就對應著tty_ops-->uart_driver-->uart->ops
160 
161 3.uart_open函式
162     static int uart_open(struct tty_struct *tty, struct file *filp)
163         struct uart_driver *drv = (struct uart_driver *)tty->driver->driver_state;
164 
165 4.uart_close函式
166     static void uart_close(struct tty_struct *tty, struct file *filp)
167         struct uart_state *state = tty->driver_data;
168 
169 5.uart_write函式
170     static int uart_write(struct tty_struct *tty, const unsigned char *buf, int count)
171         struct uart_state *state = tty->driver_data;
172 //在前面,normal->driver_state    = drv;將串口的私有資料賦值給tty
173 //上面3、4、5這幾個函式是在我們打開串口或者做串口操作的時候,將資料從tty拿出來(因為打開串口的時候,
174 //就是tty去操作設備號對應將設備的資訊傳遞到驅動中來)
175 //這幾個函式都是應用層在操作串口的時候才會呼叫,與串口資料發送沒有關系,所以就不展開分析了,
176 
177 
178 二、tty驅動分析(不針對特定處理器平臺)
179 檔案路徑:\linux_IMX6_CoreC_3.0.35_for_Linux\drivers\tty\tty_io.c
180          \linux_IMX6_CoreC_3.0.35_for_Linux\drivers\tty\tty_buffer.c
181          \linux_IMX6_CoreC_3.0.35_for_Linux\drivers\tty\tty_ldisc.c
182 tty由上往下分為tty核心層、tty線路規程、tty驅動,用戶空間對應tty設備的操作函式定義及實作都在tty_io.c中,
183 tty核心層不能直接從tty驅動獲取資料,底層的資料經過tty驅動,在經過tty線路規程,再到tty核心層,
184 1. 線路規程的初始化
185 //線路規程的初始化是在內核剛啟動的時候完成的,檔案路徑是\init\main.c
186 asmlinkage void __init start_kernel(void)
187     console_init();
188         /* Setup the default TTY line discipline. */
189         tty_ldisc_begin();
190             /* Setup the default TTY line discipline. */
191             (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
192             //分析tty_ldisc_N_TTY結構體變數(屬于tty_ldisc_ops型別,接著分析tty_ldisc_ops)
193 1.1 tty_ldisc_ops(線路規程操作函式結構體)
194     struct tty_ldisc_ops tty_ldisc_N_TTY = 
195     {
196         .magic           = TTY_LDISC_MAGIC,
197         .name            = "n_tty",
198         .open            = n_tty_open,
199         .close           = n_tty_close,
200         .flush_buffer    = n_tty_flush_buffer,
201         .chars_in_buffer = n_tty_chars_in_buffer,
202         .read            = n_tty_read,
203         .write           = n_tty_write,
204         .ioctl           = n_tty_ioctl,
205         .set_termios     = n_tty_set_termios,
206         .poll            = n_tty_poll,
207         .receive_buf     = n_tty_receive_buf,
208         .write_wakeup    = n_tty_write_wakeup
209     };
210 //以上這些函式就是tty線路規程在操作資料時候用到的函式,從tty應用層操作向下看就是tty_ops--->tty_ldisc_ops
211 //前面分析uart驅動時候uart_ops和實際的資料接收和發送函式是分開的,在這里也是類似,
212 //操作設備是一組函式,實際做資料收發的又是另外一組函式,
213 1.1.1 n_tty_open函式
214     static int n_tty_open(struct tty_struct *tty)
215         tty->read_buf = kzalloc(N_TTY_BUF_SIZE, GFP_KERNEL);//分配tty緩沖區給tty_read_buf,其中N_TTY_BUF_SIZE為4096
216         ...
217         reset_buffer_flags(tty);//初始化頭尾指標、讀計數等
218             tty->read_head = tty->read_tail = tty->read_cnt = 0;
219 1.1.2 n_tty_write函式
220     static ssize_t n_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *buf, size_t nr)
221         ...
222         //這里呼叫到了tty_driver操作函式,因為在之前的tty_open函式中有了tty->ops=driver->ops這樣的操作,
223         //注冊的時候初始化了ops
224         tty->ops->flush_chars(tty);
225         ...
226         c = tty->ops->write(tty, b, nr);
227         
228 1.1.3 n_tty_read函式
229     static ssize_t n_tty_read(struct tty_struct *tty, struct file *file, unsigned char __user *buf, size_t nr)
230         ...
231         ...
232         while (nr)
233         {
234             c = tty->read_buf[tty->read_tail];//從tty讀緩沖區獲取資料
235             ...
236             tty_put_user(tty, c, b++);
237                 tty_audit_add_data(tty, &x, 1);
238                 put_user(x, ptr);
239             uncopied = copy_from_read_buf(tty, &b, &nr);
240             uncopied += copy_from_read_buf(tty, &b, &nr);
241         }
242 //注意這里tty線路規程對資料的讀操作并沒有呼叫到tty驅動層的讀函式,
243 //和tty線路規程對資料的寫操作要做個對比和區別,
244 //tty的資料讀取是“被動”讀取的,簡單講就是通過串口中斷接收位元組,然后調度tty初始化時候注冊的作業佇列來實作資料的讀取,
245 //對應的函式是:
246     flush_to_ldisc();
247         ...
248         disc->ops->receive_buf(tty, char_buf,flag_buf, count);//具體呼叫的函式是n_tty_receive_buf函式
249         ...
250 2. int __init tty_init(void)
251     //初始化tty設備,tty設備本質上也是一個字符設備
252     //用戶空間對于tty設備的操作都對應到tty_fops結構體里面的函式
253     cdev_init(&tty_cdev, &tty_fops);//我們重點分析tty操作函式結構體里面的函式集合
254     cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1);
255     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty");
256     device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");//創建設備
257     //初始化tty設終端(關于tty的終端,我們暫時不分析)
258     cdev_init(&console_cdev, &console_fops);
259     register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console");
260     consdev = device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
261     ...
262 2.1 tty_buffer_init()函式
263         INIT_WORK(&tty_buf.work, flush_to_ldisc);//flush_to_ldisc函式系結到作業佇列,當tty_filp_buffer_push函式中呼叫schedule_work(&tty->buf.work);時候,函式得到呼叫
264 2.2 tty_fops結構體
265     static const struct file_operations tty_fops = {
266         .llseek        = no_llseek,
267         .read        = tty_read,                            //注意這里的read函式不是對應uart操作函式里面的read函式(需要做關聯),后面會講到
268         .write        = tty_write,                        //同上
269         .poll        = tty_poll,
270         .unlocked_ioctl    = tty_ioctl,
271         .compat_ioctl    = tty_compat_ioctl,
272         .open        = tty_open,
273         .release    = tty_release,
274         .fasync        = tty_fasync,
275     };
276 
277 2.3 tty_open函式(打開tty設備時候做的一些初始化操作,建立tty核心和線路規程以及硬體驅動的聯系)
278     static int tty_open(struct inode *inode, struct file *filp)
279         struct tty_driver *driver;
280         int index;
281         dev_t device = inode->i_rdev;
282         ...
283         tty = get_current_tty();
284         tty_free_file(filp);
285         ...
286         driver = tty_driver_kref_get(tty->driver);
287         ...
288         driver = get_tty_driver(device, &index);        //根據設備號,來查找到tty_driver
289         tty = tty_init_dev(driver, index, 0);            //初始化tty結構體
290             initialize_tty_struct(tty, driver, idx);    //關鍵的一個初始化,在里面建立tty核心層和線路規程的聯系
291                 tty_ldisc_init(tty);                    //初始化線路規程
292                 tty->buf.head = tty->buf.tail = NULL;    //緩沖區頭尾指空
293                 tty_buffer_init(tty);                    //初始化tty緩沖區
294                     spin_lock_init(&tty->buf.lock);
295                     tty->buf.head= NULL;
296                     tty->buf.tail= NULL;
297                     tty->buf.free= NULL;
298                     tty->buf.memory_used= 0;
299                     //初始化了一個作業佇列
300                     //當在驅動層里receive_chars的最后呼叫了tty_flip_buffer_push這個函式的時候這個隊里得到調度
301                     INIT_DELAYED_WORK(&tty->buf.work, flush_to_ldisc);//在中斷下半部中進行調度時候,flush_to_ldisc會得到呼叫,接下來分析這個函式
302                 ...
303                 tty->ops = driver->ops;                    //tty操作指向tty設備操作(注意這里是指向具體的硬體設備驅動操作)
304                 tty->dev = tty_get_device(tty);
305                     dev_t devt = tty_devnum(tty);        //獲得設備號
306                     ...
307             retval = tty_driver_install_tty(driver, tty);
308             ...
309             retval = tty_ldisc_setup(tty, tty->link);    //設定線路規程
310                 retval = tty_ldisc_open(tty, ld);        //打開線路規程
311                 tty_ldisc_enable(tty);                    //使能線路規程
312         ...
313         tty_add_file(tty, filp);
314         check_tty_count(tty, "tty_open");                //檢查tty被打開多少次
315         ...
316         retval = tty->ops->open(tty, filp);                //實際上就是driver->ops->open(注意這里的driver指的是具體硬體的driver)
317 2.3.1 tty_flip_buffer_push函式
318     void tty_flip_buffer_push(struct tty_struct *tty)
319         ...
320         ...
321         ...
322         if (tty->low_latency)
323             flush_to_ldisc(&tty->buf.work.work);
324         else
325             schedule_work(&tty->buf.work);//作業佇列調度,內核執行緒???會呼叫flush_to_ldisc
326 
327 2.3.2 flush_to_ldisc函式
328 //從tty_buffer中找到資料緩沖區char_buf_ptr,并將這個緩沖區指標傳遞給線路規程的操作函式receive_buf,
329 //拷貝資料進tty的read_buf
330     flush_to_ldisc(struct work_struct *work)
331         disc->ops->receive_buf(tty, char_buf, flag_buf,count);
332             n_tty_receive_buf(struct tty_struct *tty, const unsigned char*cp, char *fp, int count);
333                 n_tty_receive_char(tty,*p);
334                 ...
335                 if(tty->ops->flush_chars)
336                     tty->ops->flush_chars(tty);
337 
338 2.4 tty_write函式(應用層呼叫)
339     static ssize_t tty_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
340         struct tty_struct *tty = file_tty(file);
341          struct tty_ldisc *ld;                                        //tty線路規程結構體,這個結構體很重要
342         ...
343         ld = tty_ldisc_ref_wait(tty);                                //等待tty線路規程(所有從tty驅動上來的資料或者從應用層到tty驅動的資料,都要經過線路規程)
344         ret = do_tty_write(ld->ops->write, tty, file, buf, count);    //do_tty_write這里實際上是呼叫了ld->ops->write(也就是線路規程的write函式,將資料寫入tty緩沖區)
345                 //等價于呼叫n_tty_write函式
346                 //在n_tty_write函式中呼叫下面tty driver中的操作函式
347                 tty->ops->flush_chars(tty);
348                 ...
349                 c = tty->ops->write(tty, b, nr);
350             copy_from_user(tty->write_buf, buf, size);                //從用戶空間拷貝資料到tty寫緩沖中
351 
352 2.5 tty_read函式(應用層呼叫)
353     static ssize_t tty_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
354         ...
355         struct tty_struct *tty = file_tty(file);
356         ...
357         i = (ld->ops->read)(tty, file, buf, count);//呼叫線路規程里面的read函式(n_tty_read)
358             //下面這幾句代碼是n_tty_read函式的
359             while (nr)
360             {
361                 c = tty->read_buf[tty->read_tail];//從tty讀緩沖區獲取資料,實際上是在tty->read_buf的末尾tty->read_tail中讀取資料
362                 ...
363                 tty_put_user(tty, c, b++);
364                     tty_audit_add_data(tty, &x, 1);
365                     put_user(x, ptr);
366                 uncopied = copy_from_read_buf(tty, &b, &nr);
367                 uncopied += copy_from_read_buf(tty, &b, &nr);
368             }

 

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

標籤:嵌入式

上一篇:無線傳感網——zigbee基礎實驗-按鍵控制燈光開關

下一篇:《痞子衡嵌入式半月刊》 第 6 期

標籤雲
其他(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