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

【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析

這篇具有很好參考價(jià)值的文章主要介紹了【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

hello !大家好呀! 歡迎大家來(lái)到我的Linux高性能服務(wù)器編程系列之項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,在這篇文章中,你將會(huì)學(xué)習(xí)到如何利用Linux網(wǎng)絡(luò)編程技術(shù)來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聊天程序,并且我會(huì)給出源碼進(jìn)行剖析,以及手繪UML圖來(lái)幫助大家來(lái)理解,希望能讓大家更能了解網(wǎng)絡(luò)編程技術(shù)!??!

希望這篇文章能對(duì)你有所幫助【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,服務(wù)器,運(yùn)維,網(wǎng)絡(luò),linux,c++,大家要是覺(jué)得我寫(xiě)的不錯(cuò)的話(huà),那就點(diǎn)點(diǎn)免費(fèi)的小愛(ài)心吧!【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,服務(wù)器,運(yùn)維,網(wǎng)絡(luò),linux,c++(注:這章對(duì)于高性能服務(wù)器的架構(gòu)非常重要喲!?。。?/p>

【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,服務(wù)器,運(yùn)維,網(wǎng)絡(luò),linux,c++? ? ? ? ?

目錄

一.項(xiàng)目介紹

二.服務(wù)器代碼剖析

2.1 頭文件和相關(guān)數(shù)據(jù)聲明

2.2 服務(wù)器連接準(zhǔn)備代碼

2.3 服務(wù)器處理邏輯代碼

2.3 客戶(hù)端代碼剖析


?

一.項(xiàng)目介紹

? ? ? 像ssh這樣的登錄服務(wù)通常要同時(shí)處理網(wǎng)絡(luò)連接和用戶(hù)輸入,這也可以使用I/O復(fù)用來(lái)實(shí)現(xiàn)。我們以poll為例實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聊天室程序,以闡述如何使用I/O?復(fù)用技術(shù)來(lái)同時(shí)處理網(wǎng)絡(luò)連接和用戶(hù)輸入。該聊天室程序能讓所有用戶(hù)同時(shí)在線(xiàn)群聊,它分為客戶(hù)端和服務(wù)器兩個(gè)部分。其中客戶(hù)端程序有兩個(gè)功能:一是從標(biāo)準(zhǔn)輸入終端讀入用戶(hù)數(shù)據(jù),并將用戶(hù)數(shù)據(jù)發(fā)送至服務(wù)器;二是往標(biāo)準(zhǔn)輸出終端打印服務(wù)器發(fā)送給它的數(shù)據(jù)。服務(wù)器的功能是接收,客戶(hù)數(shù)據(jù),并把客戶(hù)數(shù)據(jù)發(fā)送給每一個(gè)登錄到該服務(wù)器上的客戶(hù)端(數(shù)據(jù)發(fā)送者除外)。下面我們依次給出客戶(hù)端程序和服務(wù)器程序的代碼。

二.服務(wù)器代碼剖析

2.1 頭文件和相關(guān)數(shù)據(jù)聲明

#define _GNU_SOURCE 1
#include<t_stdio.h>
#include<t_file.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include<sys/poll.h>
#include<fcntl.h>
#include<errno.h>
#define user_limit 5 //最大客戶(hù)連接數(shù)量
#define buffer_size 64
#define fd_limit 65535 //最大文件描述符數(shù)量

struct client_data{//創(chuàng)建一個(gè)客戶(hù)地址結(jié)構(gòu)體
    struct sockaddr_in address ; 
    char * write_buf;
    char buf[buffer_size];
};
int setnonblocking (int fd){//將文件描述符改為非阻塞模式
    int old_option = fcntl(fd , F_GETFL);
    int new_option = old_option | O_NONBLOCK;// 添加非阻塞選項(xiàng)
    fcntl(fd , F_SETFL , new_option);//設(shè)置
    return old_option;

}

這部分代碼包含了頭文件,定義了一些宏,以及一個(gè)用于存儲(chǔ)客戶(hù)端數(shù)據(jù)的結(jié)構(gòu)體,這個(gè)結(jié)構(gòu)體是為了服務(wù)器更好控制來(lái)自客戶(hù)端的socket套接字,以及靈活控制對(duì)socket套接字的讀寫(xiě),然后還定義了setnonblocking()函數(shù)來(lái)將傳入的文件描述符利用fcntl函數(shù)改為非阻塞模式,方便服務(wù)器進(jìn)行監(jiān)聽(tīng)。

2.2 服務(wù)器連接準(zhǔn)備代碼

這段代碼是服務(wù)器端程序的入口和初始化部分。下面是逐行的解釋?zhuān)?/p>

int main(int argc , char *argv[]){
    if(argc <= 2)//如果參數(shù)太少
    {
        printf("usage :%s ip_address port_number\n",basename(argv[0]));
        return 1;
    }

這段代碼檢查命令行參數(shù)的數(shù)量。如果參數(shù)少于兩個(gè)(程序名稱(chēng)和IP地址/端口號(hào)),則打印使用說(shuō)明并退出程序。

    const char * ip = argv[1] ;// 提取ip地址
    int port = atoi(argv[2]); //提取端口號(hào)

從命令行參數(shù)中提取服務(wù)器的IP地址和端口號(hào)。

    struct sockaddr_in address ; //服務(wù)器地址
    bzero(&address ,sizeof(address));//清空
    address.sin_family = AF_INET;
    inet_pton(AF_INET , ip ,&address.sin_addr);//設(shè)置ip
    address.sin_port = htons(port); //設(shè)置端口號(hào)

這里創(chuàng)建了一個(gè)sockaddr_in結(jié)構(gòu)體來(lái)存儲(chǔ)服務(wù)器的地址信息,并使用bzero函數(shù)將其清零。然后設(shè)置地址族為AF_INET(IPv4),使用inet_pton函數(shù)將點(diǎn)分十進(jìn)制的IP地址轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序的格式,并存儲(chǔ)在sin_addr字段中。最后,將端口號(hào)從主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序并存儲(chǔ)在sin_port字段中。

    int listenfd = socket(PF_INET ,SOCK_STREAM , 0);//創(chuàng)建監(jiān)聽(tīng)套接字
    assert(listenfd >=0);

創(chuàng)建一個(gè)TCP套接字(SOCK_STREAM)用于監(jiān)聽(tīng)客戶(hù)端連接,并檢查套接字是否創(chuàng)建成功。

    int ret = bind(listenfd , (struct sockaddr*)&address , sizeof(address));//綁定
    assert(ret !=-1);

將套接字綁定到之前設(shè)置的服務(wù)器地址上,并檢查綁定操作是否成功。

    ret = listen(listenfd ,5);//最多同時(shí)監(jiān)聽(tīng)五個(gè)
    assert(ret!=-1);

調(diào)用listen函數(shù),使套接字進(jìn)入監(jiān)聽(tīng)狀態(tài),并設(shè)置最大同時(shí)連接數(shù)為5。然后檢查監(jiān)聽(tīng)操作是否成功。

    //創(chuàng)建user數(shù)組,放入多個(gè)客戶(hù)對(duì)象,并且使用socket的值可以直接用來(lái)索引(作為數(shù)組下標(biāo))連接對(duì)應(yīng)的client_data對(duì)象
    struct client_data * user = malloc(fd_limit * sizeof(struct client_data));
   //為了提高poll性能,限制用戶(hù)數(shù)量
    struct pollfd *fds = malloc(sizeof(struct pollfd) * 6);
    int user_counter = 0;//計(jì)算客戶(hù)連接數(shù)量
    int i=0;
    for( i =  1 ; i<=user_limit ; ++i){//對(duì)每個(gè)fds數(shù)據(jù)初始化
        fds[i].fd = -1;
        fds[i].events =0;
    }

這段代碼分配了兩個(gè)數(shù)組:user數(shù)組用于存儲(chǔ)客戶(hù)端數(shù)據(jù),fds數(shù)組用于poll函數(shù)。user數(shù)組的大小被設(shè)置為fd_limit,這是一個(gè)預(yù)定義的最大文件描述符數(shù)量。fds數(shù)組的大小被設(shè)置為6,這是因?yàn)榉?wù)器程序只監(jiān)聽(tīng)一個(gè)套接字(listenfd),而其余的用于客戶(hù)端連接。user_counter用于跟蹤當(dāng)前連接的客戶(hù)端數(shù)量。fds數(shù)組的其余元素被初始化為-1,表示沒(méi)有對(duì)應(yīng)的文件描述符。

    //初始化怕poll中第一個(gè)數(shù)據(jù):監(jiān)聽(tīng)套接字
    fds[0].fd = listenfd;
    fds[0].events = POLLIN | POLLERR;
    fds[0].revents = 0;

最后,將監(jiān)聽(tīng)套接字listenfd添加到fds數(shù)組中,并設(shè)置其監(jiān)聽(tīng)的事件為可讀事件(POLLIN)和錯(cuò)誤事件(POLLERR)。revents字段用于poll函數(shù)返回時(shí)存儲(chǔ)發(fā)生的事件,在這里初始化為0。

這段代碼為服務(wù)器程序的后續(xù)操作設(shè)置了基礎(chǔ),包括套接字的創(chuàng)建和綁定,以及用于poll函數(shù)的數(shù)組的初始化。

2.3 服務(wù)器處理邏輯代碼

這段代碼是服務(wù)器程序的主循環(huán),它使用poll系統(tǒng)調(diào)用來(lái)監(jiān)控多個(gè)文件描述符(fds數(shù)組)的事件。這個(gè)循環(huán)會(huì)一直運(yùn)行,直到遇到錯(cuò)誤或者被顯式地退出。

while(1){

這是一個(gè)無(wú)限循環(huán),服務(wù)器程序?qū)⒁恢边\(yùn)行直到出現(xiàn)錯(cuò)誤或者執(zhí)行了退出循環(huán)的操作。

    ret = poll(fds , user_counter+1 , -1);//開(kāi)始監(jiān)聽(tīng)
    if(ret <0) {
        printf("poll failed..\n");
        break;
    }

在循環(huán)的頂部,調(diào)用poll函數(shù)來(lái)等待事件發(fā)生。fds數(shù)組包含了所有需要監(jiān)控的文件描述符,user_counter+1表示總共有user_counter個(gè)客戶(hù)端連接加上監(jiān)聽(tīng)套接字listenfd。-1表示poll函數(shù)將阻塞直到至少有一個(gè)文件描述符上有事件發(fā)生。如果poll調(diào)用失?。ǚ祷刂敌∮?),則打印錯(cuò)誤信息并退出循環(huán)。

    for ( i =0 ; i <user_counter+1;i++){//每次對(duì)整個(gè)fds數(shù)組進(jìn)行遍歷處理
        if(fds[i].fd==listenfd && (fds[i].revents & POLLIN)){//如果為第一個(gè)監(jiān)聽(tīng)字符且發(fā)生可讀事件時(shí)
            struct sockaddr_in client_address;//創(chuàng)建一個(gè)新客戶(hù)套接字
            socklen_t client_addrlength = sizeof(client_address);
            int connfd = accept(listenfd ,(struct sockaddr*)&client_address ,&client_addrlength );//獲取客戶(hù)端套接字
            if(connfd<0){//連接錯(cuò)誤
                printf("erron is:%dd\n");
                continue;
            }
            if(user_counter >=user_limit){//用戶(hù)太多
                const char * info ="too many users\n";
                printf("%s\n",info);
                send(connfd , info ,strlen(info) , 0);//發(fā)送錯(cuò)誤給客戶(hù)端
                close(connfd);
                continue;
            }
            //對(duì)于新連接 ,我們要同時(shí)修改fds和users數(shù)組,user[connfd]即對(duì)應(yīng)客戶(hù)端數(shù)據(jù)
            user_counter++;//客戶(hù)數(shù)量加一
            user[connfd].address = client_address;
            setnonblocking(connfd);//設(shè)置為非阻塞模式
            fds[user_counter].fd = connfd;//最新數(shù)據(jù)放入數(shù)組
            fds[user_counter].events = POLLIN | POLLRDHUP | POLLERR;
            fds[user_counter].revents = 0;
            printf("comes a new user , now have %d user\n",user_counter);
        }
        // ... 其他事件處理邏輯 ...
    }

這個(gè)循環(huán)遍歷fds數(shù)組中的每個(gè)文件描述符,檢查它們是否有事件發(fā)生。對(duì)于每個(gè)事件,服務(wù)器程序執(zhí)行相應(yīng)的操作:

  1. 如果監(jiān)聽(tīng)套接字(listenfd)上有新的連接請(qǐng)求(POLLIN事件),服務(wù)器接受新連接,并將新的文件描述符(connfd)添加到fds數(shù)組中。如果連接數(shù)超過(guò)限制(user_limit),服務(wù)器會(huì)發(fā)送一個(gè)錯(cuò)誤消息并關(guān)閉新連接。

  2. 如果有任何文件描述符上有POLLERR事件,表示發(fā)生了錯(cuò)誤,服務(wù)器會(huì)打印錯(cuò)誤信息。

  3. 如果有任何已連接的套接字上有POLLIN事件,表示有數(shù)據(jù)可讀,服務(wù)器會(huì)讀取數(shù)據(jù)并打印。

  4. 如果有任何套接字上有POLLRDHUP事件,表示對(duì)方已經(jīng)關(guān)閉了連接,服務(wù)器會(huì)關(guān)閉對(duì)應(yīng)的連接并更新fds數(shù)組。

  5. 如果有任何套接字上有POLLOUT事件,表示可以寫(xiě)數(shù)據(jù),服務(wù)器會(huì)發(fā)送數(shù)據(jù)(如果有數(shù)據(jù)要發(fā)送)。

在循環(huán)結(jié)束后,服務(wù)器程序會(huì)繼續(xù)執(zhí)行下一次循環(huán),等待更多的連接和事件。

在服務(wù)器端代碼中,poll函數(shù)用于監(jiān)控多個(gè)文件描述符的事件。poll函數(shù)的返回值表示有多少個(gè)文件描述符發(fā)生了事件,而每個(gè)文件描述符的事件類(lèi)型存儲(chǔ)在revents字段中。下面是服務(wù)器端代碼中使用poll函數(shù)監(jiān)控的不同事件類(lèi)型及其解釋?zhuān)?/p>

if(fds[i].fd==listenfd && (fds[i].revents & POLLIN)){
    // ... 接受連接邏輯 ...
}
else if(fds[i].revents & POLLERR){
    // ... 錯(cuò)誤處理邏輯 ...
}
else if(fds[i].revents & POLLIN){
    // ... 讀取數(shù)據(jù)邏輯 ...
}
else if(fds[i].revents & POLLRDHUP){
    // ... 關(guān)閉連接邏輯 ...
}
else if(fds[i].revents & POLLOUT){
    // ... 寫(xiě)數(shù)據(jù)邏輯 ...
}
  1. POLLIN: 這個(gè)事件表示文件描述符上有數(shù)據(jù)可讀。對(duì)于服務(wù)器來(lái)說(shuō),這意味著有新的客戶(hù)端連接請(qǐng)求或者已連接的客戶(hù)端有數(shù)據(jù)發(fā)送過(guò)來(lái)。

  2. POLLERR: 這個(gè)事件表示文件描述符發(fā)生了錯(cuò)誤??赡苁蔷W(wǎng)絡(luò)錯(cuò)誤,也可能是其他類(lèi)型的錯(cuò)誤。服務(wù)器需要檢查并處理這些錯(cuò)誤。

  3. POLLRDHUP: 這個(gè)事件表示文件描述符的讀端已經(jīng)被對(duì)方關(guān)閉。這通常發(fā)生在客戶(hù)端突然斷開(kāi)連接的情況下。

  4. POLLOUT: 這個(gè)事件表示文件描述符的寫(xiě)端準(zhǔn)備好了,可以寫(xiě)入數(shù)據(jù)。對(duì)于服務(wù)器來(lái)說(shuō),這意味著它可以向客戶(hù)端發(fā)送數(shù)據(jù)。

服務(wù)器程序通過(guò)檢查fds數(shù)組中每個(gè)文件描述符的revents字段,來(lái)確定發(fā)生了哪種事件,并相應(yīng)地執(zhí)行處理邏輯。如果沒(méi)有任何事件發(fā)生,poll函數(shù)會(huì)阻塞,直到至少有一個(gè)文件描述符上有事件發(fā)生。服務(wù)器程序通過(guò)這種方式可以高效地處理多個(gè)客戶(hù)端連接。

2.3 客戶(hù)端代碼剖析

這段代碼是一個(gè)簡(jiǎn)單的客戶(hù)端程序,用于連接到一個(gè)服務(wù)器,并通過(guò)標(biāo)準(zhǔn)輸入和輸出與服務(wù)器進(jìn)行通信

#define _GNU_SOURCE 1
#include<t_stdio.h>
#include<t_file.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<assert.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
#include <sys/poll.h>
#include<fcntl.h>
#include<poll.h>
#define buffer_size 64 //緩沖區(qū)大小

這段代碼包含了必要的頭文件和宏定義。_GNU_SOURCE是一個(gè)宏,它用于啟用一些GNU擴(kuò)展,如splice系統(tǒng)調(diào)用。

int main(int argc , char * argv[])
{
    if(argc <= 2)//如果參數(shù)太少
    {
        printf("usage :%s ip_address port_number\n",basename(argv[0]));
        return 1;
    }

這段代碼檢查命令行參數(shù)的數(shù)量。如果參數(shù)少于兩個(gè)(程序名稱(chēng)和IP地址/端口號(hào)),則打印使用說(shuō)明并退出程序。

    const char * ip = argv[1] ;// 提取ip地址
    int port = atoi(argv[2]); //提取端口號(hào)

從命令行參數(shù)中提取服務(wù)器的IP地址和端口號(hào)。

    struct sockaddr_in server_address ; //服務(wù)器地址
    bzero(&server_address ,sizeof(server_address));//清空
    server_address.sin_family = AF_INET;
    inet_pton(AF_INET , ip ,&server_address.sin_addr);//設(shè)置ip
    server_address.sin_port = htons(port); //設(shè)置端口號(hào)

創(chuàng)建一個(gè)sockaddr_in結(jié)構(gòu)體來(lái)存儲(chǔ)服務(wù)器的地址信息,并使用bzero函數(shù)將其清零。然后設(shè)置地址族為AF_INET(IPv4),使用inet_pton函數(shù)將點(diǎn)分十進(jìn)制的IP地址轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序的格式,并存儲(chǔ)在sin_addr字段中。最后,將端口號(hào)從主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序并存儲(chǔ)在sin_port字段中。

    int sockfd = socket(PF_INET , SOCK_STREAM , 0 );//創(chuàng)建本地套接字
    assert(socket >= 0 ); //判錯(cuò)
    if(connect(sockfd , (struct sockaddr *)&server_address , sizeof(server_address)) < 0){//連接失敗的話(huà)
        printf("connection failed...\n");
        close(sockfd);
        return 1;
    }

創(chuàng)建一個(gè)TCP套接字(SOCK_STREAM)用于與服務(wù)器通信,并檢查套接字是否創(chuàng)建成功。然后嘗試連接到服務(wù)器。如果連接失敗,打印錯(cuò)誤信息并退出程序。

    struct pollfd fds[2];//創(chuàng)建pollfd結(jié)構(gòu)類(lèi)型數(shù)組,注冊(cè)標(biāo)準(zhǔn)輸入和sockfd文件描述符上的可讀事件
    fds[0].fd = 0;
    fds[0].events = POLLIN ;//標(biāo)準(zhǔn)輸入可讀
    fds[0].revents = 0; //實(shí)際發(fā)生事件,由內(nèi)核填充
    fds[1].fd = sockfd;
    fds[1].events = POLLIN | POLLRDHUP ;//標(biāo)準(zhǔn)輸入可讀
    fds[1].revents = 0; //實(shí)際發(fā)生事件,由內(nèi)核填充

創(chuàng)建一個(gè)pollfd結(jié)構(gòu)體數(shù)組,用于監(jiān)控標(biāo)準(zhǔn)輸入(0)和套接字(sockfd)上的可讀事件。

    while (1){
        ret = poll(fds , 2 , -1); //最大被監(jiān)聽(tīng)事件只有兩個(gè), 返回符合條件文件總數(shù)
        if(ret < 0){//如果監(jiān)聽(tīng)發(fā)生錯(cuò)誤
            printf("poll falied..\n");
            break;
        }

在循環(huán)的頂部,調(diào)用poll函數(shù)來(lái)等待事件發(fā)生。fds數(shù)組包含了所有需要監(jiān)控的文件描述符,2表示總共有兩個(gè)文件描述符(標(biāo)準(zhǔn)輸入和套接字)。-1表示poll函數(shù)將阻塞直到至少有一個(gè)文件描述符上有事件發(fā)生。如果poll調(diào)用失?。ǚ祷刂敌∮?),則打印錯(cuò)誤信息并退出循環(huán)。

        if(fds[1].revents & POLLRDHUP){//假如發(fā)生了關(guān)閉對(duì)端連接
            printf("server close the connection..\n");
            break;
        }
        else if(fds[1].revents & POLLIN){//假如sockfd文件發(fā)生可讀,則讀取服務(wù)器傳來(lái)數(shù)據(jù)
            memset(readbuf , '\0' , buffer_size);
            recv(fds[1].fd , readbuf , buffer_size -1 , 0);//接收數(shù)據(jù)
             if(ret <= 0){// 如果接收失敗或?qū)Ψ疥P(guān)閉了連接
                printf("server close the connection..\n");
               break;
           }
            printf("%s\n",readbuf);//打印數(shù)據(jù)
        }
 if(fds[0].revents & POLLIN){//標(biāo)準(zhǔn)輸入文件描述符可讀,說(shuō)明我們需要寫(xiě)入數(shù)據(jù)

        ret = splice(0 , NULL , pipefd[1] , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);//從標(biāo)準(zhǔn)輸入寫(xiě)入數(shù)據(jù)到管道寫(xiě)端
        ret = splice(pipefd[0] , NULL , sockfd , NULL ,32768 , SPLICE_F_MORE | SPLICE
        ret = splice(0 , NULL , pipefd[1] , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);//從標(biāo)準(zhǔn)輸入寫(xiě)入數(shù)據(jù)到管道寫(xiě)端
        ret = splice(pipefd[0] , NULL , sockfd , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);//從管道讀端將數(shù)據(jù)傳輸?shù)絪ockfd
        printf("ok");
        }

    }
    close(sockfd);
    return 0;
}

這段代碼檢查套接字(sockfd)上的事件。如果套接字上有POLLRDHUP事件,表示對(duì)方已經(jīng)關(guān)閉了連接,服務(wù)器會(huì)關(guān)閉對(duì)應(yīng)的連接并退出循環(huán)。如果套接字上有POLLIN事件,表示有數(shù)據(jù)可讀,服務(wù)器會(huì)讀取數(shù)據(jù)并打印。

這段代碼是客戶(hù)端程序主循環(huán)的最后一部分,它處理標(biāo)準(zhǔn)輸入(0)上的數(shù)據(jù),并通過(guò)管道(pipefd)將其傳輸?shù)教捉幼郑?code>sockfd)上。

  1. ret = splice(0 , NULL , pipefd[1] , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);:

    • splice是一個(gè)系統(tǒng)調(diào)用,用于直接在內(nèi)核空間復(fù)制數(shù)據(jù),避免了用戶(hù)空間和內(nèi)核空間之間的數(shù)據(jù)拷貝。
    • 第一個(gè)參數(shù)是源文件描述符,這里是從標(biāo)準(zhǔn)輸入0
    • 第二個(gè)參數(shù)是源文件描述符的偏移量,這里為NULL,表示從文件開(kāi)始讀取。
    • 第三個(gè)參數(shù)是目標(biāo)文件描述符,這里是對(duì)應(yīng)的管道寫(xiě)端pipefd[1]。
    • 第四個(gè)參數(shù)是目標(biāo)文件描述符的偏移量,這里為NULL,表示從文件開(kāi)始寫(xiě)入。
    • 第五個(gè)參數(shù)是傳輸?shù)臄?shù)據(jù)量,這里為32768,是一個(gè)系統(tǒng)定義的常量,表示最多傳輸32768字節(jié)。
    • 第六個(gè)參數(shù)是SPLICE_F_MORE,表示這只是一個(gè)中間步驟,還有更多的數(shù)據(jù)要傳輸。
    • 第七個(gè)參數(shù)是SPLICE_F_MOVE,表示傳輸?shù)臄?shù)據(jù)是從內(nèi)核緩沖區(qū)直接移動(dòng),而不是復(fù)制。
  2. ret = splice(pipefd[0] , NULL , sockfd , NULL ,32768 , SPLICE_F_MORE | SPLICE_F_MOVE);:

    • 類(lèi)似地,這段代碼使用splice系統(tǒng)調(diào)用來(lái)從管道讀端pipefd[0]傳輸數(shù)據(jù)到套接字sockfd。
  3. printf("ok");:

    • 打印"ok"表示數(shù)據(jù)傳輸成功。

循環(huán)繼續(xù)執(zhí)行,重復(fù)上述操作,直到連接被關(guān)閉或出現(xiàn)錯(cuò)誤。

  1. close(sockfd);:

    • 關(guān)閉套接字sockfd,釋放資源。
  2. return 0;:

    • 程序返回0,表示正常退出。

這個(gè)客戶(hù)端程序通過(guò)poll系統(tǒng)調(diào)用來(lái)監(jiān)控標(biāo)準(zhǔn)輸入和套接字的事件,并通過(guò)splice系統(tǒng)調(diào)用來(lái)高效地傳輸數(shù)據(jù)。它使用管道作為中間緩沖區(qū),以避免在用戶(hù)空間和內(nèi)核空間之間進(jìn)行數(shù)據(jù)拷貝。

???好啦!到這里這篇文章就結(jié)束啦,關(guān)于實(shí)例代碼中我寫(xiě)了很多注釋?zhuān)绻蠹疫€有不懂得,可以評(píng)論區(qū)或者私信我都可以哦【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,服務(wù)器,運(yùn)維,網(wǎng)絡(luò),linux,c++!! 感謝大家的閱讀,我還會(huì)持續(xù)創(chuàng)造網(wǎng)絡(luò)編程相關(guān)內(nèi)容的,記得點(diǎn)點(diǎn)小愛(ài)心和關(guān)注喲!【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,服務(wù)器,運(yùn)維,網(wǎng)絡(luò),linux,c++?文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-860784.html

到了這里,關(guān)于【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀(guān)點(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)文章

  • Linux高性能服務(wù)器編程——學(xué)習(xí)筆記①

    Linux高性能服務(wù)器編程——學(xué)習(xí)筆記①

    第一章有一些概念講的很好,值得好好關(guān)注一下?。?! 1.1 主要的協(xié)議 1.1.1 數(shù)據(jù)鏈路層 ? 數(shù)據(jù)鏈路層實(shí)現(xiàn)了網(wǎng)卡接口的網(wǎng)絡(luò)驅(qū)動(dòng)程序,以處理數(shù)據(jù)在物理媒介(以太網(wǎng)、令牌環(huán))上的傳輸。 ? 常用的協(xié)議有兩種: ARP協(xié)議(Address Resolve Protocol,地址解析協(xié)議) RARP(Reverse

    2024年01月20日
    瀏覽(35)
  • Linux高性能服務(wù)器編程——ch10筆記

    信號(hào)是由用戶(hù)、系統(tǒng)或者進(jìn)程發(fā)送給目標(biāo)進(jìn)程的信息,以通知目標(biāo)進(jìn)程某個(gè)狀態(tài)的改變或系統(tǒng)異常。 :::tips int kill(pid_t pid, int sig); ::: kill函數(shù):一個(gè)進(jìn)程給其他進(jìn)程發(fā)送信號(hào)的API。 sig一般大于0,如果設(shè)為0則表示不發(fā)送信號(hào),可以用來(lái)檢測(cè)進(jìn)程或進(jìn)程組是否存在。由于進(jìn)程P

    2024年02月06日
    瀏覽(25)
  • Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第五章 Linux網(wǎng)絡(luò)編程基礎(chǔ)API

    Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第五章 Linux網(wǎng)絡(luò)編程基礎(chǔ)API

    我們將從以下3方面討論Linux網(wǎng)絡(luò)API: 1.socket地址API。socket最開(kāi)始的含義是一個(gè)IP地址和端口對(duì)(ip,port),它唯一表示了使用TCP通信的一端,本書(shū)稱(chēng)其為socket地址。 2.socket基礎(chǔ)API。socket的主要API都定義在sys/socket.h頭文件中,包括創(chuàng)建socket、命名socket、監(jiān)聽(tīng)socket、接受連接、發(fā)

    2024年02月07日
    瀏覽(41)
  • Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第二章 IP協(xié)議詳解

    Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第二章 IP協(xié)議詳解

    本章從兩方面探討IP協(xié)議: 1.IP頭部信息。IP頭部出現(xiàn)在每個(gè)IP數(shù)據(jù)報(bào)中,用于指定IP通信的源端IP地址、目的端IP地址,指導(dǎo)IP分片和重組,指定部分通信行為。 2.IP數(shù)據(jù)報(bào)的路由和轉(zhuǎn)發(fā)。IP數(shù)據(jù)報(bào)的路由和轉(zhuǎn)發(fā)發(fā)生在除目標(biāo)機(jī)器外的所有主機(jī)和路由器上,它們決定數(shù)據(jù)報(bào)是否應(yīng)

    2024年02月09日
    瀏覽(31)
  • 【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析

    【linux高性能服務(wù)器編程】項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析

    hello !大家好呀! 歡迎大家來(lái)到我的Linux高性能服務(wù)器編程系列之項(xiàng)目實(shí)戰(zhàn)——仿QQ聊天程序源碼剖析,在這篇文章中, 你將會(huì)學(xué)習(xí)到如何利用Linux網(wǎng)絡(luò)編程技術(shù)來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的聊天程序,并且我會(huì)給出源碼進(jìn)行剖析,以及手繪UML圖來(lái)幫助大家來(lái)理解,希望能讓大家更能了

    2024年04月28日
    瀏覽(33)
  • Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第一章 TCP/IP協(xié)議族

    Linux高性能服務(wù)器編程 學(xué)習(xí)筆記 第一章 TCP/IP協(xié)議族

    現(xiàn)在Internet使用的主流協(xié)議族是TCP/IP協(xié)議族,它是一個(gè)分層、多協(xié)議的通信體系。 TCP/IP協(xié)議族包含眾多協(xié)議,我們只詳細(xì)討論IP協(xié)議和TCP協(xié)議,因?yàn)樗鼈儗?duì)編寫(xiě)網(wǎng)絡(luò)應(yīng)用程序有最直接的影響。如果想系統(tǒng)學(xué)習(xí)網(wǎng)絡(luò)協(xié)議,RFC(Request For Comments,評(píng)論請(qǐng)求)是首選資料。 TCP/IP協(xié)議

    2024年02月09日
    瀏覽(41)
  • Linux高性能服務(wù)器編程|閱讀筆記:第6章 - 高級(jí)I/O函數(shù)

    Linux高性能服務(wù)器編程|閱讀筆記:第6章 - 高級(jí)I/O函數(shù)

    Hello! 非常感謝您閱讀海轟的文章,倘若文中有錯(cuò)誤的地方,歡迎您指出~ ? ?(?ˊ?ˋ)? 昵稱(chēng):海轟 標(biāo)簽:程序猿

    2024年02月03日
    瀏覽(22)
  • Linux高性能服務(wù)器編程|閱讀筆記:第1章 - TCP/IP協(xié)議族

    Linux高性能服務(wù)器編程|閱讀筆記:第1章 - TCP/IP協(xié)議族

    Hello! 非常感謝您閱讀海轟的文章,倘若文中有錯(cuò)誤的地方,歡迎您指出~ ? ?(?ˊ?ˋ)? 昵稱(chēng):海轟 標(biāo)簽:程序猿|C++選手|學(xué)生 簡(jiǎn)介:因C語(yǔ)言結(jié)識(shí)編程,隨后轉(zhuǎn)入計(jì)算機(jī)專(zhuān)業(yè),獲得過(guò)國(guó)家獎(jiǎng)學(xué)金,有幸在競(jìng)賽中拿過(guò)一些國(guó)獎(jiǎng)、省獎(jiǎng)…已保研 學(xué)習(xí)經(jīng)驗(yàn):扎實(shí)基礎(chǔ) + 多做

    2024年02月01日
    瀏覽(44)
  • 強(qiáng)推Linux高性能服務(wù)器編程, 真的是后端開(kāi)發(fā)技術(shù)提升, 沉淀自身不容錯(cuò)過(guò)的一本經(jīng)典書(shū)籍

    強(qiáng)推Linux高性能服務(wù)器編程, 真的是后端開(kāi)發(fā)技術(shù)提升, 沉淀自身不容錯(cuò)過(guò)的一本經(jīng)典書(shū)籍

    目錄 第1章 TCP/IP協(xié)議 1.1 TCP/IP協(xié)議族體系結(jié)構(gòu)以及主要協(xié)議 1.1.1 數(shù)據(jù)鏈路層 1.1.2 網(wǎng)絡(luò)層 1.1.3 傳輸層 1.1.4 應(yīng)用層 1.2 封裝 1.3 分用 1.5 ARP協(xié)議工作原理 1.5.1 以太網(wǎng)ARP請(qǐng)求/應(yīng)答報(bào)文詳解 1.5.2 ARP高速緩存的查看和修改 1.5.3 使用tcpdump觀(guān)察ARP通信過(guò)程所得結(jié)果如下 本篇核心關(guān)鍵所在

    2024年02月07日
    瀏覽(120)
  • 【網(wǎng)絡(luò)編程】高性能并發(fā)服務(wù)器源碼剖析

    【網(wǎng)絡(luò)編程】高性能并發(fā)服務(wù)器源碼剖析

    ? hello !大家好呀! 歡迎大家來(lái)到我的網(wǎng)絡(luò)編程系列之洪水網(wǎng)絡(luò)攻擊,在這篇文章中, 你將會(huì)學(xué)習(xí)到在網(wǎng)絡(luò)編程中如何搭建一個(gè)高性能的并發(fā)服務(wù)器,并且我會(huì)給出源碼進(jìn)行剖析,以及手繪UML圖來(lái)幫助大家來(lái)理解,希望能讓大家更能了解網(wǎng)絡(luò)編程技術(shù)!?。?希望這篇文章能

    2024年04月15日
    瀏覽(43)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包