国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手

這篇具有很好參考價(jià)值的文章主要介紹了linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

一、TCP通信簡(jiǎn)單模擬實(shí)現(xiàn)

Tcp通信模擬實(shí)現(xiàn)與Udp通信模擬實(shí)現(xiàn)的區(qū)別不大,一個(gè)是面向字節(jié)流,一個(gè)是面向數(shù)據(jù)報(bào);udp協(xié)議下拿到的數(shù)據(jù)可以直接發(fā)送,tcp協(xié)議下需要?jiǎng)?chuàng)建鏈接,用文件描述符完成數(shù)據(jù)的讀寫

1.1 服務(wù)端實(shí)現(xiàn)

1.1.1 接口認(rèn)識(shí)

1.1.1.1 listen:監(jiān)聽socket
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);
sockfd:創(chuàng)建的套接字
backlog:新連接隊(duì)列的長(zhǎng)度限制
1.1.1.2 accept:獲取連接
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
sockfd:創(chuàng)健的套接字,僅用于監(jiān)聽新鏈接
addr:結(jié)構(gòu)體,這里說(shuō)網(wǎng)絡(luò)通信,用sockaddr_in
addrlen:結(jié)構(gòu)體大小
返回值:一個(gè)新的文件描述符(套接字),這個(gè)才是和客戶端通信的文件描述符

通信就用accept返回的文件描述符,面向字節(jié)流,后續(xù)都是文件操作

1.1.2 tcpServer.hpp

#pragma once
#include "logMessage.hpp"
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <unistd.h>
namespace Server
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };

    using namespace std;

    static const uint16_t gport = 8080;
    static const uint16_t gbacklog = 5;
    class tcpServer
    {
    public:
        tcpServer(const uint16_t &port = gport)
            : listen_sockfd_(-1), port_(port)
        {
        }

        void InitServer()
        {
            // 1.創(chuàng)建socket
            listen_sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
            if (listen_sockfd_ < 0)
            {
                logMessage(FATAL, "create socket error");
                exit(SOCKET_ERR);
            }
            logMessage(NORMAL, "create socket success");

            // 2.bind網(wǎng)絡(luò)信息
            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;
            if(bind(listen_sockfd_,(struct sockaddr*)&local,sizeof(local))<0)
            {
                logMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }

            logMessage(NORMAL,"bind socket success");
            
            //3.設(shè)置socket為監(jiān)聽狀態(tài)
            if(listen(listen_sockfd_,gbacklog)<0)
            {
                logMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            logMessage(NORMAL,"listen socket success");

        }
        void start()
        {
            for(; ;)
            {
                //4.server獲取新鏈接
                struct sockaddr_in peer;
                socklen_t len=sizeof(peer);
                //sock:和客戶端通信的文件描述符
                int sock=accept(listen_sockfd_,(struct sockaddr*)&peer,&len);
                if(sock<0)//沒有獲取新鏈接成功就執(zhí)行下一次循環(huán)
                {
                    logMessage(FATAL,"accpect sock error");
                    continue;
                }
                logMessage(NORMAL,"accept sock success");
                std::cout<<"sock"<<sock<<endl;

                //5.通信就用sock文件描述符,面向字節(jié)流,后續(xù)都是文件操作
                /*version1*/
                serverIO(sock);
                close(sock);
            }
        }
        void serverIO(int sock)
        {
            char buffer[1024];
            while (true)
            {
                ssize_t n=read(sock,buffer,sizeof(buffer)-1);
                if(n>0)
                {
                    buffer[n]=0;
                    std::cout<<"recv message "<<buffer<<endl;
                    string outbuffer=buffer;
                    outbuffer+="server[echo]";
                    write(sock,outbuffer.c_str(),outbuffer.size());
                }
                else if(n==0)
                {
                    //客戶端退出
                    logMessage(NORMAL,"client quit ,me too!!");
                    break;
                }
            }
            
        }
        ~tcpServer()
        {
        }

    private:
        int listen_sockfd_;//不負(fù)責(zé)通信,只負(fù)責(zé)監(jiān)聽鏈接,獲取新鏈接
        uint16_t port_;
    };
}

1.1.3 tcpServer.cc

#include "tcpServer.hpp"
#include <memory>

using namespace std;
using namespace Server;
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}


int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t serverport=atoi(argv[1]);
    unique_ptr<tcpServer> tsvr(new tcpServer(serverport));
    tsvr->InitServer();
    tsvr->start();
    return 0;

}

1.2 客戶端實(shí)現(xiàn)

1.2.1 接口認(rèn)識(shí)

1.2.1.1 connect:發(fā)起連接
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
參數(shù)與accept一樣,代表的含義也一樣
返回值:成功0,失敗-1

1.2.2 tcpClient.hpp

#pragma once
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>
#include <string>
#include <unistd.h>

namespace Client
{
    enum
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR
    };
    using namespace std;
    class tcpClient
    {
    public:
        tcpClient(const string &clientip, const uint16_t &clientport)
            : clientip_(clientip), clientport_(clientport), sockfd_(-1)
        {
        }
        void InitCient()
        {
            // 1.創(chuàng)建socket
            sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
            if (sockfd_ < 0)
            {
                std::cerr << "socket create error" << endl;
                exit(2);
            }
        }
        void run()
        {
            struct sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(clientport_);
            server.sin_addr.s_addr = inet_addr(clientip_.c_str());

            // 發(fā)起鏈接
            if (connect(sockfd_, (struct sockaddr *)&server, sizeof(server)) != 0)
            {
                std::cerr << "connect create error" << endl;
            }
            else
            {
                string msg;
                while (true)
                {
                    cout << "Enter# ";
                    getline(cin, msg);
                    write(sockfd_, msg.c_str(), msg.size());

                    char buffer [1024];
                    ssize_t n=read(sockfd_,buffer,sizeof(buffer)-1);
                    if (n>0)
                    {
                        buffer[n]=0;
                        cout<<"Server處理后為# "<<buffer<<endl;

                    }
                    else
                    {
                        break;
                    }
                    

                }
            }
        }
        ~tcpClient() {
            if(sockfd_>=0) close(sockfd_);
        }

    private:
        int sockfd_;
        uint16_t clientport_;
        string clientip_;
    };
}

1.2.3 tcpClient.cc

#include "tcpClient.hpp"
#include <memory>
using namespace std;
using namespace Client;
static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " server_ip server_port\n\n";
}


int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t clientport=atoi(argv[2]);
    string clientip=argv[1];

    unique_ptr<tcpClient> ucli(new tcpClient(clientip,clientport));
    ucli->InitCient();
    ucli->run();
    return 0;
}

上述代碼是一個(gè)單進(jìn)程的版本,一個(gè)鏈接過(guò)來(lái)會(huì)去死循環(huán)執(zhí)行serverIO,也就是說(shuō)同一時(shí)間只能有一個(gè)鏈接過(guò)來(lái)通信,其他的鏈接必須阻塞等待上一個(gè)鏈接退出

1.3 優(yōu)化方案

1.3.1 TCP網(wǎng)絡(luò)通信----多進(jìn)程版

更該tcpServer.hpp中的start函數(shù)即可,其他文件和單進(jìn)程版一致

void start()
{
    logMessage(NORMAL, "Thread init success");
    for (;;)
    {
        // 4.server獲取新鏈接
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        // sock:和客戶端通信的文件描述符
        int sock = accept(listen_sockfd_, (struct sockaddr *)&peer, &len);
        if (sock < 0) // 沒有獲取新鏈接成功就執(zhí)行下一次循環(huán)
        {
            logMessage(FATAL, "accpect sock error");
            continue;
        }
        logMessage(NORMAL, "accept sock success,get new sock:%d", sock);

        /*******************************************version2多進(jìn)程版*/

        pid_t id = fork();
        if (id == 0) // 子進(jìn)程
        {
            // 關(guān)閉子進(jìn)程不需要的文件描述符
            close(listen_sockfd_);

            // 子進(jìn)程退出,父進(jìn)程回收資源,孫子進(jìn)程去執(zhí)行任務(wù)
            // 孫子進(jìn)程成為孤兒進(jìn)程,1號(hào)進(jìn)程托管并回收其退出資源
            if (fork() > 0)
                exit(0); 

            // 孫子進(jìn)程
            serverIO(sock);
            close(sock);//任務(wù)完成關(guān)閉文件描述符
            exit(0); 
        }
        
        // 細(xì)節(jié):父進(jìn)程必須關(guān)閉子進(jìn)程的sock,避免一直被占用
        // 這里的關(guān)閉并不是完全關(guān)閉,只是引用計(jì)數(shù)減一,并不影響孫子進(jìn)程
        close(sock); // 獲取之后立馬關(guān)閉,多次鏈接出現(xiàn)sock都一樣,也可能不一樣

        // 父進(jìn)程,阻塞等待子進(jìn)程退出
        pid_t ret = waitpid(id, nullptr, 0);
        if (ret > 0)
        {
            std::cout << "waitsuccess" << ret << endl;
        }
    }
}     
  1. 父進(jìn)程必須關(guān)閉子進(jìn)程的sock,避免一直被占用
    這里的關(guān)閉并不是完全關(guān)閉,只是引用計(jì)數(shù)減一,并不影響孫子進(jìn)程
  2. waitpid這里不能單純用非阻塞等待,當(dāng)有多個(gè)連接到來(lái)的時(shí)候,并且有一個(gè)進(jìn)程退出,父進(jìn)程非阻塞等待,去執(zhí)行accept,但是如果后續(xù)沒有連接來(lái)了,就一直阻塞在accept,剩下的子進(jìn)程就沒法回收了

前面【信號(hào)】中曾說(shuō)道子進(jìn)程退出時(shí)會(huì)發(fā)送SIGCHLD信號(hào),我們可以對(duì)其設(shè)置捕捉,忽略掉其行為,父進(jìn)程就不需要阻塞等待了

void start()
{
    logMessage(NORMAL, "Thread init success");
   	signal(SIGCHLD,SIG_IGN);//設(shè)置信號(hào)忽略行為
    for (;;)
    {
        // 4.server獲取新鏈接
        struct sockaddr_in peer;
        socklen_t len = sizeof(peer);
        // sock:和客戶端通信的文件描述符
        int sock = accept(listen_sockfd_, (struct sockaddr *)&peer, &len);
        if (sock < 0) // 沒有獲取新鏈接成功就執(zhí)行下一次循環(huán)
        {
            logMessage(FATAL, "accpect sock error");
            continue;
        }
        logMessage(NORMAL, "accept sock success,get new sock:%d", sock);

        /*******************************************version2多進(jìn)程版*/

        pid_t id = fork();
        if (id == 0) // 子進(jìn)程
        {
            // 關(guān)閉子進(jìn)程不需要的文件描述符
            close(listen_sockfd_);
            // 子進(jìn)程
            serverIO(sock);
            close(sock);//任務(wù)完成關(guān)閉文件描述符
            exit(0); 
        }
        
        // 細(xì)節(jié):父進(jìn)程必須關(guān)閉子進(jìn)程的sock,避免一直被占用
        // 這里的關(guān)閉并不是完全關(guān)閉,只是引用計(jì)數(shù)減一,并不影響孫子進(jìn)程
        close(sock); // 獲取之后立馬關(guān)閉,多次鏈接出現(xiàn)sock都一樣,也可能不一樣

       
    }
}     

1.3.2 TCP網(wǎng)絡(luò)通信----多線程版

在tcpServer類外添加ThreadData類,類內(nèi)修改start函數(shù),添加threadRoutinue函數(shù)其余不變

    class tcpServer;
    class ThreadData
    {
    public:
        ThreadData(tcpServer *self, int sockfd)
            : self_(self), sockfd_(sockfd)
        {
        }

    public:
        tcpServer *self_;
        int sockfd_;
    };
    
void start()
        {
            logMessage(NORMAL, "Thread init success");
            // signal(SIGCHLD,SIG_IGN);
            for (;;)
            {
                // 4.server獲取新鏈接
                struct sockaddr_in peer;
                socklen_t len = sizeof(peer);
                // sock:和客戶端通信的文件描述符
                int sock = accept(listen_sockfd_, (struct sockaddr *)&peer, &len);
                if (sock < 0) // 沒有獲取新鏈接成功就執(zhí)行下一次循環(huán)
                {
                    logMessage(FATAL, "accpect sock error");
                    continue;
                }
                logMessage(NORMAL, "accept sock success,get new sock:%d", sock);

                

                /*******************************************version3:多線程版本*/
                 pthread_t tid;
                 ThreadData* td=new ThreadData(this,sock);
                 pthread_create(&tid,nullptr,threadRoutinue,td);

                
            }
        }
        //類內(nèi)調(diào)用,靜態(tài)方法
         static void* threadRoutinue(void* args)
         {
             pthread_detach(pthread_self());
             ThreadData* td= static_cast<ThreadData*>(args);
             td->self_->serverIO(td->sockfd_);
             //在一個(gè)進(jìn)程中的所有線程都可以訪問到文件描述符表,屬于共享資源,
             //一個(gè)線程所對(duì)應(yīng)的fd在使用完畢后需要進(jìn)行關(guān)閉。
             close(td->sockfd_);
             delete td;
             return nullptr;
         }

多進(jìn)程版,多線程版,線程池版,可參考我的Gitee

二、日志函數(shù)編寫

在計(jì)算機(jī)中,日志文件是記錄在操作系統(tǒng)或其他軟件運(yùn)行中發(fā)生的事件或在通信軟件的不同用戶之間的消息的文件。記錄是保持日志的行為。在最簡(jiǎn)單的情況下,消息被寫入單個(gè)日志文件。

我們借助可變參數(shù)列表來(lái)模擬實(shí)現(xiàn)日志函數(shù)
實(shí)現(xiàn)格式如:[日志等級(jí)][時(shí)間][pid][message]

#pragma once
#include <iostream>
#include <string>
#include <stdarg.h>
#include <ctime>
#include <unistd.h>

//把錯(cuò)誤信息寫到指定文件

#define LOG_NORMAL "log_nrl.txt"
#define LOG_ERR "log_err.txt"



#define DEBUG   0
#define NORMAL  1
#define WARNING 2
#define ERROR   3
#define FATAL   4

//typedef char* va_list

const char * to_levelstr(int level)
{
    switch(level)
    {
        case DEBUG : return "DEBUG";
        case NORMAL: return "NORMAL";
        case WARNING: return "WARNING";
        case ERROR: return "ERROR";
        case FATAL: return "FATAL";
        default : return nullptr;
    }
}

//void logMessage(DEBUG,"sss %f %d %c",2.1,6,'h')
void logMessage(int level,const char* format,...)
{
#define NUM 1024
    char logprefix[NUM];

    //前半部分[日志等級(jí)][時(shí)間][pid]
    snprintf(logprefix,sizeof(logprefix),"[%s][%ld][%d]",to_levelstr(level),(long int)time(nullptr),getpid());

    char logcontent[NUM];
    va_list arg;
    //初始化arg為參數(shù)列表中的第一個(gè)參數(shù)的地址
    va_start(arg,format);

    //后半部分,錯(cuò)誤信息
    //vsnprintf()函數(shù)的作用是將可變參數(shù)列表arg中的數(shù)據(jù)按照指定的格式format寫入緩沖區(qū)logcontent中
    vsnprintf(logcontent,sizeof(logcontent),format,arg);  

   

//這里做了簡(jiǎn)化,實(shí)際上是一個(gè)等級(jí)一個(gè)日志文件
    FILE* log=fopen(LOG_NORMAL,"a");
    FILE* err=fopen(LOG_ERR,"a");

    if(log !=nullptr && err!=nullptr)
    {
       
        if(level==DEBUG || level==NORMAL||level==WARNING)
        {
            fprintf(log,"%s%s\n",logprefix,logcontent);
        }

        if(level==ERROR || level==FATAL)
        {
            fprintf(err,"%s%s\n",logprefix,logcontent);
        }

        fclose(log);
        fclose(err);
    }

}

三、守護(hù)進(jìn)程

3.1 引入:為什么需要守護(hù)進(jìn)程化

守護(hù)進(jìn)程又叫精靈進(jìn)程—本質(zhì)孤兒進(jìn)程的一種有了守護(hù)進(jìn)程,上述的服務(wù)端才能變成一個(gè)真正的服務(wù)端

linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
1.當(dāng)我們使用xsell鏈接遠(yuǎn)端云服務(wù)器的時(shí)候,打開的頁(yè)面第一個(gè)出現(xiàn)的就是bash命令行,這個(gè)時(shí)候我們輸入sleep 10000 | sleep 20000 |sleep 30000 &就可以添加一個(gè)后臺(tái)任務(wù)。

linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
2.在命令行運(yùn)行sleep 40000 | sleep 50000 |sleep 60000 &后,查看進(jìn)程,發(fā)現(xiàn)新創(chuàng)建的三個(gè)進(jìn)程PGID一樣,屬于同一個(gè)組,完成一個(gè)任務(wù),與之前的任務(wù)同屬于一個(gè)會(huì)話(SID都一樣)
linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
3.通過(guò)查看SID進(jìn)程發(fā)現(xiàn),是bash:會(huì)話ID是以bash命名的
linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
4.前后臺(tái)任務(wù)切換
fg + 作業(yè)編號(hào)切換指定任務(wù)到前臺(tái)
ctrl+z暫停任務(wù):bash自動(dòng)切換到前臺(tái)
bg +作業(yè)編號(hào)指定任務(wù)stop->run
linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
當(dāng)我們進(jìn)行網(wǎng)絡(luò)通信的時(shí)候,如果服務(wù)器關(guān)機(jī)或注銷了,任務(wù)就可能會(huì)被清理,導(dǎo)致客戶端發(fā)送的消息無(wú)響應(yīng),這顯然與真正的服務(wù)器不一樣,我們需要把服務(wù)任務(wù)自成會(huì)話,自成進(jìn)程組,不受終端設(shè)備影響-----守護(hù)進(jìn)程

3.2 進(jìn)程,守護(hù)進(jìn)程化

#include <unistd.h>

pid_t setsid(void);//必須是非組長(zhǎng)調(diào)用

setsid 用于在一個(gè)新的會(huì)話中啟動(dòng)一個(gè)進(jìn)程。在運(yùn)行 setsid 命令時(shí),所啟動(dòng)的進(jìn)程將會(huì)脫離當(dāng)前的終端會(huì)話,并在一個(gè)新的會(huì)話中運(yùn)行,這樣它就不會(huì)受到終端會(huì)話關(guān)閉或掛起的影響,而可以持續(xù)運(yùn)行。

#pragma once
#include <unistd.h>
#include <signal.h>
#include <cstdlib>
#include <cassert>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define DEV "/dev/null"  //垃圾站,寫進(jìn)的內(nèi)容全丟棄

//自建一個(gè)會(huì)話,組長(zhǎng)就是自己,調(diào)用函數(shù)的不能是組長(zhǎng)
//調(diào)用完畢之后成為組長(zhǎng)
void daemonSelf(char* currPath=nullptr)
{
    //1.讓調(diào)用進(jìn)程忽略掉異常的信號(hào)
    //客戶端已經(jīng)退出,服務(wù)端再寫會(huì)崩潰
    signal(SIGPIPE,SIG_IGN);

    //2.不是組長(zhǎng),調(diào)用setsid
    if(fork()>0) exit(0);
    
    //子進(jìn)程---守護(hù)進(jìn)程又叫精靈進(jìn)程---本質(zhì)孤兒進(jìn)程
    pid_t n=setsid();
    assert(n!=-1);

    //3.守護(hù)進(jìn)程是脫離終端的,關(guān)閉或重定向以前進(jìn)程默認(rèn)打開的文件

    //      /dev/null 垃圾站,寫進(jìn)的內(nèi)容全丟棄
    int fd=open(DEV,O_RDWR);
    if(fd>=0)
    {
        dup2(fd,0);
        dup2(fd,1);
        dup2(fd,2);

        //012已經(jīng)執(zhí)行devil/null
        close(fd);
    }
    else
    {
        close(0);
        close(1);
        close(2);
    }

    //4.可選:進(jìn)程執(zhí)行路徑發(fā)生更改
    //chdir:將進(jìn)程的當(dāng)前工作目錄更改為 currpath 參數(shù)指定的目錄
    if(!currPath) chdir(currPath);


}

在服務(wù)端初始化完畢之后,啟動(dòng)之前執(zhí)行daemonSelf()函數(shù),再啟動(dòng)服務(wù)端,查看進(jìn)程就可以得到以下信息
linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
父進(jìn)程id為1證明這個(gè)進(jìn)程是一個(gè)孤兒進(jìn)程,而且可以發(fā)現(xiàn)這個(gè)進(jìn)程的PID,PGID,GID都一樣,這就是自成會(huì)話,自成進(jìn)程組的守護(hù)進(jìn)程?。?!

這個(gè)時(shí)候,即便關(guān)閉終端,只要不kill掉這個(gè)進(jìn)程,他就會(huì)在一直運(yùn)行響應(yīng)客戶端

四、TCP協(xié)議通信流程

linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手
建立連接的過(guò)程:

  • 調(diào)用socket, 創(chuàng)建文件描述符;
  • 調(diào)用connect, 向服務(wù)器發(fā)起連接請(qǐng)求;
  • connect會(huì)發(fā)出SYN段并阻塞等待服務(wù)器應(yīng)答; (第一次)
  • 服務(wù)器收到客戶端的SYN, 會(huì)應(yīng)答一個(gè)SYN-ACK段表示"同意建立連接"; (第二次)
  • 客戶端收到SYN-ACK后會(huì)從connect()返回, 同時(shí)應(yīng)答一個(gè)ACK段; (第三次)
    這個(gè)建立連接的過(guò)程, 通常稱為 三次握手

斷開連接的過(guò)程:

  • 如果客戶端沒有更多的請(qǐng)求了, 就調(diào)用close()關(guān)閉連接, 客戶端會(huì)向服務(wù)器發(fā)送FIN段(第一次);
  • 此時(shí)服務(wù)器收到FIN后, 會(huì)回應(yīng)一個(gè)ACK, 同時(shí)read會(huì)返回0 (第二次);
  • read返回之后, 服務(wù)器就知道客戶端關(guān)閉了連接, 也調(diào)用close關(guān)閉連接, 這個(gè)時(shí)候服務(wù)器會(huì)向客戶端發(fā)送一個(gè)FIN; (第三次)
  • 客戶端收到FIN, 再返回一個(gè)ACK給服務(wù)器; (第四次)

4.1 三次握手與四次揮手感性認(rèn)識(shí)

三次握手—建立連接:
女方對(duì)男方說(shuō)想談戀愛,男方答應(yīng)并問到什么時(shí)候開始,女方說(shuō)現(xiàn)在

四次揮手—斷開連接:
比如女方對(duì)男方說(shuō)離婚,男方回復(fù)離婚
同時(shí)男方反應(yīng)一會(huì)覺得不行,憑什么你先對(duì)我說(shuō),我也得休了你,然后對(duì)女方說(shuō)離婚,女方回復(fù)離婚

TCP三握四揮傳送門>>>文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-458086.html

到了這里,關(guān)于linux【網(wǎng)絡(luò)編程】TCP協(xié)議通信模擬實(shí)現(xiàn)、日志函數(shù)模擬、守護(hù)進(jìn)程化、TCP協(xié)議通信流程、三次握手與四次揮手的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 【Java】--網(wǎng)絡(luò)編程:基于TCP協(xié)議的網(wǎng)絡(luò)通信

    【Java】--網(wǎng)絡(luò)編程:基于TCP協(xié)議的網(wǎng)絡(luò)通信

    TCP協(xié)議(Transmission Control Protocol),即傳輸控制協(xié)議,是一種 面向連接 的, 可靠 的,基于 字節(jié)流 的傳輸層通信協(xié)議。數(shù)據(jù)大小無(wú)限制。 建立連接的過(guò)程需要 三次握手 。 斷開連接的過(guò)程需要 四次揮手 。 使用TCP協(xié)議的通信雙方分別為 客戶端 和 服務(wù)器端 。 客戶端負(fù)責(zé)向服務(wù)

    2024年01月23日
    瀏覽(40)
  • 網(wǎng)絡(luò)編程day2——基于TCP/IP協(xié)議的網(wǎng)絡(luò)通信

    ? ? ? ? 計(jì)算機(jī)S ? ? ? ? ? ? ? ? ? ? ? ? ????????????????????????計(jì)算機(jī)C ? ? ?創(chuàng)建socket對(duì)象 ? ? ? ? ? ? ? ? ????????????????? 創(chuàng)建socket對(duì)象 ? ? ?準(zhǔn)備通信地址(自己的ip(非公網(wǎng)ip))? ? ? 準(zhǔn)備通信地址 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? (計(jì)算

    2024年02月10日
    瀏覽(40)
  • Java網(wǎng)絡(luò)編程之IP,端口號(hào),通信協(xié)議(UDP,TCP)

    Java網(wǎng)絡(luò)編程之IP,端口號(hào),通信協(xié)議(UDP,TCP)

    ① C/S :客戶端/服務(wù)器 在用戶本地需要下載安裝客戶端程序,在遠(yuǎn)程有一個(gè)服務(wù)器端程序。 優(yōu)點(diǎn):畫面精美,用戶體驗(yàn)好 缺點(diǎn):用戶需要下載更新 ② B/S :瀏覽器/服務(wù)器 只需要一個(gè)瀏覽器,用戶通過(guò)指定網(wǎng)址訪問對(duì)應(yīng)的服務(wù)器。 優(yōu)點(diǎn):不需要開發(fā)客戶端,只需要頁(yè)面+服務(wù)

    2024年02月03日
    瀏覽(96)
  • 網(wǎng)絡(luò)編程——深入理解TCP/IP協(xié)議——OSI模型和TCP/IP模型:構(gòu)建網(wǎng)絡(luò)通信的基石

    網(wǎng)絡(luò)編程——深入理解TCP/IP協(xié)議——OSI模型和TCP/IP模型:構(gòu)建網(wǎng)絡(luò)通信的基石

    TCP/IP協(xié)議,即 傳輸控制協(xié)議/互聯(lián)網(wǎng)協(xié)議 ,是一組用于在計(jì)算機(jī)網(wǎng)絡(luò)中實(shí)現(xiàn)通信的協(xié)議。它由兩個(gè)主要的協(xié)議組成:TCP(傳輸控制協(xié)議)和IP(互聯(lián)網(wǎng)協(xié)議)。TCP負(fù)責(zé)確保數(shù)據(jù)的可靠傳輸,而IP則負(fù)責(zé)路由數(shù)據(jù)包以在網(wǎng)絡(luò)中傳遞。TCP/IP協(xié)議簇還包含其他輔助協(xié)議,如UDP(用戶數(shù)

    2024年02月14日
    瀏覽(32)
  • Linux 網(wǎng)絡(luò)編程學(xué)習(xí)筆記——一、TCP/IP 協(xié)議族

    Linux 網(wǎng)絡(luò)編程學(xué)習(xí)筆記——一、TCP/IP 協(xié)議族

    數(shù)據(jù)鏈路層實(shí)現(xiàn)了網(wǎng)卡接口的網(wǎng)絡(luò)驅(qū)動(dòng)程序,以處理數(shù)據(jù)在物理媒介(以太網(wǎng)、令牌環(huán)等)上的傳輸,不同的物理網(wǎng)絡(luò)具有不同的電氣特性,網(wǎng)絡(luò)驅(qū)動(dòng)程序隱藏了這些細(xì)節(jié),為上層協(xié)議提供一個(gè)統(tǒng)一的接口。最常用的協(xié)議是 ARP(Address Resolve Protocol,地址解析協(xié)議)和 RARP(

    2024年02月02日
    瀏覽(40)
  • 【QT網(wǎng)絡(luò)編程】實(shí)現(xiàn)UDP協(xié)議通信

    【QT網(wǎng)絡(luò)編程】實(shí)現(xiàn)UDP協(xié)議通信

    Internet 協(xié)議集支持一個(gè)無(wú)連接的傳輸協(xié)議,該協(xié)議稱為用戶數(shù)據(jù)報(bào)協(xié)議(UDP,User Datagram Protocol)。UDP 為應(yīng)用程序提供了 一種無(wú)需建立連接就可以發(fā)送封裝的 IP 數(shù)據(jù)包的方法 。RFC 768 描述了 UDP。 UDP協(xié)議根據(jù)消息傳送模式可以分為: 單播(Unicast)、組播(Multicast)和廣播(

    2024年02月02日
    瀏覽(26)
  • 基于UDP/TCP的網(wǎng)絡(luò)通信編程實(shí)現(xiàn)

    基于UDP/TCP的網(wǎng)絡(luò)通信編程實(shí)現(xiàn)

    紅色是心中永不褪色的赤誠(chéng) 操作系統(tǒng)為網(wǎng)絡(luò)編程提供了 Socket api , Socket是基于TCP/IP協(xié)議的網(wǎng)絡(luò)通信的基本單元, 基于Socket的網(wǎng)絡(luò)程序開發(fā)就是 網(wǎng)絡(luò)編程. 由于直接與應(yīng)用層聯(lián)系的是傳輸層, 所以針對(duì)應(yīng)用層協(xié)議(TCP, UDP), Shocket提供了三種套接字, 分別是 流套接字(使用TCP) , 數(shù)據(jù)報(bào)

    2024年02月08日
    瀏覽(33)
  • 「網(wǎng)絡(luò)編程」第二講:網(wǎng)絡(luò)編程socket套接字(三)_ 簡(jiǎn)單TCP網(wǎng)絡(luò)通信程序的實(shí)現(xiàn)

    「網(wǎng)絡(luò)編程」第二講:網(wǎng)絡(luò)編程socket套接字(三)_ 簡(jiǎn)單TCP網(wǎng)絡(luò)通信程序的實(shí)現(xiàn)

    「前言」文章是關(guān)于網(wǎng)絡(luò)編程的socket套接字方面的,上一篇是網(wǎng)絡(luò)編程socket套接字(二),下面開始講解!? 「歸屬專欄」網(wǎng)絡(luò)編程 「主頁(yè)鏈接」個(gè)人主頁(yè) 「筆者」楓葉先生(fy) 「楓葉先生有點(diǎn)文青病」「每篇一句」 I?do?not?know?where?to?go,but?I?have?been?on?the?road. 我不知

    2024年02月11日
    瀏覽(29)
  • Linux網(wǎng)絡(luò)編程:socket、客戶端服務(wù)器端使用socket通信(TCP)

    Linux網(wǎng)絡(luò)編程:socket、客戶端服務(wù)器端使用socket通信(TCP)

    socket(套接字),用于網(wǎng)絡(luò)中不同主機(jī)間進(jìn)程的通信。 socket是一個(gè)偽文件,包含讀緩沖區(qū)、寫緩沖區(qū)。 socket必須成對(duì)出現(xiàn)。 socket可以建立主機(jī)進(jìn)程間的通信,但需要協(xié)議(IPV4、IPV6等)、port端口、IP地址。 ??????? ?(1)創(chuàng)建流式socket套接字。 ? ? ? ? ? ? ? ? a)此s

    2024年02月11日
    瀏覽(34)
  • linux【網(wǎng)絡(luò)編程】之HTTPS協(xié)議,一文了解HTTPS是如何保證通信安全的

    linux【網(wǎng)絡(luò)編程】之HTTPS協(xié)議,一文了解HTTPS是如何保證通信安全的

    在上篇文章中我們了解到什么事HTTP協(xié)議,HTTP協(xié)議內(nèi)容都是按照?本的?式明?傳輸?shù)?這就導(dǎo)致在傳輸過(guò)程中出現(xiàn)?些被篡改的情況,本期我們來(lái)探討一下HTTPS協(xié)議。 HTTPS( 超文本傳輸安全協(xié)議 )也是?個(gè)應(yīng)?層協(xié)議.是在HTTP協(xié)議的基礎(chǔ)上引?了?個(gè)加密層. HTTPS:默認(rèn)端口與

    2024年02月08日
    瀏覽(40)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包