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

【網(wǎng)絡(luò)編程】實(shí)現(xiàn)一個(gè)簡(jiǎn)單多線程版本TCP服務(wù)器(附源碼)

這篇具有很好參考價(jià)值的文章主要介紹了【網(wǎng)絡(luò)編程】實(shí)現(xiàn)一個(gè)簡(jiǎn)單多線程版本TCP服務(wù)器(附源碼)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

【網(wǎng)絡(luò)編程】實(shí)現(xiàn)一個(gè)簡(jiǎn)單多線程版本TCP服務(wù)器(附源碼),Linux,網(wǎng)絡(luò),tcp/ip,服務(wù)器

??預(yù)備知識(shí)

?? Accept函數(shù)

accept 函數(shù)是在服務(wù)器端用于接受客戶端連接請(qǐng)求的函數(shù),它在監(jiān)聽(tīng)套接字上等待客戶端的連接,并在有新的連接請(qǐng)求到來(lái)時(shí)創(chuàng)建一個(gè)新的套接字用于與該客戶端通信。

  • 下面是 accept 函數(shù)的詳細(xì)介紹以及各個(gè)參數(shù)的意義:
#include <sys/socket.h>

int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

sockfd: 是服務(wù)器監(jiān)聽(tīng)套接字的文件描述符,通常是使用 socket 函數(shù)創(chuàng)建的套接字。accept 函數(shù)在該套接字上等待連接請(qǐng)求。

addr: 是一個(gè)指向 struct sockaddr 類(lèi)型的指針,用于存儲(chǔ)客戶端的地址信息。當(dāng)新連接建立成功后,客戶端的地址信息將會(huì)被填充到這個(gè)結(jié)構(gòu)體中。

addrlen: 是一個(gè)指向 socklen_t 類(lèi)型的指針,它指示 addr 結(jié)構(gòu)體的長(zhǎng)度。在調(diào)用 accept 函數(shù)之前,需要將其初始化為 addr 結(jié)構(gòu)體的大小,函數(shù)執(zhí)行后會(huì)更新為實(shí)際的客戶端地址長(zhǎng)度。

返回值:如果連接成功建立,accept 函數(shù)將返回一個(gè)新的文件描述符,該文件描述符用于與客戶端進(jìn)行通信。如果連接失敗,函數(shù)將返回 -1,并設(shè)置 errno 以指示錯(cuò)誤原因。

  • accept 函數(shù)的工作原理如下:

當(dāng)服務(wù)器的監(jiān)聽(tīng)套接字接收到一個(gè)新的連接請(qǐng)求時(shí),accept 函數(shù)會(huì)創(chuàng)建一個(gè)新的套接字用于與該客戶端通信。
新的套接字會(huì)繼承監(jiān)聽(tīng)套接字的監(jiān)聽(tīng)屬性,包括 IP 地址、端口等。
accept 函數(shù)會(huì)填充 addr 結(jié)構(gòu)體,以便獲取客戶端的地址信息。
服務(wù)器可以使用返回的新套接字與客戶端進(jìn)行通信。

  • 注意事項(xiàng):

accept 函數(shù)在沒(méi)有連接請(qǐng)求時(shí)會(huì)阻塞,直到有新的連接請(qǐng)求到來(lái)。
如果希望設(shè)置非阻塞模式,可以使用 fcntl 函數(shù)設(shè)置 O_NONBLOCK 屬性。
在多線程或多進(jìn)程環(huán)境下,需要注意 accept 函數(shù)的線程安全性,可以使用互斥鎖等機(jī)制來(lái)保護(hù)。
綜上所述,accept 函數(shù)在構(gòu)建服務(wù)器程序時(shí)非常重要,它使服務(wù)器能夠接受客戶端的連接請(qǐng)求并創(chuàng)建新的套接字與客戶端進(jìn)行通信。

??字節(jié)序轉(zhuǎn)換函數(shù)

在網(wǎng)絡(luò)編程中,字節(jié)序問(wèn)題很重要,因?yàn)椴煌挠?jì)算機(jī)體系結(jié)構(gòu)可能使用不同的字節(jié)序,這可能導(dǎo)致在通信過(guò)程中的數(shù)據(jù)解釋錯(cuò)誤。為了在不同體系結(jié)構(gòu)之間正確傳遞數(shù)據(jù),需要進(jìn)行字節(jié)序的轉(zhuǎn)換。

  • 以下是一些常用的字節(jié)序轉(zhuǎn)換函數(shù):

ntohl 和 htonl: 這些函數(shù)用于 32 位整數(shù)的字節(jié)序轉(zhuǎn)換。ntohl 用于將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序,htonl 則相反,將主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序。

ntohs 和 htons: 這些函數(shù)用于 16 位整數(shù)的字節(jié)序轉(zhuǎn)換。ntohs 用于將網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換為主機(jī)字節(jié)序,htons 則相反,將主機(jī)字節(jié)序轉(zhuǎn)換為網(wǎng)絡(luò)字節(jié)序。

這些函數(shù)通常用于在網(wǎng)絡(luò)編程中處理套接字通信中的數(shù)據(jù)轉(zhuǎn)換,以確保在不同平臺(tái)上的正確數(shù)據(jù)交換。

  • 示例
#include <arpa/inet.h>

int main() {
    uint32_t networkValue = 0x12345678;
    uint32_t hostValue = ntohl(networkValue); // 0x78563412 on a little-endian host
    uint32_t convertedValue = htonl(hostValue); // 0x12345678 on a little-endian host

    uint16_t networkPort = 0x1234;
    uint16_t hostPort = ntohs(networkPort); // 0x3412 on a little-endian host
    uint16_t convertedPort = htons(hostPort); // 0x1234 on a little-endian host

    return 0;
}

請(qǐng)注意,在使用這些函數(shù)時(shí),需要包含 <arpa/inet.h> 頭文件。這些函數(shù)通常在網(wǎng)絡(luò)編程中用于正確處理字節(jié)序問(wèn)題,以確保不同平臺(tái)之間的數(shù)據(jù)傳輸正確。

??listen函數(shù)

在TCP通信中,服務(wù)端需要使用 listen 函數(shù)來(lái)監(jiān)聽(tīng)連接請(qǐng)求。這是因?yàn)門(mén)CP是一種面向連接的協(xié)議,它采用客戶端-服務(wù)端模型進(jìn)行通信,通信雙方需要先建立連接,然后進(jìn)行數(shù)據(jù)的傳輸。監(jiān)聽(tīng)的過(guò)程是為了等待客戶端發(fā)起連接請(qǐng)求。

  • 具體原因如下:

建立連接: 在TCP通信中,通信雙方需要通過(guò)三次握手建立連接??蛻舳送ㄟ^(guò) connect 函數(shù)向服務(wù)器發(fā)起連接請(qǐng)求,而服務(wù)端則需要通過(guò) listen 函數(shù)來(lái)準(zhǔn)備接收連接請(qǐng)求。

處理并發(fā)連接: 服務(wù)端可能會(huì)同時(shí)接收多個(gè)客戶端的連接請(qǐng)求,而每個(gè)連接都需要為其分配一個(gè)獨(dú)立的套接字。通過(guò)監(jiān)聽(tīng)連接請(qǐng)求,服務(wù)端可以在一個(gè)循環(huán)中接受多個(gè)連接,為每個(gè)連接創(chuàng)建對(duì)應(yīng)的套接字,從而實(shí)現(xiàn)并發(fā)處理多個(gè)客戶端。

連接隊(duì)列: listen 函數(shù)將連接請(qǐng)求存儲(chǔ)在一個(gè)隊(duì)列中,等待服務(wù)端逐個(gè)接受。這個(gè)隊(duì)列稱(chēng)為“未完成連接隊(duì)列”(backlog queue)。如果連接請(qǐng)求過(guò)多,超出了隊(duì)列的長(zhǎng)度,那么新的連接請(qǐng)求可能會(huì)被拒絕或被丟棄。

連接參數(shù): listen 函數(shù)還可以指定一個(gè)參數(shù),表示在未完成連接隊(duì)列中可以容納的連接請(qǐng)求數(shù)量。這個(gè)參數(shù)可以影響服務(wù)端處理并發(fā)連接的能力。

總之,TCP監(jiān)聽(tīng)是為了等待客戶端發(fā)起連接請(qǐng)求,建立連接,然后實(shí)現(xiàn)雙方的數(shù)據(jù)傳輸。這種機(jī)制允許服務(wù)器處理多個(gè)客戶端連接,實(shí)現(xiàn)高并發(fā)的網(wǎng)絡(luò)服務(wù)。

  • 函數(shù)原型:
int listen(int sockfd, int backlog);

  • 參數(shù)說(shuō)明:

sockfd:要進(jìn)行監(jiān)聽(tīng)的套接字描述符。
backlog:表示在未完成連接隊(duì)列中可以容納的連接請(qǐng)求數(shù)量。這個(gè)參數(shù)可以影響服務(wù)器處理并發(fā)連接的能力。通常情況下,系統(tǒng)會(huì)為這個(gè)值設(shè)置一個(gè)默認(rèn)的最大值,但你也可以根據(jù)你的需求進(jìn)行適當(dāng)調(diào)整。
返回值:
如果函數(shù)調(diào)用成功,返回 0。
如果出現(xiàn)錯(cuò)誤,返回 -1,并設(shè)置全局變量 errno 來(lái)指示錯(cuò)誤類(lèi)型。

使用步驟:

創(chuàng)建套接字并綁定地址。
調(diào)用 listen 函數(shù)將套接字標(biāo)記為被動(dòng)套接字,開(kāi)始監(jiān)聽(tīng)連接請(qǐng)求。
使用 accept 函數(shù)接受客戶端連接請(qǐng)求,建立實(shí)際的連接。

  • 示例用法
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

int main() {
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(8080);
    server_addr.sin_addr.s_addr = INADDR_ANY;

    if (bind(listen_sock, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("bind");
        exit(EXIT_FAILURE);
    }

    if (listen(listen_sock, 5) == -1) { // 開(kāi)始監(jiān)聽(tīng),最多允許5個(gè)未完成連接
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 現(xiàn)在可以使用 accept 函數(shù)接受連接請(qǐng)求并建立連接

    close(listen_sock);
    return 0;
}

注意:listen 后的套接字僅能用于接受連接請(qǐng)求,不能用于讀寫(xiě)數(shù)據(jù)。接收到的連接請(qǐng)求將在一個(gè)隊(duì)列中等待,直到使用 accept 函數(shù)從隊(duì)列中取出并建立連接。

??代碼

??Log.hpp

#pragma once

#include <cstdio>
#include <ctime>
#include <cstdarg>
#include <cassert>
#include <cstring>
#include <cerrno>
#include <stdlib.h>

#define DEBUG 0
#define NOTICE 1
#define WARINING 2
#define FATAL 3

const char *log_level[]={"DEBUG", "NOTICE", "WARINING", "FATAL"};

// logMessage(DEBUG, "%d", 10);
void logMessage(int level, const char *format, ...)
{
    assert(level >= DEBUG);
    assert(level <= FATAL);

    char *name = getenv("USER");

    char logInfo[1024];
    va_list ap; // ap -> char*
    va_start(ap, format);

    vsnprintf(logInfo, sizeof(logInfo)-1, format, ap);

    va_end(ap); // ap = NULL


    FILE *out = (level == FATAL) ? stderr:stdout;

    fprintf(out, "%s | %u | %s | %s\n", \
        log_level[level], \
        (unsigned int)time(nullptr),\
        name == nullptr ? "unknow":name,\
        logInfo);

    // char *s = format;
    // while(s){
    //     case '%':
    //         if(*(s+1) == 'd')  int x = va_arg(ap, int);
    //     break;
    // }
}

??Makefile

.PHONY:all
all:TCPClient TCPServer

TCPClient: TCPClient.cc
	g++ -o $@ $^ -std=c++11 -lpthread
TCPServer:TCPServer.cc
	g++ -o $@ $^ -std=c++11 -lpthread

.PHONY:clean
clean:
	rm -f TCPClient TCPServer

??TCPClient.cc

#include"util.hpp"
volatile bool quit=false;
static void Usage(std::string proc)
{
    std::cerr<<"Usage:\n\t"<<proc<<"serverip serverport "<<std::endl;
    std::cerr<<"Example:\n\t"<<proc<<"127.0.0.1 8080\n"<<std::endl;
}

int main(int argc,char *argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    std::string serverip=argv[1];
    uint16_t serverport=atoi(argv[2]);
    //1.創(chuàng)建socket SOCK_STREAM
    int sock=socket(AF_INET,SOCK_STREAM,0);
    if(sock<0)
    {
        std::cerr<<"socket :"<<strerror(errno)<<std::endl;
        exit(SOCKET_ERR);
    }
    //2.鏈接 
    //向服務(wù)器發(fā)起鏈接請(qǐng)求
    struct sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family=AF_INET;
    server.sin_port=htons(server.sin_port);
    inet_aton(serverip.c_str(),&server.sin_addr);

    //2.2發(fā)起請(qǐng)求 connect自動(dòng)會(huì)進(jìn)行bind
    if(connect(sock,(const struct sockaddr*)&server,sizeof(server))!=0)
    {
        //鏈接失敗
        std::cerr<<"connect :"<<strerror(errno)<<std::endl;
        exit(CONN_ERR);
    }
    //鏈接成功
    std::cout<<" info :connect success :"<<sock<<std::endl;

    std::string message;


    while(!quit)
    {
        message.clear();
        std::cout<<"請(qǐng)輸入您的消息>>>>"<<std::endl;
        std::getline(std::cin,message);
        if(strcasecmp(message.c_str(),"quit")==0)
        {
            //如果輸入的是quit 直接退出程序
            quit=true; //設(shè)置成true 會(huì)把當(dāng)前信息先執(zhí)行發(fā)送到服務(wù)器 再進(jìn)入while循環(huán)時(shí)條件不滿直接退出

        }

        //從服務(wù)器接收到的消息
        ssize_t s=write(sock,message.c_str(),message.size());
        
        if(s>0)
        {
            message.resize(1024);
            ssize_t s=read(sock,(char *)(message.c_str()),1024);
            if(s>0)
                message[s]=0;
            std::cout<<"Server Echo>>>"<<"message"<<std::endl;
        }
         else if (s <= 0)
        {
            break;
        }
    }
    close(sock);
    
    return 0;
}

??TCPServer.cc

#include "util.hpp"
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <pthread.h>
class ServerTcp;//先聲明

class ThreadData
{
    public:
    uint16_t clientPort_;//客戶端端口號(hào)
    std::string clientip_;//客戶端ip
    int sock_;
    ServerTcp *this_;

     ThreadData(uint16_t port, std::string ip, int sock,  ServerTcp *ts)
        : clientPort_(port), clientip_(ip), sock_(sock),this_(ts)
    {}

};


class ServerTcp
{

    public:
    //構(gòu)造和和析構(gòu)函數(shù)
    ServerTcp(uint16_t port,const std::string &ip=""):port_(port),ip_(ip),listenSock_(-1)
    {}
    ~ServerTcp()
    {}
    


    public:
    //初始化函數(shù)
    void init()
    {

        //第一步:創(chuàng)建套接字
        listenSock_=socket(PF_INET,SOCK_STREAM,0);

        if(listenSock_<0)
        {
            //創(chuàng)建失敗
            logMessage(FATAL,"socket:%s",strerror(errno)); //用日志打印錯(cuò)誤信息
            exit(SOCKET_ERR);
        }
        //創(chuàng)建成功
        logMessage(DEBUG,"sockt:%s,%d",strerror(errno),listenSock_);

        //第二步 bind綁定
        //2.1填充服務(wù)器信息

        struct sockaddr_in local;
        memset(&local,0,sizeof(local));//設(shè)置0?
        /*可以確保將所有這些字段初始化為零,以避免在實(shí)際使用過(guò)程中出現(xiàn)未定義行為或不可預(yù)測(cè)的結(jié)果。*/
        local.sin_family=AF_INET;   
        /*如果 ip_ 為空,服務(wù)器將綁定到任意可用的本地IP地址。如果 ip_ 不為空,服務(wù)器將綁定到 ip_ 所代表的具體IP地址。*/
        ip_.empty()?(local.sin_addr.s_addr)=htons(INADDR_ANY):(inet_aton(ip_.c_str(),&local.sin_addr));
        
        //2.2
        if(bind(listenSock_,(const struct sockaddr*)&local,sizeof local)<0)//
        {
            //bind綁定失敗
            logMessage(FATAL,"bind:%s",strerror(errno));
            exit(BIND_ERR);
        }

        //綁定成功
        logMessage(DEBUG,"bind:%S,%d",strerror(errno),listenSock_);
        //3.監(jiān)聽(tīng)socket
        if(listen(listenSock_,5)<0)
        {
            logMessage(FATAL,"listen:%s",strerror(errno));
            exit(LISTEN_ERR);
        }
        //監(jiān)聽(tīng)成功
        logMessage(DEBUG,"listen:%S,%d",strerror(errno),listenSock_);
        //到這一步就等待運(yùn)行 等待客戶端鏈接
 
    }

    static void *threadRoutine(void *args)
    {
        pthread_detach(pthread_self()); //設(shè)置線程分離
        ThreadData *td = static_cast<ThreadData*>(args);
        td->this_->tranService(td->sock_, td->clientip_, td->clientPort_);
        delete td;
        return nullptr;
    }
    
    //加載
    void loop()
    {
        while(true)
        {
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            //獲取鏈接 accept返回值??
            int serviceSock=accept(listenSock_,(struct sockaddr*)&peer,&len);
            if(serviceSock<0)
            {
                //獲取連接失敗
                logMessage(WARINING,"Accept :%S[%d]",strerror(errno),serviceSock);
                continue;//獲取失敗 繼續(xù)接收....
            }

            //獲取客戶端的基本信息 存儲(chǔ)起來(lái)
             uint16_t peerPort=ntohs(peer.sin_port);
             std::string peerip=inet_ntoa(peer.sin_addr);
            //打印一下獲取的客戶端信息
             logMessage(DEBUG,"Aceept :%s|%s[%d],socket fd :%d",strerror(errno),peerip.c_str(),peerPort,serviceSock);


               // 5 提供服務(wù), echo -> 小寫(xiě) -> 大寫(xiě)
            // 5.0 v0 版本 -- 單進(jìn)程 -- 一旦進(jìn)入transService,主執(zhí)行流,就無(wú)法進(jìn)行向后執(zhí)行,只能提供完畢服務(wù)之后才能進(jìn)行accept
            // transService(serviceSock, peerIp, peerPort);
            
            // 5.1 v1 版本 -- 多進(jìn)程版本 -- 父進(jìn)程打開(kāi)的文件會(huì)被子進(jìn)程繼承嗎?會(huì)的
            // pid_t id = fork();
            // assert(id != -1);
            // if(id == 0)
            // {
            //     close(listenSock_); //建議
            //     //子進(jìn)程
            //     transService(serviceSock, peerIp, peerPort);
            //     exit(0); // 進(jìn)入僵尸
            // }
            // // 父進(jìn)程
            // close(serviceSock); //這一步是一定要做的!

            // 5.1 v1.1 版本 -- 多進(jìn)程版本  -- 也是可以的
            // 爺爺進(jìn)程
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     // 爸爸進(jìn)程
            //     close(listenSock_);//建議
            //     // 又進(jìn)行了一次fork,讓 爸爸進(jìn)程
            //     if(fork() > 0) exit(0);
            //     // 孫子進(jìn)程 -- 就沒(méi)有爸爸 -- 孤兒進(jìn)程 -- 被系統(tǒng)領(lǐng)養(yǎng) -- 回收問(wèn)題就交給了系統(tǒng)來(lái)回收
            //     transService(serviceSock, peerIp, peerPort);
            //     exit(0);
            // }
            // // 父進(jìn)程
            // close(serviceSock); //這一步是一定要做的!
            // // 爸爸進(jìn)程直接終止,立馬得到退出碼,釋放僵尸進(jìn)程狀態(tài)
            // pid_t ret = waitpid(id, nullptr, 0); //就用阻塞式
            // assert(ret > 0);
            // (void)ret;

            // 5.2 v2 版本 -- 多線程
            // 這里不需要進(jìn)行關(guān)閉文件描述符嗎??不需要啦
            // 多線程是會(huì)共享文件描述符表的!
            ThreadData *td = new ThreadData(peerPort, peerip, serviceSock, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, threadRoutine, (void*)td);

            // waitpid(); 默認(rèn)是阻塞等待!WNOHANG
            // 方案1

            // logMessage(DEBUG, "server 提供 service start ...");
            // sleep(1);
        }

    }


     //提供服務(wù)函數(shù) -----> 大小寫(xiě)轉(zhuǎn)換
     void tranService(int sock,const std::string &clientip,uint16_t clientPort)
     {
            assert(sock>=0);
            assert(!clientip.empty());
            assert(clientPort>=1024); //1~~1024端口為系統(tǒng)端口 不可輕易更改
            char inbuffer[BUFFER_SIZE];
            while(true)
            {
                ssize_t s=read(sock,inbuffer,sizeof(inbuffer)-1); //-1是給\0留出一個(gè)位置
                if(s>0)
                {
                    inbuffer[s]='0';
                    if(strcasecmp(inbuffer,"quit")==0)
                    {
                        logMessage(DEBUG,"client quit----------%s[%d]",clientip.c_str(),clientPort);
                        break;
                    }
                    logMessage(DEBUG,"Treans Before:%s[%d]>>>%s",clientip.c_str(),clientPort,inbuffer);
                    //進(jìn)行大小寫(xiě)轉(zhuǎn)換
                    for(int i=0;i<s;i++)
                    {
                        if(isalpha(inbuffer[i])&&islower(inbuffer[i]))
                        {
                            inbuffer[i]=toupper(inbuffer[i]);
                        }
                    }
                        logMessage(DEBUG,"Trans after:%s[%d]>>>>%s",clientip.c_str(),clientPort,inbuffer);
                
                        write(sock,inbuffer,strlen(inbuffer));//給客戶端發(fā)送回去
                }
                    else if(s==0)
                    {
                    // pipe: 讀端一直在讀,寫(xiě)端不寫(xiě)了,并且關(guān)閉了寫(xiě)端,讀端會(huì)如何?s == 0,代表對(duì)端關(guān)閉
                     // s == 0: 代表對(duì)方關(guān)閉,client 退出
                    logMessage(DEBUG, "client quit -- %s[%d]", clientip.c_str(), clientPort);
                    break;
                    }
                    else
                     {
                    logMessage(DEBUG, "%s[%d] - read: %s", clientip.c_str(), clientPort, strerror(errno));
                    break;
                     }
 
                }
                // 只要走到這里,一定是client退出了,服務(wù)到此結(jié)束
        close(sock); // 如果一個(gè)進(jìn)程對(duì)應(yīng)的文件fd,打開(kāi)了沒(méi)有被歸還,文件描述符泄漏!
        logMessage(DEBUG, "server close %d done", sock);
            }
          
    private:
    // sock
    int listenSock_;
    // port
    uint16_t port_;
    // ip
    std::string ip_;
};



static void Usage(std::string proc)
{
    std::cerr << "Usage:\n\t" << proc << " port ip" << std::endl;
    std::cerr << "example:\n\t" << proc << " 8080 127.0.0.1\n" << std::endl;

}

// ./ServerTcp local_port local_ip
int main(int argc, char *argv[])
{
    if(argc != 2 && argc != 3 )
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::string ip;
    if(argc == 3) ip = argv[2];

    ServerTcp svr(port, ip);
    svr.init();
    svr.loop();
    return 0;
}

?? util.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cstdlib>
#include <cassert>
#include <ctype.h>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"

#define SOCKET_ERR 1
#define BIND_ERR   2
#define LISTEN_ERR 3
#define USAGE_ERR  4
#define CONN_ERR   5

#define BUFFER_SIZE 1024

大家可以拉下來(lái)自行測(cè)試…

?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-642193.html

到了這里,關(guān)于【網(wǎng)絡(luò)編程】實(shí)現(xiàn)一個(gè)簡(jiǎn)單多線程版本TCP服務(wù)器(附源碼)的文章就介紹完了。如果您還想了解更多內(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)文章

  • [Qt網(wǎng)絡(luò)編程]之UDP通訊的簡(jiǎn)單編程實(shí)現(xiàn)

    [Qt網(wǎng)絡(luò)編程]之UDP通訊的簡(jiǎn)單編程實(shí)現(xiàn)

    hello!歡迎大家來(lái)到我的Qt學(xué)習(xí)系列之 網(wǎng)絡(luò)編程之UDP通訊的簡(jiǎn)單編程實(shí)現(xiàn)。 希望這篇文章能對(duì)你有所幫助!?。?本篇文章的相關(guān)知識(shí)請(qǐng)看我的上篇文章: 目錄 UDP通訊 ?基于主窗口的實(shí)現(xiàn) ?基于線程的實(shí)現(xiàn) ???????? UDP數(shù)據(jù)報(bào)協(xié)議是一個(gè)面向無(wú)連接的傳輸層報(bào)文協(xié)議 ,它簡(jiǎn)

    2024年04月25日
    瀏覽(29)
  • 基于Python編程實(shí)現(xiàn)簡(jiǎn)單網(wǎng)絡(luò)爬蟲(chóng)實(shí)現(xiàn)

    基于Python編程實(shí)現(xiàn)簡(jiǎn)單網(wǎng)絡(luò)爬蟲(chóng)實(shí)現(xiàn)

    引言 網(wǎng)絡(luò)爬蟲(chóng)(英語(yǔ):web crawler),也叫網(wǎng)絡(luò)蜘蛛(spider),是一種用來(lái)自動(dòng)瀏覽萬(wàn)維網(wǎng)的網(wǎng)絡(luò)機(jī)器人。其目的一般為編纂網(wǎng)絡(luò)索引。 --維基百科 網(wǎng)絡(luò)爬蟲(chóng)可以將自己所訪問(wèn)的頁(yè)面保存下來(lái),以便搜索引擎事后生成索引供用戶搜索。 一般有兩個(gè)步驟:1.獲取網(wǎng)頁(yè)內(nèi)容 ?2.對(duì)獲

    2024年01月18日
    瀏覽(31)
  • 計(jì)算機(jī)網(wǎng)絡(luò)編程 | 并發(fā)服務(wù)器代碼實(shí)現(xiàn)(多進(jìn)程/多線程)

    計(jì)算機(jī)網(wǎng)絡(luò)編程 | 并發(fā)服務(wù)器代碼實(shí)現(xiàn)(多進(jìn)程/多線程)

    歡迎關(guān)注博主 Mindtechnist 或加入【Linux C/C++/Python社區(qū)】一起學(xué)習(xí)和分享Linux、C、C++、Python、Matlab,機(jī)器人運(yùn)動(dòng)控制、多機(jī)器人協(xié)作,智能優(yōu)化算法,濾波估計(jì)、多傳感器信息融合,機(jī)器學(xué)習(xí),人工智能等相關(guān)領(lǐng)域的知識(shí)和技術(shù)。 專(zhuān)欄:《網(wǎng)絡(luò)編程》 當(dāng)涉及到構(gòu)建高性能的服務(wù)

    2024年02月08日
    瀏覽(36)
  • Socket編程接口API并實(shí)現(xiàn)簡(jiǎn)單的TCP網(wǎng)絡(luò)編程

    Socket編程接口API并實(shí)現(xiàn)簡(jiǎn)單的TCP網(wǎng)絡(luò)編程

    #include sys/types.h #include sys/socket.h socket()創(chuàng)建套接字,成功返回套接字的文件描述符,失敗返回-1 domain: 設(shè)置套接字的協(xié)議簇, AF_UNIX AF_INET AF_INET6 type: 設(shè)置套接字的服務(wù)類(lèi)型 SOCK_STREAM SOCK_DGRAM protocol: 一般設(shè)置為 0,表示使用默認(rèn)協(xié)議 int socket(int domain, int type, int protocol); bind()將

    2024年02月13日
    瀏覽(31)
  • 「網(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套接字(二),下面開(kāi)始講解!? 「歸屬專(zhuān)欄」網(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)
  • 【網(wǎng)絡(luò)編程】UDP簡(jiǎn)單實(shí)現(xiàn)翻譯軟件與網(wǎng)絡(luò)聊天室

    【網(wǎng)絡(luò)編程】UDP簡(jiǎn)單實(shí)現(xiàn)翻譯軟件與網(wǎng)絡(luò)聊天室

    在上一章【網(wǎng)絡(luò)編程】demo版UDP網(wǎng)絡(luò)服務(wù)器實(shí)現(xiàn)實(shí)現(xiàn)了客戶端和服務(wù)端之間的數(shù)據(jù)的發(fā)送與接收,上一章我們是直接讓服務(wù)端把接收到的數(shù)據(jù)打印出來(lái)。 但是服務(wù)端并不是只接收到數(shù)據(jù)就完了,它還要 處理任務(wù) 。 所以我們可以在服務(wù)端設(shè)置一個(gè)回調(diào)函數(shù): 用來(lái)處理接收到的

    2024年02月05日
    瀏覽(26)
  • UNIX網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    UNIX網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    UNIX網(wǎng)絡(luò)編程:socket fork()多進(jìn)程 實(shí)現(xiàn)clients/server通信 隨筆介紹了通過(guò)fork()多進(jìn)程實(shí)現(xiàn)了服務(wù)器與多客戶端通信。但除了多進(jìn)程能實(shí)現(xiàn)之外,多線程也是一種實(shí)現(xiàn)方式。 重要的是,多進(jìn)程和多線程是涉及操作系統(tǒng)層次。隨筆不僅要利用pthread_create()實(shí)現(xiàn)多線程編程,也要理解線

    2024年02月06日
    瀏覽(25)
  • Linux網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    Linux網(wǎng)絡(luò)編程:socket & pthread_create()多線程 實(shí)現(xiàn)clients/server通信

    UNIX網(wǎng)絡(luò)編程:socket fork()多進(jìn)程 實(shí)現(xiàn)clients/server通信 隨筆介紹了通過(guò)fork()多進(jìn)程實(shí)現(xiàn)了服務(wù)器與多客戶端通信。但除了多進(jìn)程能實(shí)現(xiàn)之外,多線程也是一種實(shí)現(xiàn)方式。 重要的是,多進(jìn)程和多線程是涉及操作系統(tǒng)層次。隨筆不僅要利用pthread_create()實(shí)現(xiàn)多線程編程,也要理解線

    2024年02月05日
    瀏覽(23)
  • 網(wǎng)絡(luò)編程套接字(二)之UDP服務(wù)器簡(jiǎn)單實(shí)現(xiàn)

    網(wǎng)絡(luò)編程套接字(二)之UDP服務(wù)器簡(jiǎn)單實(shí)現(xiàn)

    目錄 一、服務(wù)端UdpServer 1、udp_server.hpp 1、服務(wù)器的初始化 2、服務(wù)器的運(yùn)行 2、udp_server.cc 二、客戶端UdpClient udp_client.cc 三、完整代碼 首先,我們?cè)谠撐募?,將服?wù)器封裝成一個(gè)類(lèi),而作為一款服務(wù)器,必須要有自己的端口號(hào),同時(shí)網(wǎng)絡(luò)服務(wù)器需要有對(duì)應(yīng)的IP地址,文件描述

    2024年04月16日
    瀏覽(20)
  • 【探索Linux】P.29(網(wǎng)絡(luò)編程套接字 —— 簡(jiǎn)單的TCP網(wǎng)絡(luò)程序模擬實(shí)現(xiàn))

    【探索Linux】P.29(網(wǎng)絡(luò)編程套接字 —— 簡(jiǎn)單的TCP網(wǎng)絡(luò)程序模擬實(shí)現(xiàn))

    在前一篇文章中,我們?cè)敿?xì)介紹了UDP協(xié)議和TCP協(xié)議的特點(diǎn)以及它們之間的異同點(diǎn)。 本文將延續(xù)上文內(nèi)容,重點(diǎn)討論簡(jiǎn)單的TCP網(wǎng)絡(luò)程序模擬實(shí)現(xiàn) 。通過(guò)本文的學(xué)習(xí),讀者將能夠深入了解TCP協(xié)議的實(shí)際應(yīng)用,并掌握如何編寫(xiě)簡(jiǎn)單的TCP網(wǎng)絡(luò)程序。讓我們一起深入探討TCP網(wǎng)絡(luò)程序的

    2024年04月14日
    瀏覽(98)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包