欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Linux手把手教你實現(xiàn)udp服務(wù)器的詳細(xì)過程

 更新時間:2024年04月19日 15:49:07   作者:一朵貓貓菇  
本文給大家分享Linux實現(xiàn)udp服務(wù)器的詳細(xì)過程,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

前言

上一篇文章中我們講到了很多的網(wǎng)絡(luò)名詞以及相關(guān)知識,下面我們就直接進(jìn)入udp服務(wù)器的實現(xiàn)。

一、udp服務(wù)器的實現(xiàn)

首先我們需要創(chuàng)建五個文件(文件名可以自己命名也可以和我一樣),分別是makefile,udpclient.cc,udpclient.hpp,udpserver.cc,udpserver.hpp,下面我們先進(jìn)行makefile的編寫,在makefile中我們要一次創(chuàng)建兩個可執(zhí)行程序:

cc=g++
.PHONY:all
all:udpClient udpServer
udpClient:udpClient.cc
	$(cc) -o $@ $^ -std=c++11
udpServer:udpServer.cc
	$(cc) -o $@ $^ -std=c++11
.PHONY:clean
clean:
	rm -f udpClient udpServer

我們通過all就可以創(chuàng)建多個可執(zhí)行程序了,對于cc這個變量我們設(shè)置為g++,以后如果想換其他的編譯器就可以直接替換了。

在udpserver.hpp這個文件中我們先寫出整體框架:

namespace Server
{
    class udpServer
    {
    public:
        udpServer() 
        {
        }
        void InitServer()
        {
        }
        void start()
        {
        }
        ~udpServer()
        {
        }
    private:
        //服務(wù)器一定要有自己的服務(wù)端口號(注意端口號是16位的)
        uint16_t _port;     //端口號
        //實際上一款服務(wù)器不建議指明一個IP
        string _ip;    //ip
    };
}

那么我們現(xiàn)在服務(wù)器的ip填多少呢?實際上我們只是完成測試,所以ip就填0.0.0.0就好了,這樣的話任意的ip都能訪問我們的服務(wù)器,所以我們定義一個static變量來保存ip:

 static const string defaultIp = "0.0.0.0";

有了ip和端口號后,我們就可以用構(gòu)造函數(shù)初始化了:

 udpServer(const uint16_t& port,const string ip = defaultIp)
            :_port(port)
            ,_ip(ip) 
        {
        }

 我們的服務(wù)器未來要啟動的話就必須先初始化然后再啟動,所以我們寫了init和start接口,那么該如何初始化呢?實際上不管是udp還是tcp,我們初始化都是需要套接字的,下面我們看看套接字的接口:

 如何理解套接字呢,我們都知道linux一切皆文件,所以未來的網(wǎng)絡(luò)通信一定是在同一個文件中只要和網(wǎng)卡設(shè)備關(guān)聯(lián)起來就實現(xiàn)了網(wǎng)絡(luò)通信,所以套接字的目的實際上是創(chuàng)建一個文件,可以看到我們的套接字有三個參數(shù),第一個參數(shù)的解釋是域,實際上就是讓我們選擇是進(jìn)行網(wǎng)絡(luò)通信還是本地通信,這里我們一般選擇AF_INET選項,代表使用IPV4協(xié)議的網(wǎng)絡(luò)通信。第二個參數(shù)是type,表面套接字要向我們提供服務(wù)的類型,怎么理解呢,如下圖:

我們現(xiàn)在所寫的UDP服務(wù)器的特點是不可靠傳輸無連接,而這正是與SOCK_DGRAM這個選項所匹配的,我們查看這個選項的解釋可以看到:DGRAM適用于不可靠傳輸,連接少

我們下一篇要實現(xiàn)的TCP服務(wù)器,就會用到SOCK_STREAM這個選項,因為這個選項的解釋是面向流式服務(wù),而我們TCP的特點就是面向字節(jié)流。

第三個參數(shù)我們一般缺省為0,因為這個參數(shù)代表我們未來要采用什么協(xié)議,如果我們寫為0,那么這個接口會根據(jù)我們填的前兩個參數(shù)來幫我們確定第三個參數(shù)是選擇TCP協(xié)議還是UDP協(xié)議。

這個接口的返回值相信大家也看到了,沒錯!一旦創(chuàng)建套接字成功,那么就會給我們返回一個文件描述符,如果失敗則會給我們返回-1并且提供錯誤碼。

了解了socket這個接口,那么我們下一步就是增加一個私有變量來接收socket返回的文件描述符(注意:這個文件描述符會被后面的接口多次用到):

 然后我們在構(gòu)造函數(shù)中將這個文件描述符初始化為-1:

udpServer(const uint16_t& port,const string ip = defaultIp)
            :_port(port)
            ,_ip(ip)
            ,_sockfd(-1)
        {
        }

然后我們初始化第一步:使用套接字

 void InitServer()
        {
            //UDP第一步:創(chuàng)建了一個套接字
            _sockfd = socket(AF_INET,SOCK_DGRAM,0);
            if (_sockfd==-1)
            {
                cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
                exit(SOCKET_ERROR);
            }
            cout<<"server socket success: "<<" : "<<_sockfd<<endl;
        }

如果套接字創(chuàng)建失敗,就算沒有給我們的文件描述符返回-1,由于我們初始化的時候就初始化為-1,所以還是會報錯,注意:一旦連套接字都沒創(chuàng)建成功,那么就沒有繼續(xù)的必要了直接退出即可,這里我們直接用枚舉列出所有的退出碼然后在退出的時候使用:

    enum 
    {
       SOCKET_ERROR = 2
    };

創(chuàng)建成功我們就直接打印一下文件描述符即可。

下面進(jìn)入初始化第二步:綁定端口和ip

 首先第一個參數(shù)就是我們使用socket接口給我們返回的文件描述符,第二個參數(shù)是什么呢?大家看到這個參數(shù)名struct sockaddr*是否感到熟悉呢?沒錯就是我們上一篇講到的sockaddr結(jié)構(gòu):

 注意我們用的IPV4協(xié)議要用sockaddr_in這個結(jié)構(gòu),但是接口參數(shù)是sockaddr*這個結(jié)構(gòu),所以我們用的時候要做一下強(qiáng)制類型轉(zhuǎn)換??梢钥吹轿覀兊倪@個結(jié)構(gòu)有4個位置需要我們填充,第一個AF_INET代表協(xié)議家族,第二個是端口號,第三個是IP地址,第四個是這個結(jié)構(gòu)體的大小。

第三個參數(shù)是這個結(jié)構(gòu)體的長度。

對于bind這個接口,如果成功則返回0,如果失敗則返回-1.

由于bind的第二個參數(shù)是結(jié)構(gòu)體指針,所以我們需要先創(chuàng)建一個新的結(jié)構(gòu)體,然后對這個結(jié)構(gòu)體進(jìn)行填充,填充后傳入?yún)?shù):

            struct sockaddr_in local;  //在棧(用戶)上定義了一個結(jié)構(gòu)體變量
            bzero(&local,sizeof(local));
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);  //給別人發(fā)消息要將port和ip發(fā)送給對方 htons主機(jī)轉(zhuǎn)網(wǎng)絡(luò)序列(port是short類型)
            local.sin_addr.s_addr = inet_addr(_ip.c_str());     //1.string->uint32_t 2.主機(jī)轉(zhuǎn)網(wǎng)絡(luò),ip是四字節(jié)htonl

bzero這個接口可以將我們的結(jié)構(gòu)體里面的內(nèi)容初始化為0,然后我們進(jìn)行填充首先協(xié)議家族填寫AF_INET這里是固定寫法,然后就是填寫端口號和ip地址,對于端口號,在結(jié)構(gòu)體中的類型是16字節(jié)的short短整型,而htons這個接口可以將主機(jī)字節(jié)序轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序(還記得我們上一篇講的內(nèi)容嗎?網(wǎng)絡(luò)中所有字節(jié)序必須是大端存儲,而主機(jī)中有可能大端有可能小端,所以hton這個接口就是將任意的主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序的接口),htons后面的s代表要轉(zhuǎn)化為16字節(jié)的,如果你的port是32字節(jié)的,那么你就需要用htonl轉(zhuǎn)換為long類型。

對于ip的填充,首先結(jié)構(gòu)體中的ip的類型是32位的,而我們剛剛在類內(nèi)定義的是一個字符串,所以我們需要先將字符串轉(zhuǎn)換為32位整形,然后再將這個32位整形由主機(jī)字節(jié)序轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序,所以正常的步驟是:1.string->uint32_t  2.htonl(uint32_t)          但是現(xiàn)在我們有一個很好用的接口,這個接口是inet_addr,下面我們看看這個接口:

 我們可以看到inet_addr的參數(shù)是一個const char*類型,這是什么呢?實際上這個類型就是我們ip常用的點分十進(jìn)制類型,這個函數(shù)的返回值是in_addr_t,也就是說這個函數(shù)可以直接將點分十進(jìn)制類型轉(zhuǎn)化為我們結(jié)構(gòu)體中所需要的ip類型。

我們將這個結(jié)構(gòu)體填充完畢后,下面就直接綁定端口號和ip:

            int n = bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if (n==-1)
            {
                cerr<<"bind error:  "<<errno<<" : "<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }

前面我們說過,bind的參數(shù)與我們ipv4協(xié)議使用的結(jié)構(gòu)體類型不一樣需要強(qiáng)制轉(zhuǎn)化。當(dāng)我們綁定失敗,我們就打印錯誤信息,然后加一個bind接口的錯誤碼用于返回:

    enum 
    {
       SOCKET_ERROR = 2
       ,BIND_ERR
    };

綁定結(jié)束后我們的服務(wù)器初始化接口就結(jié)束了,下面我們進(jìn)入服務(wù)器啟動的接口,在這里我們要注意,服務(wù)器啟動的本質(zhì)就是一個死循環(huán),就比如我們的手機(jī)系統(tǒng),如果不是主動的退出,我們的手機(jī)是不會關(guān)機(jī)的。

對于udp服務(wù)器的啟動,我們先大概的思考一下:./udpserver ip port也就是說需要三個參數(shù),所以我們可以先設(shè)計一下udpserver.cc:

首先對于不懂如何啟動服務(wù)器的用戶我們需要加一個使用手冊,保證用戶可以正常啟動服務(wù)器:

static void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<" local_ip local_port\n\n";
}
int main(int argc,char* argv[])
{
    if (argc!=3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[2]);
    string ip = argv[1];
    unique_ptr<udpServer> usvr(new udpServer(port,ip));
    usvr->InitServer();
    usvr->start();
    return 0;
}

對于main函數(shù)的參數(shù)我們之前已經(jīng)講過,argc代表你傳了幾個參數(shù),argv這個數(shù)組對應(yīng)的下標(biāo)就是我們的參數(shù)。我們的目的是:./udpserver ip port這樣使用,所以一共有三個參數(shù),如果用戶沒有傳3個參數(shù),那么我們就直接提示如何使用并且退出程序,這里我們也可以弄一個錯誤碼寫到枚舉中:

    enum 
    {
       USAGE_ERR = 1
       ,SOCKET_ERROR
       ,BIND_ERR
    };

如果用戶輸入成功,那么我們先獲取用戶輸入的端口號,因為用戶輸入的是字符串,所以需要將字符串轉(zhuǎn)化為整形,我們用uint16_t的類型來接收端口號,因為我們的server類中的ip是string的,所以可以直接用string變量獲取ip地址。然后我們用一個智能指針來管理服務(wù)器,在服務(wù)器中使用端口號和ip構(gòu)造服務(wù)器,然后對服務(wù)器進(jìn)行初始化和啟動即可。

下面我們講解一個在綁定前填充結(jié)構(gòu)體中ip地址的問題:實際上我們在正在做項目的時候,是不會直接像下面這樣指明一個IP的:

真實的寫法應(yīng)該是下面這樣:

local.sin_addr.s_addr = INADDR_ANY; //任意地址綁定才是服務(wù)器的真實寫法

 什么意思呢?實際上就是當(dāng)我們將服務(wù)器的IP設(shè)為ANY(本質(zhì)其實是0),就代表未來發(fā)給我的數(shù)據(jù)只要是綁定了我的端口那么就能與我通信,這樣就不會漏掉沒有我IP地址的服務(wù)器給我發(fā)的消息了。還記得我們剛開始寫的IP是什么嗎?沒錯就是全0,也就是說我們現(xiàn)在寫的這個服務(wù)器是不需要我們具體的IP只需要通過端口號就可以啟動臺服務(wù)器,并且未來客戶端訪問我們的服務(wù)器的時候是不需要指明IP的,任意一個IP+特定的端口號都能訪問我們這臺服務(wù)器。既然不需要IP,下面我們就修改一下代碼:

static void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<" local_port\n\n";
}
int main(int argc,char* argv[])
{
    if (argc!=2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    } 
    uint16_t port = atoi(argv[1]); 
    unique_ptr<udpServer> usvr(new udpServer(handerMessage,port));
    usvr->InitServer();
    usvr->start();
    return 0;
}

所以實際上一個服務(wù)器的IP不重要,只要我們有端口號就能啟動這臺服務(wù)器,并且客戶端用任意的IP和我們服務(wù)器特定的端口號就可以和我們的服務(wù)器通信。

下面我們編寫start接口的代碼,一旦啟動我們就要接受數(shù)據(jù),所以我們先認(rèn)識一個接口:

 這個接口的第一個參數(shù)是我們創(chuàng)建套接字返回的文件描述符,意思就是我們從哪個套接字里讀數(shù)據(jù)。第二個參數(shù)是一個緩沖區(qū),第三個參數(shù)是這個緩沖區(qū)的長度,2和3這兩個參數(shù)代表的是你讀到的數(shù)據(jù)要放在哪個緩沖區(qū)里,第四個參數(shù)是讀取方式,這里我們默認(rèn)填0代表阻塞式讀取,也就是說客戶端不給我們服務(wù)端發(fā)消息時,我們就一直等待客戶端發(fā)消息,這就叫阻塞式讀取。第五個參數(shù)和第六個參數(shù)非常重要,這兩個參數(shù)是輸出型參數(shù),也就是說未來客戶端給我們發(fā)消息時,會將數(shù)據(jù)放到緩沖區(qū)中,然后會將客戶端的端口號和IP放到struct sockaddr*這個結(jié)構(gòu)體當(dāng)中,第六個參數(shù)就是這個結(jié)構(gòu)體的長度,我們可以理解為:我們只需要創(chuàng)建一個空的結(jié)構(gòu)體,然后客戶端發(fā)消息后這個接口就會將客戶端的端口號和IP放到我們自己創(chuàng)建的結(jié)構(gòu)體中。

 對于這個接口的返回值,如果成功則會給我們返回讀到數(shù)據(jù)的字節(jié)數(shù),如果失敗返回-1.

static const int gnum = 1024;
void start()
        {
            //服務(wù)器的本質(zhì)實際上就是一個死循環(huán)
            char buffer[gnum];
            for (;;)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);   //必填
                ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(structsockaddr*)&peer,&len); //成功返回字節(jié)數(shù)
            }
        }

我們在使用recvfrom接口的時候,對于緩沖區(qū)是不用考慮\0的存在的,所以長度是1024-1.然后我們的結(jié)構(gòu)體類型在參數(shù)中需要做強(qiáng)制類型轉(zhuǎn)換,理由與上面同理。下面我們思考讀到數(shù)據(jù)該干什么?我們的目的是實現(xiàn)一個udp服務(wù)器用來進(jìn)行簡單的聊天,聊天的時候要顯示出客戶端的ip和端口號,所以我們這樣設(shè)計:

void start()
        {
            //服務(wù)器的本質(zhì)實際上就是一個死循環(huán)
            char buffer[gnum];
            for (;;)
            {
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);   //必填
                ssize_t s = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len); //成功返回字節(jié)數(shù)
                //1.數(shù)據(jù)是什么? 2.誰發(fā)的
                if (s>0)
                {
                    buffer[s] = 0;
                    string clientip = inet_ntoa(peer.sin_addr);   //1.網(wǎng)絡(luò)序列 2.int->點分十進(jìn)制IP
                    uint16_t clientport = ntohs(peer.sin_port);
                    string message = buffer;
                    cout<<clientip<<"["<<clientport<<"]#"<<message<<endl;
                }
            }
        }

如果讀取數(shù)據(jù)成功,我們先將緩沖區(qū)中最后一個位置填上\0,這樣我們就可以用string來接收這個緩沖區(qū)中的字符了,然后我們獲取用戶的IP,由于結(jié)構(gòu)體中的類型是網(wǎng)絡(luò)的,所以我們需要將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)回主機(jī)字節(jié)序,而這里有一個接口與我們那會用的inet_addr正好相反,那就是inet_ntoa接口:

 這個接口可以為完成兩步:1.ntol(struct in_addr) 2.ntol(struct in_addr)->char*

ntol就是hton相反的轉(zhuǎn)換接口。

獲取到string類型的ip后,我們再接收端口號,同樣需要轉(zhuǎn)換,然后我們就打印用戶端ip[端口號]+用戶端發(fā)的消息即可。這樣服務(wù)端的代碼就實現(xiàn)完成了。

下面我們開始完成客戶端代碼:

首先客戶端必須要有的是服務(wù)端的IP和服務(wù)端的port,所以我們先寫一個框架:

namespace Client
{
    class udpClient
    {
    public:
       udpClient(const string& serverip,const uint16_t &serverport)
          :_serverip(serverip)
          ,_serverport(serverport)
       {
       }
       void InitClient()
       {
       }
       void run()
       {
       }
       ~udpClient()
       {
       }
    private:
       string _serverip;
       uint16_t _serverport;
    };
}

前面我們說過,對于服務(wù)器而言,ip地址是不重要的,只需要端口號就可以啟動服務(wù)器,因為一般服務(wù)器的IP都是全0,代表任意IP都可以訪問,所以我們的客戶端只需要隨便填一個IP加上特殊的端口號就可以通信了,那么客戶端內(nèi)部ip和port肯定是必須要有的,明白了這個知識我們就先實現(xiàn)一下client.cc的框架:

#include "udpClient.hpp"
#include <memory>
using namespace Client;
static void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<" server_ip server_port\n\n";
}
//./udpClient server_ip server_port
int main(int argc, char* argv[])
{
    if (argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    string serverip = argv[1];
    uint16_t serverport = atoi(argv[2]);
    unique_ptr<udpClient> ucli(new udpClient(serverip,serverport));
    ucli->InitClient();
    ucli->run();
    return 0;
}

這里的原理和我們服務(wù)器寫的一模一樣,我們就直接編寫客戶端代碼:

首先我們客戶端的初始化一定也是需要創(chuàng)建套接字的,既然要創(chuàng)建套接字就必須要有一個變量接收套接字返回的文件描述符:

udpClient(const string& serverip,const uint16_t &serverport)
          :_sockfd(-1)
          ,_serverip(serverip)
          ,_serverport(serverport) 
       {
       }

然后我們編寫初始化函數(shù):

void InitClient()
       {
           // 1.創(chuàng)建socket
           _sockfd = socket(AF_INET,SOCK_DGRAM,0);
           if (_sockfd==-1)
           {
               cerr<<"socket error: "<<errno<<" : "<<strerror(errno)<<endl;
               exit(2);
           }
           cout<<"client socket success: "<<" : "<<_sockfd<<endl;
           //2.  client要不要bind(必須要),client要不要明確的bind(不需要,不需要程序員自己bind(由OS自動形成端口綁定))
       }

我們客戶端的代碼很簡單,相比服務(wù)端客戶端是不需要明確的去bind的,這是因為服務(wù)端必須要有指定的不能隨意改變的端口,這樣我們的客戶端才能找到服務(wù)端,就像110一樣,110這個電話是不能隨意更改的,但是對于用戶端自己來講,我自己是什么樣的端口不重要,我只需要通過服務(wù)端的端口訪問服務(wù)端。所以我們一定要注意:客戶端需要bind,但是不需要程序員明確的bind,這里我們自己不bind,操作系統(tǒng)察覺到我們沒有綁定后會自動幫我們綁定,并且每次綁定的端口號都是隨機(jī)的。

下面我們編寫客戶端運行的函數(shù),客戶端運行很簡單,我們只需要讓客戶端輸入數(shù)據(jù),這樣的話我們服務(wù)端就可以接受到數(shù)據(jù),因為我們的目的就是簡單的網(wǎng)絡(luò)通信。

對于客戶端發(fā)消息,我們需要認(rèn)識一個接口:

 第一個參數(shù)是我們創(chuàng)建套接字返回的文件描述符,第二個參數(shù)和第三個參數(shù)是一起的,buf是我們發(fā)送的數(shù)據(jù)所在的緩沖區(qū),第三個參數(shù)是緩沖區(qū)的長度,第四個參數(shù)是發(fā)送方式,我們還是默認(rèn)填0表示阻塞發(fā)送,有數(shù)據(jù)就發(fā),沒數(shù)據(jù)就等。第五個參數(shù)和第六個參數(shù)同樣是輸入型參數(shù),我們客戶端需要提前創(chuàng)建一個結(jié)構(gòu)體,向里面填充我們客戶端的ip和端口號,然后通過sendto接口發(fā)送到服務(wù)端,然后服務(wù)端就會接收到我們的數(shù)據(jù)和ip和端口號。

void run()
       {
           struct sockaddr_in server;
           memset(&server,0,sizeof(server));
           server.sin_family = AF_INET;
           server.sin_addr.s_addr = inet_addr(_serverip.c_str());
           server.sin_port = htons(_serverport);
           string message;
           while (!_quit)
           {
              cout<<"Please Enter# ";
              cin>>message;
              sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
           }
       }

這里我們的客戶端要持續(xù)的輸入所以設(shè)為死循環(huán),quit是我們新增的一個成員變量:

 以上就是我們客戶端的代碼了,實際上客戶端的代碼非常簡單,下面我們運行起來:

 運行起來后我們可以看到是沒問題的,這里也解釋了為什么說客戶端端口不需要程序員綁定,我們可以看到每次客戶端重新登錄在服務(wù)端顯示的端口號都是不一樣的,因為這是操作系統(tǒng)自動指定的端口號,而我們的服務(wù)端的端口號是唯一的,我們客戶端必須輸入服務(wù)端正確的端口號才能訪問服務(wù)端,當(dāng)然小伙伴們也一樣將服務(wù)端的可執(zhí)行程序直接發(fā)給你們的小伙伴,然后讓他們直接通過任意ip+ 你的服務(wù)器端口號來和你進(jìn)行聊天,下面是多人通過網(wǎng)絡(luò)聊天的界面:

總結(jié)

以上就是我們udp服務(wù)器的所有內(nèi)容了,下一篇文章我們將會把這個服務(wù)器改造稱為英漢互譯,大型聊天室等好玩的工具。

到此這篇關(guān)于Linux手把手教你實現(xiàn)udp服務(wù)器的文章就介紹到這了,更多相關(guān)Linux udp服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 圖文詳解Ubuntu搭建Ftp服務(wù)器的方法(包成功)

    圖文詳解Ubuntu搭建Ftp服務(wù)器的方法(包成功)

    今天小編就為大家分享一篇關(guān)于圖文詳解Ubuntu搭建Ftp服務(wù)器的方法(包成功),小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-03-03
  • Ubuntu下安裝nvidia顯卡驅(qū)動(安裝方式簡單)

    Ubuntu下安裝nvidia顯卡驅(qū)動(安裝方式簡單)

    這篇文章主要介紹了Ubuntu下安裝nvidia顯卡驅(qū)動,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Linux的netstat命令詳解

    Linux的netstat命令詳解

    這篇文章主要介紹了Linux的netstat命令,netstat命令用于顯示與IP、TCP、UDP和ICMP協(xié)議相關(guān)的統(tǒng)計數(shù)據(jù),它能提供TCP連接,TCP和UDP監(jiān)聽,進(jìn)程內(nèi)存管理的相關(guān)報告。需要的朋友可以參考下面文章內(nèi)容
    2021-09-09
  • Linux之進(jìn)程狀態(tài)&&進(jìn)程優(yōu)先級詳解

    Linux之進(jìn)程狀態(tài)&&進(jìn)程優(yōu)先級詳解

    文章介紹了操作系統(tǒng)中進(jìn)程的狀態(tài),包括運行狀態(tài)、阻塞狀態(tài)和掛起狀態(tài),并詳細(xì)解釋了Linux下進(jìn)程的具體狀態(tài)及其管理,此外,文章還討論了進(jìn)程的優(yōu)先級、查看和修改進(jìn)程優(yōu)先級的方法,以及并發(fā)相關(guān)的概念和函數(shù)的返回值
    2025-02-02
  • Linux下實現(xiàn)UTF-8和GB2312互相轉(zhuǎn)換的方法

    Linux下實現(xiàn)UTF-8和GB2312互相轉(zhuǎn)換的方法

    下面小編就為大家?guī)硪黄狶inux下實現(xiàn)UTF-8和GB2312互相轉(zhuǎn)換的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧,祝大家游戲愉快哦
    2016-12-12
  • 如何在Linux服務(wù)上管理Redis的啟動、重啟和關(guān)閉

    如何在Linux服務(wù)上管理Redis的啟動、重啟和關(guān)閉

    Redis是一個高性能的開源鍵值對存儲數(shù)據(jù)庫,廣泛用于緩存、會話管理和實時數(shù)據(jù)處理等場景,本文將詳細(xì)介紹如何在Linux系統(tǒng)上啟動、重啟和關(guān)閉Redis服務(wù),并提供相關(guān)的配置和故障排除技巧,需要的朋友可以參考下
    2024-05-05
  • 關(guān)于Linux賬號管理詳解

    關(guān)于Linux賬號管理詳解

    本文主要針對Linux系統(tǒng)的賬戶管理方便的內(nèi)容做了詳細(xì)介紹,以及操作賬戶時的具體做法。
    2017-11-11
  • Linux中大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化的方法

    Linux中大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化的方法

    這篇文章主要給大家介紹了關(guān)于Linux中大內(nèi)存頁Oracle數(shù)據(jù)庫優(yōu)化的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-11-11
  • ssh自動備份主機(jī)文件的腳本

    ssh自動備份主機(jī)文件的腳本

    ssh自動備份主機(jī)文件的腳本,需要的朋友可以參考下。
    2011-08-08
  • Apache 開通子站點配置方法

    Apache 開通子站點配置方法

    前一段時間突發(fā)奇想,想自己給自己做個記錄系統(tǒng),暫且就叫他記錄系統(tǒng)吧。其實木的就是記錄一些亂七八糟的事情,譬如,賬簿,記事本之類的
    2012-06-06

最新評論