最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Linux多路轉(zhuǎn)接之select函數(shù)使用方式

 更新時間:2024年08月01日 09:41:49   作者:zzu_ljk  
這篇文章主要介紹了Linux多路轉(zhuǎn)接之select函數(shù)使用方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

首先我們要了解一下,什么是多路轉(zhuǎn)接?

多路轉(zhuǎn)接也叫多路復用,是一種用于管理多個IO通道的技術。

它能實現(xiàn)同時監(jiān)聽和處理多個IO事件,而不是為每個IO通道創(chuàng)建單獨的線程或者進程,多路轉(zhuǎn)接允許在單個進程或線程中同時處理多個IO操作,從而提高程序的性能和效率。

本篇文章介紹的select函數(shù),就用于select系統(tǒng)調(diào)用的多路轉(zhuǎn)接技術。

1. 認識select函數(shù)

select函數(shù)是系統(tǒng)提供的一個多路轉(zhuǎn)接接口。

IO = 等待就緒 + 數(shù)據(jù)拷貝,而select是只負責等。

  • select系統(tǒng)調(diào)用可以讓我們的程序同時監(jiān)聽多個文件描述符上的事件是否就緒。
  • select的核心工作就是等,當監(jiān)聽的多個文件描述符中有一個或多個事件就緒時,select函數(shù)才會成功返回并將對應文件描述符的就緒事件告知調(diào)用者。

2. select函數(shù)原型

參數(shù)說明:

  • nfds:需要監(jiān)聽的文件描述符中,最大的文件描述符值 + 1。
  • readfs:輸入輸出型參數(shù),調(diào)用時用戶告知內(nèi)核需要監(jiān)聽哪些文件描述符的讀事件是否就緒,返回時內(nèi)核告訴用戶哪些文件描述符的讀事件已經(jīng)就緒。
  • writefds:輸入輸出型參數(shù),調(diào)用時用戶告知內(nèi)核需要監(jiān)聽哪些文件描述符的寫事件是否就緒,返回時內(nèi)核告知用戶哪些文件描述符的寫事件已經(jīng)就緒。
  • exceptfds:輸入輸出型參數(shù),調(diào)用時告知內(nèi)核需要監(jiān)聽哪些文件描述符的異常事件是否就緒,返回時內(nèi)核告知用戶哪些文件描述符的異常事件已經(jīng)就緒。
  • timeout:輸入輸出參數(shù),調(diào)用時由用戶設置select的等待時間,返回時表示timeout的剩余時間。

參數(shù)timeout的取值:

  • NULL/nullptr:select調(diào)用后進行阻塞等待,直到被監(jiān)視的某個文件描述符上的事件就緒。
  • 0:select調(diào)用后進行非阻塞等待,無論被監(jiān)視的文件描述符的事件是否就緒,select檢測后都會立即返回。
  • 特定的時間值:select調(diào)用后在指定的時間內(nèi)進行阻塞等待,如果被監(jiān)視的文件描述符上一直沒有事件就緒,則在該時間后select進行超時返回。

返回值說明:

  • 如果函數(shù)調(diào)用成功,則返回有事件就緒的文件描述符個數(shù)。
  • 如果timeout時間耗盡,則返回0。
  • 如果函數(shù)調(diào)用失敗,則返回-1,同時錯誤碼會被設置。

select調(diào)用失敗,錯誤碼可能被設置為:

  • EBADF:文件描述符有無效的或者該文件已關閉
  • EINTR:此調(diào)用被信號所中斷
  • EINVAL:參數(shù)nfds為負值
  • ENOMEM:核心內(nèi)存不足

fd_set 結(jié)構(gòu)

fd_set 結(jié)構(gòu)與 sigset_t 結(jié)構(gòu)類似,fd_set 本質(zhì)也是一個位圖,用位圖中對應的位來表示要監(jiān)聽的文件描述符。

調(diào)用select函數(shù)之前就需要用fd_set結(jié)構(gòu)定義出對應的文件描述符集,然后將需要監(jiān)視的文件描述符添加到文件描述符集當中,這個添加的過程本質(zhì)就是在進行位操作,但是這個位操作不需要用戶自己進行,系統(tǒng)專門提供了一組專門的接口,用戶對fd_set位圖進行各種操作。

timeval 結(jié)構(gòu)

傳入select函數(shù)的最后一個參數(shù)timeout,就是一個指向timeval結(jié)構(gòu)的指針,timeval結(jié)構(gòu)用于描述一段時間長度,該結(jié)構(gòu)當中包含兩個成員,其中tv_sec表示的是秒,tv_usec表示的是微妙。

3. socket就緒條件

讀就緒

  • socket內(nèi)核中,接收緩沖區(qū)中的字節(jié)數(shù),大于等于低水位標記物SO_RCVLOWAT,此時可以無阻塞地讀取該文件描述符,并且返回值大于0。
  • socket TCP通信中,對端連接關閉,此時對該socket讀,則返回0。
  • 監(jiān)聽的socket上有新的連接請求。
  • socket上有未處理的錯誤。

寫就緒

  • socket內(nèi)核中,發(fā)送緩沖區(qū)中的可用字節(jié)數(shù),大于等于低水位標記SO_SNDLOWAT,此時可以無阻塞地寫,并且返回值大于0。
  • socket的寫操作被關閉(close或者shutdown),對一個寫操作被關閉的socket進行寫操作,會觸發(fā)SIGPIPE信號。
  • socket使用非阻塞connect連接成功或失敗之后。
  • socket上有未讀取的錯誤。

異常就緒

  • socket上收到帶外數(shù)據(jù)

4. select工作流程

這里我們只介紹select處理讀取的操作。

如果我們要實現(xiàn)一個簡單的select服務器,該服務器要做的就是讀取客戶端發(fā)來的數(shù)據(jù)并進行打印,那么這個select服務器的工作流程應該是這樣的:

  • 先初始化服務器,完成套接字的創(chuàng)建、綁定和監(jiān)聽。
  • 定義一個fd_array數(shù)組用于保存監(jiān)聽套接字和已經(jīng)與客戶端建立連接的套接字,剛開始時就將監(jiān)聽套接字添加到fd_array數(shù)組當中。
  • 然后服務器開始循環(huán)調(diào)用select函數(shù),檢測讀事件是否就緒,如果就緒則執(zhí)行對應的操作。
  • 每次調(diào)用select函數(shù)之前,都需要定義一個讀文件描述符集readfds,并將fd_array當中的文件描述符依此設置進readfds當中,表示讓select幫我們監(jiān)視這些文件描述符的讀事件是否就緒。
  • 當select檢測到數(shù)據(jù)就緒時會讀事件就緒的文件描述符設置進readfds當中,此時我們能夠得知哪些文件描述符的讀事件就緒了,并對這些文件描述符進行對應的操作。
  • 如果讀事件就緒的就是監(jiān)聽套接字,則調(diào)用accept函數(shù)從底層全連接隊列獲取已經(jīng)建立好的連接,并將該連接對應的套接字添加到fd_array數(shù)組當中。
  • 如果讀事件就緒的是與客戶端建議連接的套接字,則調(diào)用read函數(shù)讀取客戶端發(fā)來的數(shù)據(jù)并進行打印輸出。
  • 當然,服務器與客戶端建立連接的套接字讀事件就緒,也可能是因為客戶端將連接關閉了,此時服務器應該調(diào)用close關閉套接字,并將該套接字從fd_array中清除,因為下一次不需要再監(jiān)視該文件描述符的讀事件了。

注意:

  • 因為傳入的select函數(shù)的readfds、writefds和exceptfds都是輸入輸出型參數(shù),當select函數(shù)返回時這些參數(shù)當中的值已經(jīng)被修改了,因此每次調(diào)用seletct函數(shù)時都需要對其進行重新設置,timeout也是類似的道理。
  • 因為每次調(diào)用select函數(shù)之前都需要對readfds進行重新設置,所以需要定義一個fd_array數(shù)組保存與客戶端已經(jīng)建立的若干連接和監(jiān)聽套接字,實際fd_array數(shù)組當中的文件描述符就是需要讓select監(jiān)視讀事件的文件描述符。
  • 我們的select服務器只是讀取客戶端發(fā)來的數(shù)據(jù),因此只需讓select幫我們監(jiān)視特定文件描述符的讀事件,如果同時讓select幫我們監(jiān)視特定文件描述符的讀事件和寫事件,則需要分別定義readfds和writefds,并定義兩個數(shù)組分別保存需要被監(jiān)視讀事件和寫事件的文件描述符,便于每次調(diào)用select函數(shù)前對readfds和writefds進行重新設置。
  • 服務器剛開始運行時,fd_array數(shù)組當中只有監(jiān)聽套接字,因此select第一次調(diào)用時只需要監(jiān)視監(jiān)聽套接字的讀事件是否就緒,但每次調(diào)用accept獲取到新連接之后,都會將連接對應的套接字添加到fd_array當中,因此后續(xù)select調(diào)用時就需要監(jiān)視監(jiān)聽套接字和若干連接套接字的讀事件是否就緒。
  • 由于調(diào)用select時還需要傳入被監(jiān)視的文件描述符中最大文件描述符值+1,因此每次在遍歷fd_array對readfds進行重新設置時,還需要記錄最大文件描述符的值。

5. select服務器

Socket類

我們編寫一個Socket類,對套接字相關的接口進行一定程序的封裝,為了讓外部能夠直接調(diào)用Socket類當中的函數(shù),我們將這些成員函數(shù)定義成靜態(tài)成員函數(shù)。

#pragma once

#include <iostream>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <cstring>
#include <cstdlib>

class Socket
{
public:
    // 創(chuàng)建套接字
    static int SocketCreate()
    {
        int sock = socket(AF_INET, SOCK_STREAM, 0);
        if (sock < 0)
        {
            std::cerr << "socket error" << std::endl;
            exit(2);
        }

        // 設置端口復用
        int opt = 1;
        setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
        return sock;
    }

    // 綁定
    static void SocketBind(int sock, int port)
    {
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port);
        local.sin_addr.s_addr = INADDR_ANY;

        socklen_t len = sizeof(local);

        if (bind(sock, (struct sockaddr*)&local, len) < 0)
        {
            std::cerr << "bind error" << std::endl;
            exit(3);
        }
    }

    // 監(jiān)聽
    static void SocketListen(int sock, int backlog)
    {
        if (listen(sock, backlog) < 0)
        {
            std::cerr << "listen error" << std::endl;
            exit(4);
        }
    }
};

SelectServer類

編寫SelectServer類,因為我當前使用的是云服務器,所以編寫的select服務器在綁定時只需將IP地址設置為INADDR_ANY即可,所以類中只包含監(jiān)聽套接字和端口號兩個成員變量即可。

  • 在構(gòu)造SelectServer對象時,需要指明select服務器的端口號,當然也可以在初始化select服務器的時候指明。
  • 在初始化select服務器的時候需要調(diào)用Socket類當中的函數(shù),依此進行套接字的創(chuàng)建、綁定和監(jiān)聽即可。
  • 在析構(gòu)函數(shù)中可以選擇調(diào)用close函數(shù)將監(jiān)聽套接字進行關閉,但實際也可以不進行該動作,因為服務器運行后一般是不退出的。
#pragma once

#include "Socket.hpp"
#include <sys/select.h>

#define BACK_LOG 5

class SelectServer
{
public:
    SelectServer(int port)
        : _port(port)
    {}

    void InitSelectServer()
    {
        _listen_sock = Socket::SocketCreate();
        Socket::SocketBind(_listen_sock, _port);
        Socket::SocketListen(_listen_sock, BACK_LOG);
    }

    ~SelectServer()
    {
        if (_listen_sock >= 0) close(_listen_sock);
    }

private:
    int _listen_sock;
    int _port;
};

運行服務器

服務器初始化完畢之后就可以周期性地執(zhí)行某種動作了,而select服務器要做的就是不斷調(diào)用select函數(shù),當事件就緒對應執(zhí)行某種動作即可。

  • 首先,在select服務器開始死循環(huán)調(diào)用select函數(shù)之前,需要先定義一個fd_array數(shù)組,先把數(shù)組中所有的位置初始化為無效,并將監(jiān)聽套接字添加到該數(shù)組當中,fd_array數(shù)組當中保存的就是需要被select監(jiān)視讀事件是否就緒的文件描述符。
  • 此后,select服務器就不斷調(diào)用select函數(shù)監(jiān)視讀事件是否就緒,每次調(diào)用select函數(shù)之前都需要重新設置readfds,具體設置過程就是遍歷fd_array數(shù)組,將fd_array數(shù)組當中的文件描述符添加到readfds當中,并同時記錄最大的文件描述符maxfd。
  • 當select函數(shù)返回后,如果返回值為0,則說明timeout時間耗盡,此時直接準備下一次select調(diào)用即可。如果select的返回值為-1,則說明select調(diào)用失敗,此時也讓服務器準備下一次select調(diào)用,但實際應該進一步判斷錯誤碼,根據(jù)錯誤碼來判斷是否應該繼續(xù)調(diào)用select函數(shù)。
  • 如果select函數(shù)的返回值大于0,則說明select函數(shù)調(diào)用成功,此時已經(jīng)有文件描述符的讀事件就緒,接下來就應該對就緒事件進行處理。
#pragma once

#include "Socket.hpp"
#include <sys/select.h>

#define BACK_LOG 5
#define NUM 1024
#define DFL_FD - 1

class SelectServer
{
public:
    SelectServer(int port)
        : _port(port)
    {}

    void InitSelectServer()
    {
        _listen_sock = Socket::SocketCreate();
        Socket::SocketBind(_listen_sock, _port);
        Socket::SocketListen(_listen_sock, BACK_LOG);
    }

    ~SelectServer()
    {
        if (_listen_sock >= 0) close(_listen_sock);
    }

    void Run()
    {
        fd_set readfds; // 創(chuàng)建讀文件描述符集
        int fd_array[NUM]; // 保存需要被監(jiān)視讀事件是否就緒的文件描述符
        ClearFdArray(fd_array, NUM, DFL_FD); // 將數(shù)組中的所有位置設置為無效
        fd_array[0] = _listen_sock; // 將監(jiān)聽套接字添加到fd_array數(shù)組中的第0個位置
        while (1)
        {
            FD_ZERO(&readfds); // 清空readfds
            // 將fd_array數(shù)組當中的文件描述符添加到readfds中,并記錄最大的文件描述符
            int maxfd = DFL_FD;
            for (int i = 0; i < NUM; ++i)
            {
                if (fd_array[i] == DFL_FD) continue; // 跳過無效的位置
                FD_SET(fd_array[i], &readfds);  // 將有效位置的文件描述符添加到readfds中
                if (fd_array[i] > maxfd) maxfd = fd_array[i]; // 更新最大文件描述符
            }

            switch (select(maxfd + 1, &readfds, nullptr, nullptr, nullptr))
            {
                case 0:
                    std::cout << "timeout..." << std::endl;
                    break;
                case -1:
                    std::cerr << "select error" << std::endl;
                    break;
                default:
                    std::cout << "有事件發(fā)生..." << std::endl;
                    break; 
            }
        }

    }

private:
    void ClearFdArray(int fd_array[], int num, int default_fd)
    {
        for (int i = 0; i < num; ++i) fd_array[i] = default_fd;
    }

    int _listen_sock;
    int _port;
};

啟動服務器

#include "SelectServer.hpp"
#include <string>

int main(int argc, char* argv[])
{
    if (argc != 2)
    {
        std::cerr << "Usage: " << "SelectServer" << " port" << std::endl;
        exit(1);
    }
    int port = atoi(argv[1]);

    SelectServer* svr = new SelectServer(port);
    svr->InitSelectServer();
    svr->Run();

    return 0;
}

由于當前服務器調(diào)用select函數(shù)時直接將timeout設置為了nullptr,因此select函數(shù)調(diào)用后會進行阻塞等待。

而服務器在第一次調(diào)用select函數(shù)時只讓select函數(shù)監(jiān)視監(jiān)聽套接字的讀事件,所以運行服務器之后如果沒有客戶端發(fā)來連接請求,那么讀事件就不會就緒,而服務器會一直在第一次調(diào)用的select函數(shù)中進行阻塞等待。

當我們借助telnet工具向select服務器發(fā)起連接請求之后,select函數(shù)就會立馬檢測到監(jiān)聽套接字的讀事件就緒,此時select函數(shù)便會返回成功,并將我們設置的提示語句進行打印輸出,因為當前程序沒有對就緒事件進行處理,此后每次select函數(shù)一調(diào)用就會檢測到讀事件就緒成功返回,因此屏幕不但打印輸出提示語句。

如果服務器在調(diào)用select函數(shù)時將timeout的值設置為0,那么select函數(shù)調(diào)用后就會進行非阻塞等待,無論被監(jiān)視的文件描述符上的事件是否就緒,select檢測后都會立即返回。

此時如果select監(jiān)視的文件描述符上有事件就緒,那么select函數(shù)的返回值就是大于0的,如果select函數(shù)監(jiān)視的文件描述符上沒有事件就緒,那么select的返回值就是小于0的,這里也就不進行演示了。

事件處理

當select檢測到右文件描述符的讀事件就緒并成功返回后,接下來就應該對就緒事件進行處理了,這里編寫一個HandleEvent函數(shù),當讀事件就緒之后就調(diào)用該函數(shù)進行事件處理。

  • 在進行事件處理時需要遍歷fd_array數(shù)組當中的文件描述符,以此判斷各個文件描述符對應的讀事件是否就緒,如果就緒則需要進行事件處理。
  • 當一個文件描述符的讀事件就緒之后,還需要進一步判斷該文件描述符是否是監(jiān)聽套接字,如果是監(jiān)聽套接字的讀事件就緒,那么就應該調(diào)用accept函數(shù)將底層的連接獲取上來。但是只調(diào)用accept函數(shù)將連接獲取上來還不夠,為了下一次調(diào)用select函數(shù)時能夠讓select幫我們監(jiān)視新連接的事件是否就緒,在連接獲取上來后還應該將連接對應的文件描述符添加到fd_array數(shù)組當中,這樣在下一次調(diào)用select函數(shù)前對readfds重新設置時就能將該文件描述符添加進去了。
  • 如果是客戶端建立的連接對應的讀事件就緒,那么就應該調(diào)用read函數(shù)讀取客戶端發(fā)來的連接,如果讀取成功則將讀到的數(shù)據(jù)在服務端進行打印。如果調(diào)用read函數(shù)讀取失敗或者客戶端關閉了連接,那么select服務器也應該調(diào)用close函數(shù)關閉對應的連接,但此時只關閉連接也是不夠的,還應該將該連接對應的文件描述符從fd_array數(shù)組當中清除,否則后續(xù)調(diào)用的select函數(shù)還會幫我們監(jiān)視該連接的讀事件是否就緒,但實際已經(jīng)不需要了。
    void HandleEvent(const fd_set& readfds, int fd_array[], int num)
    {
        for (int i = 0; i < num; ++i)
        {
            // 跳過無效位置
            if (fd_array[i] == DFL_FD) continue;
                
            // 連接事件就緒
            if (fd_array[i] == _listen_sock && FD_ISSET(fd_array[i], &readfds))
            {
                // 獲取連接
                struct sockaddr_in peer;
                memset(&peer, 0, sizeof(peer));
                socklen_t len = sizeof(peer);
                int sock = accept(_listen_sock, (struct sockaddr*)&peer, &len);
                if (sock < 0)
                {
                    std::cerr << "accept error" << std::endl;
                    continue;
                }
                std::string peer_ip = inet_ntoa(peer.sin_addr);
                int peer_port = ntohs(peer.sin_port);
                std::cout << "get a new link[" << peer_ip << ":" << peer_port << "]" << std::endl;
                // 將獲取到的文件描述符添加到fd_array中
                if (!SetFdArray(fd_array, num, sock))
                {
                    // 如果添加失敗,關閉文件描述符
                    close(sock);
                    std::cout << "select server is full, close fd: " << sock << std::endl;
                }
            }
        }
    }

private:
    bool SetFdArray(int fd_array[], int num, int fd)
    {
        for (int i = 0; i < num; ++i)
        {
            if (fd_array[i] == DFL_FD) 
            {
                fd_array[i] = fd;
                return true;
            }
        }
        return false;
    }

添加文件描述符到fd_array數(shù)組中,本質(zhì)就是遍歷fd_array數(shù)組,找到一個沒有被使用的位置將該文件描述符添加進去即可。

但有可能fd_array數(shù)組中全部的位置都已經(jīng)被占用了,那么文件描述符就會添加失敗,此時就只能將剛剛獲取上來的連接對應的套接字進行關閉,因為此時服務器是沒有能力處理這個連接的。

該select服務器存在的一些問題

  • 服務器沒有對客戶端進行響應,select服務器如果要向客戶端發(fā)送數(shù)據(jù),不能直接調(diào)用write函數(shù),因為調(diào)用write函數(shù)時實際也為了“等”和“拷貝”兩步,我們也應該將“等”的這個過程交給select函數(shù),因此在每次調(diào)用select函數(shù)之前,除了需要重新設置readfds之外還需要重新設置writefds,并且還需要一個數(shù)組來保存需要被監(jiān)視事件是否就緒的文件描述符,當某一文件描述符的寫事件就緒時我們才能夠調(diào)用write函數(shù)向客戶端發(fā)送數(shù)據(jù)。
  • 沒有定制協(xié)議,代碼中讀取數(shù)據(jù)時并沒有按照某種規(guī)則進行讀取,此時就可能造成粘包問題。比如HTTP協(xié)議規(guī)定在讀取底層數(shù)據(jù)時讀取到空行就表明讀完了一個HTTP報頭,此時再根據(jù)HTTP報頭當中的Content-Length屬性得知正文的長度,最終就能讀取到一個完整的HTTP報文,HTTP協(xié)議通過這種方式就避免了粘包問題。
  • 沒有對應的輸入輸出緩沖區(qū),代碼中直接將讀取的數(shù)據(jù)存儲到了字符數(shù)組buffer中,這是不嚴謹?shù)?,因為本地?shù)據(jù)讀取可能并沒有讀取到一個完整的報文,此時服務器就不能進行數(shù)據(jù)的分析處理,一個將讀取到的數(shù)據(jù)存儲到一個輸入緩沖區(qū)中,當讀取到一個完整的報文之后再讓服務器進行處理。此外,如果服務器能夠?qū)蛻舳诉M行響應,那么服務器的響應數(shù)據(jù)也不應該直接調(diào)用write函數(shù)發(fā)送給客戶端,應該先存儲到一個輸出緩沖區(qū)當中,因為響應數(shù)據(jù)可能很龐大,無法一次發(fā)送完畢,可能需要進行分批發(fā)送。

6. select的優(yōu)缺點

select的優(yōu)點

  • 可以同時等待多個文件描述符,并且只負責等待,實際的IO操作由accept、read、write等接口完成,這些接口在進行IO操作時不會被阻塞。
  • select同時等待多個文件描述符,因此可以將“讀”的時間重疊,提高了IO的效率。

當然,這也是所有多路轉(zhuǎn)接接口的優(yōu)點。

select的缺點

  • 每次調(diào)用select,都需要手動設置fd集合,從接口使用角度來看并不方便。
  • 每次調(diào)用select,都需要把fd集合從用戶態(tài)拷貝到內(nèi)核態(tài),這個開銷在fd很多時會很大。
  • 同時每次調(diào)用select時都需要在內(nèi)核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大。
  • select可監(jiān)控的文件描述符數(shù)量太少。

select可監(jiān)控的文件描述符有1024個,除去其中的一個監(jiān)聽套接字,那么它最多只能連接1023個客戶端。

總結(jié)

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • 詳解ubuntu下安裝Docker

    詳解ubuntu下安裝Docker

    本篇文章主要介紹了ubuntu下安裝Docker,詳細的介紹了安裝Docker的情況,具有一定的參考價值,有需要的一起來了解一下。
    2016-12-12
  • Linux使用iptables限制多個IP訪問你的服務器

    Linux使用iptables限制多個IP訪問你的服務器

    iptables是一個管理netfilter的工具。這篇文章主要介紹了Linux使用iptables限制多個IP訪問你的服務器的相關知識,需要的朋友可以參考下
    2018-10-10
  • centos服務器下nginx圖片防盜鏈設置方法

    centos服務器下nginx圖片防盜鏈設置方法

    本篇文章主要介紹了centos服務器下nginx防盜鏈設置方法,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-03-03
  • GNU Parallel的具體使用

    GNU Parallel的具體使用

    這篇文章主要介紹了GNU Parallel的具體使用,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2019-01-01
  • apache2.2和php5.2.17在windows下整合過程的錯誤解決方法

    apache2.2和php5.2.17在windows下整合過程的錯誤解決方法

    照理來說apache和php的整合應該是非常簡單的,apache下載windows安裝版本后一路next即可完成安裝,php下載解壓版本后直接解壓到指定目錄,然后在apache的配置文件httpd.conf的最后加入如下幾行即可
    2011-08-08
  • Linux SSD磁盤的優(yōu)化配置指南

    Linux SSD磁盤的優(yōu)化配置指南

    在現(xiàn)代 Linux 系統(tǒng)中,固態(tài)硬盤(SSD)已經(jīng)成為主流存儲設備,相比傳統(tǒng)機械硬盤(HDD),SSD 具有更快的讀寫速度、更低的延遲和更高的 IOPS,本文將深入探討如何在 Linux 環(huán)境下對 SSD 進行全面優(yōu)化,需要的朋友可以參考下
    2026-04-04
  • Linux恢復刪除文件的lsof命令詳解

    Linux恢復刪除文件的lsof命令詳解

    Linux系統(tǒng)是服務器最常見的操作系統(tǒng),當然也面臨著非常多的安全事件,當發(fā)生刪除文件錯誤的時候,恢復文件就尤為重要了,下面這篇文章主要介紹了Linux恢復刪除文件的lsof命令,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-01-01
  • Ubuntu14.04安裝、配置與卸載QT5的步驟詳解

    Ubuntu14.04安裝、配置與卸載QT5的步驟詳解

    這篇文章主要介紹了Ubuntu14.04安裝、配置與卸載QT5詳細步驟,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05
  • Linux查看程序被Killed的原因及分析

    Linux查看程序被Killed的原因及分析

    文章總結(jié):本文介紹了如何查看系統(tǒng)中被Killed的進程信息,并提供了設定kill優(yōu)先度的方法,優(yōu)先度通過oom_adj值來調(diào)整,范圍為-16到+15,值越高優(yōu)先級越高,文章還提到如何處理被拒絕訪問的命令,并鼓勵大家提供支持
    2024-11-11
  • Apache 的 order deny allow 設置說明

    Apache 的 order deny allow 設置說明

    Allow和Deny可以用于apache的conf文件或者.htaccess文件中(配合Directory, Location, Files等),用來控制目錄和文件的訪問授權。
    2010-12-12

最新評論

长乐市| 山东省| 宣恩县| 临漳县| 于田县| 忻州市| 兴仁县| 尼木县| 印江| 砚山县| 昆山市| 舞钢市| 巴塘县| 新乐市| 化德县| 宾阳县| 衡阳县| 军事| 田林县| 故城县| 保山市| 阿勒泰市| 红安县| 简阳市| 衡南县| 深州市| 浦县| 达日县| 长岭县| 恩施市| 保德县| 随州市| 射洪县| 康定县| 松溪县| 出国| 库车县| 逊克县| 深泽县| 门源| 万山特区|