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

【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器

這篇具有很好參考價值的文章主要介紹了【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器


需要云服務(wù)器等云產(chǎn)品來學習Linux的同學可以移步/-->騰訊云<--/-->阿里云<--/-->華為云<--/官網(wǎng),輕量型云服務(wù)器低至112元/年,新用戶首次下單享超低折扣。


?目錄

一、UDP

1、Linux客戶端、服務(wù)器

1.1udpServer.hpp

1.2udpServer.cc

1.3udpClient.hpp

1.4udpClient.cc

1.5onlineUser.hpp

2、Windows客戶端

二、TCP

1、單進程版的TCP客戶端、服務(wù)器

1.1tcpServer.hpp

1.2tcpServer.cc

1.3tcpClient.hpp

1.4tcpClient.cc

1.5log.hpp

2、多進程版的TCP客戶端、服務(wù)器

3、多線程版的TCP客戶端、服務(wù)器

4、線程池版的TCP客戶端、服務(wù)器

4.1tcpServer.hpp

4.2ThreadPool.hpp?

4.3Task.hpp

5、守護進程+多線程版的TCP客戶端、服務(wù)器

5.1daemon.hpp

5.2tcpServer.cc


UDP/TCP客戶端、服務(wù)器代碼可參考本人gitee

UDP/TCP套接字的創(chuàng)建流程可參考此處

一、UDP

1、Linux客戶端、服務(wù)器

1.1udpServer.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
#include <functional>
namespace Server
{
    const static string defaultIp="0.0.0.0";//缺省的IP
    const static int gnum=1024;
    typedef function<void(int,string,uint16_t,string)> func_t;
    enum 
    {
        USAGE_ERR=1,
        SOCKET_ERR,
        BIND_ERR,
        OPEN_ERR,
    };
    class udpServer
    {
    public:
        udpServer(const func_t& callback,const uint16_t& port,const string& ip=defaultIp)
        :_callback(callback)//udpServer.cc傳入的對客戶端數(shù)據(jù)處理的函數(shù)
        ,_port(port)
        ,_ip(ip)
        ,_sockfd(-1)
        {}
        void initServer()
        {
             //1、創(chuàng)建socket
            _sockfd=socket(AF_INET,SOCK_DGRAM,0);//網(wǎng)絡(luò)通信+數(shù)據(jù)報
            if(-1==_sockfd)
            {
                cout<<"socket error"<<errno<<":"<<strerror(errno)<<endl;
                exit(SOCKET_ERR);
            }
            cout<<"socket success"<<":"<<_sockfd<<endl;
            //2、綁定IP和端口號
            struct sockaddr_in local;
            bzero(&local,sizeof(local));//將一段內(nèi)存初始化為全0
            local.sin_family=AF_INET;//協(xié)議族設(shè)置為網(wǎng)絡(luò)通信
            local.sin_port=htons(_port);//設(shè)置端口號,需要轉(zhuǎn)為大端,主機轉(zhuǎn)網(wǎng)絡(luò)
            local.sin_addr.s_addr=inet_addr(_ip.c_str());//將IP字符串轉(zhuǎn)uint32_t的同時轉(zhuǎn)為網(wǎng)絡(luò)字節(jié)序
            //local.sin_addr.s_addr=htonl(INADDR_ANY);//INADDR_ANY就是0,表明任何IP都可以訪問這個服務(wù)器的_port端口
            int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
            if(-1==n)
            {
                cout<<"bind error"<<errno<<":"<<strerror(errno)<<endl;
                exit(BIND_ERR);
            }
        }
        void start()
        {
            char buffer[gnum];
            while(1)
            {
                //循環(huán)讀取數(shù)據(jù)
                struct sockaddr_in local;//輸出型參數(shù)
                socklen_t len=sizeof(local);//必填
                size_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&local,&len);//阻塞式讀取
                //這里需要關(guān)心1、數(shù)據(jù)是什么2、數(shù)據(jù)是誰發(fā)的
                if(s>0)
                {
                    buffer[s]=0;//加上'\0'
                    //1、這是從網(wǎng)絡(luò)讀出來的IP,需要由網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)主機字節(jié)序2、整數(shù)轉(zhuǎn)點分十進制IP,用inet_ntoa進行轉(zhuǎn)換
                    string clientIp=inet_ntoa(local.sin_addr);//將32位IPv4地址(in_addr結(jié)構(gòu)體)轉(zhuǎn)換成點分十進制字符串形式的IP地址
                    uint16_t clientPort=ntohs(local.sin_port);//一樣需要轉(zhuǎn)換字節(jié)序
                    string message=buffer;
                    cout<<clientIp<<"["<<clientPort<<"]#"<<message<<endl;
                    //對數(shù)據(jù)進行處理
                    _callback(_sockfd,clientIp,clientPort,message);
                }
            }
        }
        ~udpServer()
        {

        }
    private:
        uint16_t _port;//端口號
        string _ip;//IP地址(服務(wù)器不建議固定的綁定一個IP地址,因為服務(wù)器需要接收所有的IP)
        int _sockfd;//套接字文件描述符
        func_t _callback;//回調(diào)函數(shù)
    };
}

1.2udpServer.cc

#include <memory>
#include <unordered_map>
#include <fstream>
#include <signal.h>
using namespace std;
#include "udpServer.hpp"
#include "onlineUser.hpp"
using namespace Server;
// const std::string dictTxt="./dict.txt";
// unordered_map<string,string> dict;//字典
// std::string key,value;

static void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<"local_ip local_port\n\n";
}

// static bool cutString(const string& target,string* key,string* value,const string& sep)//字符串截取
// {
//     //string sep=":";
//     auto pos=target.find(sep,0);
//     if(pos==string::npos)
//     {
//         return false;
//     }
//     *key=target.substr(0,pos);
//     *value=target.substr(pos+sep.size());
//     return true;
// }
// static void initDict()//文件操作
// {
//     ifstream in(dictTxt,std::ios_base::binary);
//     if(!in.is_open())//如果文件打開失敗
//     {
//         cerr<<"open file"<<dictTxt<<"error"<<endl;
//         exit(OPEN_ERR);
//     }
//     string line;
//     while(getline(in,line))
//     {
//         if(cutString(line,&key,&value,":"))//如果截取成功
//         {
//             dict.insert(make_pair(key,value));//dict.insert(key,value);
//         }
//         else //截取失敗
//         {
//             //...
//         }
//     }
//     in.close();
//     cout<<"load dict success"<<endl;
// }
// static void debugPrint()//測試打印函數(shù)
// {
//     for(auto& dt:dict)
//     {
//         cout<<dt.first<<"/"<<dt.second<<endl;
//     }
// }
// //客戶端單詞翻譯代碼
// void handMessage(int sockfd,string clientIp,uint16_t clientPort,string message)
// {
//     //對客戶端的信息進行特定的業(yè)務(wù)處理,實現(xiàn)了server通信和業(yè)務(wù)的解耦
//     string response_message;//將查找的字符串保存至此處
//     unordered_map<string,string>::iterator iter=dict.find(message);
//     if(iter==dict.end())
//     {
//         response_message="unknow";
//     }
//     else
//         response_message=iter->second;
//     //服務(wù)端向客戶端回發(fā)數(shù)據(jù)
//     struct sockaddr_in client;
//     bzero(&client,sizeof(client));
//     client.sin_family=AF_INET;
//     client.sin_addr.s_addr=inet_addr(clientIp.c_str());
//     client.sin_port=htons(clientPort);
//     sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,sizeof(client));
// }
// //解析客戶端上傳的命令
// void execCommand(int sockfd,string clientIp,uint16_t clientPort,string cmd)
// {
//     //對客戶端的信息進行特定的業(yè)務(wù)處理,實現(xiàn)了server通信和業(yè)務(wù)的解耦
//     auto end=cmd.find("rm");
//     if(end!=string::npos)
//     {
//         cerr<<clientIp<<":"<<clientPort<<"非法操作"<<cmd<<endl;
//         return;
//     }
//     string response_message;//將客戶端上傳的指令保存至此處
//     FILE* fp=popen(cmd.c_str(),"r");
//     if(fp==nullptr)
//     {
//         response_message=cmd+" exec failed";
//     }
//     char line[1024];
//     while(fgets(line,sizeof(line),fp))
//     {
//         response_message+=line;//讀出客戶端傳入的指令
//     }
//     pclose(fp);
//     //服務(wù)端向客戶端回發(fā)數(shù)據(jù)
//     struct sockaddr_in client;
//     bzero(&client,sizeof(client));
//     client.sin_family=AF_INET;
//     client.sin_addr.s_addr=inet_addr(clientIp.c_str());
//     client.sin_port=htons(clientPort);
//     sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,sizeof(client));
// }
//聊天室
OnlineUser olUser;
void routeMessage(int sockfd,string clientIp,uint16_t clientPort,string message)
{
    //上線就新增,下線就減掉
    if(message=="online")
    {
        olUser.addUser(clientIp,clientPort);
    }
    if(message=="offline")
    {
        olUser.delUser(clientIp,clientPort);
    }
    if(olUser.isOnline(clientIp,clientPort))
    {
        //廣播消息
        olUser.broadcastMessage(sockfd,clientIp,clientPort,message);
    }
    else
    {
        //服務(wù)端向客戶端回發(fā)數(shù)據(jù)
        string response_message="請先運行online";
        struct sockaddr_in client;
        bzero(&client,sizeof(client));
        client.sin_family=AF_INET;
        client.sin_addr.s_addr=inet_addr(clientIp.c_str());
        client.sin_port=htons(clientPort);
        sendto(sockfd,response_message.c_str(),response_message.size(),0,(struct sockaddr*)&client,sizeof(client));
    }
}
// void reload(int signo)//熱加載回調(diào)函數(shù)
// {
//     (void)signo;
//     initDict();
// }
int main(int argc,char* argv[])//./udpServer port
{
    if(argc!=2)//判斷外部傳入的參數(shù)是否為3
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=atoi(argv[1]);//需要轉(zhuǎn)uint16_t整型

    // signal(2,reload);//發(fā)送信號,實現(xiàn)文本的熱加載
    // initDict();
    //std::unique_ptr<udpServer> usvr(new udpServer(handMessage,port));//在線翻譯
    //std::unique_ptr<udpServer> usvr(new udpServer(execCommand,port));//指令解析
    std::unique_ptr<udpServer> usvr(new udpServer(routeMessage,port));//聊天室
    usvr->initServer();
    usvr->start();
    return 0;
}

1.3udpClient.hpp

#pragma once
#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <pthread.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
#include <strings.h>
namespace Client
{
    using namespace std;
    class udpClient
    {
    public:
        udpClient(const string& serverIp,const uint16_t& serverPort)
        :_sockfd(-1)
        ,_serverPort(serverPort)
        ,_serverIp(serverIp)
        {}
        void initClient()
        {
            //創(chuàng)建socket
            _sockfd=socket(AF_INET,SOCK_DGRAM,0);
            if(-1==_sockfd)
            {
                cout<<"socket error"<<errno<<":"<<strerror(errno)<<endl;
                exit(2);
            }
            cout<<"socket syuccess"<<":"<<_sockfd<<endl;
        }
        static void* readMessage(void* args)//類內(nèi)創(chuàng)建線程,有個this指針干擾
        {
            int sockfd=*static_cast<int*>(args);
            pthread_detach(pthread_self());
            while(1)
            {
                //接收服務(wù)端發(fā)送的數(shù)據(jù)
                char buffer[1024];
                struct sockaddr_in temp;
                socklen_t len=sizeof(temp);
                size_t s=recvfrom(sockfd,buffer,sizeof(buffer),0,(struct sockaddr*)&temp,&len);
                if(s>0)
                {
                    buffer[s]=0;//字符串以'\0'結(jié)尾
                }
                cout<<buffer<<endl;
            }
            return nullptr;
        }
        void run()
        {
            pthread_create(&_reader,nullptr,readMessage,(void*)&_sockfd);
            struct sockaddr_in server;
            memset(&server,sizeof(server),0);//初始化為全0
            server.sin_family=AF_INET;
            server.sin_addr.s_addr=inet_addr(_serverIp.c_str());
            server.sin_port=htons(_serverPort);//主機轉(zhuǎn)網(wǎng)絡(luò)
            string message;
            char cmdline[1024];
            while(1)
            {
                //cerr<<"Please Enter#";
                // cin>>message;
                fprintf(stderr,"Enter#");
                fflush(stderr);
                fgets(cmdline,sizeof(cmdline),stdin);
                cmdline[strlen(cmdline)-1]=0;
                message=cmdline;
                //發(fā)送數(shù)據(jù),sendto的時候,操作系統(tǒng)會幫我們自動綁定客戶端端口+IP地址
                sendto(_sockfd,message.c_str(),message.size(),0,(struct sockaddr*)&server,sizeof(server));
                
            }
        }
        ~udpClient()
        {}
    private:
        int _sockfd;
        uint16_t _serverPort;
        string _serverIp;
        pthread_t _reader;//讀線程
    };
}

1.4udpClient.cc

#include <memory>
#include "udpClient.hpp"
using namespace Client;
static void Usage(string proc)
{
    cout<<"Usage:\n\t"<<proc<<"server_ip server_port\n\n";
}
int main(int argc,char* argv[])//./udpClient server_ip server_port
{
    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;
}

1.5onlineUser.hpp

#pragma once
#include <iostream>
#include <string>
#include <unordered_map>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <cstring>
#include <cstdlib>
#include <arpa/inet.h>
using namespace std;
class User
{
public:
    User(const string& ip,const uint16_t& port)
        :_ip(ip)
        ,_port(port)
    {

    }
    ~User()
    {}
    string ip()
    {
        return _ip;
    }
    uint16_t port()
    {
        return _port;
    }
private:
    string _ip;//用戶IP
    uint16_t _port;//用戶端口號

};
class OnlineUser
{
public:
    OnlineUser()
    {}
    ~OnlineUser()
    {}
    void addUser(const string& ip,const uint16_t& port)//新增用戶
    {
        string id=ip+"-"+to_string(port);
        users.insert(make_pair(id,User(ip,port)));
    }
    void delUser(const string& ip,const uint16_t& port)//刪除用戶
    {
        string id=ip+"-"+to_string(port);
        users.erase(id);
    }
    bool isOnline(const string& ip,const uint16_t& port)//是否在線
    {
        string id=ip+"-"+to_string(port);
        return users.find(id)==users.end()?false:true;
    }
    void broadcastMessage(int sockfd,const string& ip,const uint16_t& port,const string& message)//給所有的user廣播消息
    {
        for(auto& user:users)
        {
            //服務(wù)端向客戶端回發(fā)數(shù)據(jù)
            struct sockaddr_in client;
            bzero(&client,sizeof(client));
            client.sin_family=AF_INET;
            client.sin_addr.s_addr=inet_addr(user.second.ip().c_str());
            client.sin_port=htons(user.second.port());
            string s=ip+"_"+to_string(port)+"# ";//id+"#"
            s+=message;
            sendto(sockfd,s.c_str(),s.size(),0,(struct sockaddr*)&client,sizeof(client));
        }
    }
private:
    unordered_map<string,User> users;//string:id=ip+"-"+to_string(port);User:User類
};

2、Windows客戶端

????????可先讓上方Linux服務(wù)器先運行起來,再讓Windows客戶端連接上該服務(wù)端,實現(xiàn)網(wǎng)絡(luò)通信。

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#include <iostream>
#include <WinSock2.h>
#include <string>
#include <cstring>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
uint16_t serverPort = 8080;
string serverIp = "43.XXX.105.XX";//你的云服務(wù)器IP
#define NUM 1024
int main()
{
	WSAData wsd;
	//啟動Winsock
	if (WSAStartup(MAKEWORD(2, 2), &wsd) != 0)
	{
		cout << "WSAStartUp Error = " << WSAGetLastError() << endl;
		return -1;
	}
	else
	{
		cout << "WSAStartup Success" << endl;
	}
	SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);//創(chuàng)建套接字
	if (sock == SOCKET_ERROR)
	{
		cout<<"socket Error = "<< WSAGetLastError() << endl;
		return -2;
	}
	else
	{
		cout << "socket Success" << endl;
	}
	struct sockaddr_in server;
	memset(&server, 0, sizeof(server));
	server.sin_addr.s_addr = inet_addr(serverIp.c_str());
	server.sin_family = AF_INET;
	server.sin_port = htons(serverPort);
	string line;
	char buffer[NUM];
	while (1)
	{
		//發(fā)送數(shù)據(jù)
		cout << "Please Enter#";
		getline(cin, line);
		int n = sendto(sock, line.c_str(), line.size(), 0, (struct sockaddr*)&server, sizeof(server));
		if (n < 0)
		{
			cerr << "sendto Error" << endl;
			break;
		}
		cout << "發(fā)送成功" << endl;
		//接收數(shù)據(jù)
		buffer[0] = 0;//C式清空數(shù)組
		struct sockaddr_in peer;
		int len = (int)sizeof(peer);
		n = recvfrom(sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&peer, &len);
		if (n > 0)
		{
			buffer[n] = 0;
			cout << "server 返回的消息是" << buffer << endl;
		}
		else break;
	}
	closesocket(sock);//關(guān)閉套接字
	WSACleanup();
	return 0;
}

二、TCP

1、單進程版的TCP客戶端、服務(wù)器

????????單線程會一直在ServerIO讀取寫入數(shù)據(jù),為一個客戶端服務(wù),如果此時連接的客戶端不止一個,其他客戶端發(fā)送的信息將不會被顯示。需要使用多線程或多進程解決。

1.1tcpServer.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include "log.hpp"
namespace Server
{
    enum 
    {
        USAGE_ERR=1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
    };
    static const uint16_t gport=8080;//缺省的端口號
    static const int gbacklog=5;//最大連接數(shù)=5+1
    const static std::string defaultIp="0.0.0.0";//缺省的IP
    class TcpServer
    {
    public:
        TcpServer(const uint16_t& port=gport,const std::string& ip=defaultIp )
            :_listenSocket(-1)
            ,_port(port)   
            ,_ip(ip)
        {

        }
        void InitServer()//初始化服務(wù)器
        {
            //1、創(chuàng)建sockrt套接字
            _listenSocket=socket(AF_INET,SOCK_STREAM,0);
            if(_listenSocket<0)
            {
                LogMessage(FATAL,"create socket error");
                exit(SOCKET_ERR);
            }
            LogMessage(NORMAL,"create socket success");
            //2、綁定端口號+ip地址
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_addr.s_addr=inet_addr(_ip.c_str());
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            if(bind(_listenSocket,(struct sockaddr*)&local,sizeof(local))<0)
            {
                LogMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }
            LogMessage(NORMAL,"bind socket success");
            //3、設(shè)置監(jiān)聽狀態(tài)
            if(-1==listen(_listenSocket,gbacklog))
            {
                LogMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            LogMessage(NORMAL,"listen socket success");
        }
        void Start()//啟動服務(wù)器
        {
            while(1)
            {
                //4、服務(wù)器獲取客戶端連接請求
                struct sockaddr_in peer;//輸出型參數(shù),拿到客戶端的信息
                socklen_t len=sizeof(peer);
                int sock=accept(_listenSocket,(struct sockaddr*)&peer,&len);  
                if(-1==sock)      
                {
                    LogMessage(ERROR,"accept error,next");
                    continue;
                }           
                LogMessage(NORMAL,"accept a new link success");
                //5、使用accept的返回值sock進行通信,均為文件操作
                ServerIO(sock);
                close(sock);//必須關(guān)閉使用完畢的sock,否則文件描述符泄漏
            }
        }
        void ServerIO(int sock)
        {
            char buffer[1024];
            while(1)
            {
                //服務(wù)器讀取客戶端數(shù)據(jù),通過套接字sock這個文件描述符讀取數(shù)據(jù)
                ssize_t n=read(sock,buffer,sizeof(buffer)-1);
                if(n>0)
                {
                    buffer[n]=0;
                    std::cout<<"recv message:"<<buffer<<std::endl;
                    std::string outBuffer=buffer;
                    outBuffer+="[server echo]";
                    //服務(wù)器將數(shù)據(jù)處理后發(fā)送回客戶端
                    write(sock,outBuffer.c_str(),outBuffer.size());
                }
                else if(0==n)//服務(wù)器read返回值為0,說明客戶端關(guān)閉了
                {
                    LogMessage(NORMAL,"client quit,server quit");
                    break;
                }
            }
        }
        ~TcpServer()
        {}
    private:
        int _listenSocket;//監(jiān)聽客戶端的連接請求,不用于數(shù)據(jù)通信
        uint16_t _port;//服務(wù)器端口號
        std::string _ip;//服務(wù)器ip地址
    };
}

1.2tcpServer.cc

#include "tcpServer.hpp"
#include "memory"
using namespace Server;
static void Usage(std::string proc)
{
    std::cout<<"Usage:\n\t"<<proc<<"serverPort\n\n";
}
//./tcpServer local_port
int main(int argc,char* argv[])
{
    if(argc!=2)//判斷外部傳入的參數(shù)是否為2
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=std::stoi(argv[1]);
    std::unique_ptr<TcpServer> tsvr(new TcpServer(port));
    tsvr->InitServer();
    tsvr->Start();
    return 0;
}

1.3tcpClient.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#define NUM 1024
class TcpClient
{
public:
    TcpClient(const std::string& serverIp,const uint16_t& serverPort)
        :_serverIp(serverIp)
        ,_serverPort(serverPort)
        ,_sock(-1)
    {

    }
    void InitClient()
    {
        //1、創(chuàng)建套接字
        _sock=socket(AF_INET,SOCK_STREAM,0);
        if(_sock<0)
        {   
            std::cerr<<"cerete socket err"<<std::endl;
            exit(2);
        }
        //2、客戶端需要bind,但是客戶端的綁定不需要我們自己寫,操作系統(tǒng)會去綁定;(無需程序員bind)
    }
    void Start()
    {
        //3、客戶端發(fā)起連接
        struct sockaddr_in server;
        memset(&server,0,sizeof(server));
        server.sin_addr.s_addr=inet_addr(_serverIp.c_str());
        server.sin_family=AF_INET;
        server.sin_port=htons(_serverPort);
        if(connect(_sock,(struct sockaddr*)&server,sizeof(server))<0)//連接失敗
        {
            std::cerr<<"sock connect error"<<std::endl;
        }
        else//連接成功
        {
            //4、客戶端發(fā)送/接收消息,文件操作
            std::string msg;
            while(1)
            {
                std::cout<<"Enter:";
                std::getline(std::cin,msg);
                write(_sock,msg.c_str(),msg.size());
                char buffer[NUM];
                int n=read(_sock,buffer,sizeof(buffer)-1);
                if(n>0)
                {
                    buffer[n]=0;
                    std::cout<<"Server 回顯消息:"<<buffer<<std::endl;
                }
                else
                    break;
            }
        }
    }
    ~TcpClient()
    {
        if(_sock>=0)
        {
            close(_sock);
        }
    }
private:
    int _sock;//客戶端套接字
    uint16_t _serverPort;//服務(wù)器端口號
    std::string _serverIp;//服務(wù)器ip
};

1.4tcpClient.cc

#include "tcpClient.hpp"
#include <memory>
static void Usage(std::string proc)
{
    std::cout<<"Usage:\n\t"<<proc<<"local_ip local_port\n\n";
}
//./tcpClient serverIp serverPort
int main(int argc,char* argv[])
{
    if(argc!=3)
    {
        Usage(argv[0]);
        exit(1);
    }
    std::string serverIp=argv[1];
    uint16_t serverPort=std::stoi(argv[2]);
    std::unique_ptr<TcpClient> tcli(new TcpClient(serverIp,serverPort));
    tcli->InitClient();
    tcli->Start();
    return 0;
}

1.5log.hpp

#pragma once
#include <iostream>
#include <string>
#define DEBUG 0
#define NORMAL 1
#define WARNING 2
#define ERROR 3
#define FATAL 4
//日志功能
void LogMessage(int level,const std::string& message)
{
    //[日志等級][時間戳/時間][pid][message]
    std::cout<<message<<std::endl;
}

2、多進程版的TCP客戶端、服務(wù)器

????????更換tcpServer.hpp即可,其他文件和單進程版一樣。

#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include <cstdlib>
#include "log.hpp"
namespace Server
{
    enum 
    {
        USAGE_ERR=1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
    };
    static const uint16_t gport=8080;//缺省的端口號
    static const int gbacklog=5;//最大連接數(shù)=5+1
    const static std::string defaultIp="0.0.0.0";//缺省的IP
    class TcpServer
    {
    public:
        TcpServer(const uint16_t& port=gport,const std::string& ip=defaultIp )
            :_listenSocket(-1)
            ,_port(port)   
            ,_ip(ip)
        {

        }
        void InitServer()//初始化服務(wù)器
        {
            //1、創(chuàng)建sockrt套接字
            _listenSocket=socket(AF_INET,SOCK_STREAM,0);
            if(_listenSocket<0)
            {
                LogMessage(FATAL,"create socket error");
                exit(SOCKET_ERR);
            }
            LogMessage(NORMAL,"create socket success");
            //2、綁定端口號+ip地址
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_addr.s_addr=inet_addr(_ip.c_str());
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            if(bind(_listenSocket,(struct sockaddr*)&local,sizeof(local))<0)
            {
                LogMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }
            LogMessage(NORMAL,"bind socket success");
            //3、設(shè)置監(jiān)聽狀態(tài)
            if(-1==listen(_listenSocket,gbacklog))
            {
                LogMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            LogMessage(NORMAL,"listen socket success");
        }
        void Start()//啟動服務(wù)器
        {
            while(1)
            {
                //4、服務(wù)器獲取客戶端連接請求
                struct sockaddr_in peer;//輸出型參數(shù),拿到客戶端的信息
                socklen_t len=sizeof(peer);
                int sock=accept(_listenSocket,(struct sockaddr*)&peer,&len);  
                if(-1==sock)      
                {
                    LogMessage(ERROR,"accept error,next");
                    continue;
                }           
                LogMessage(NORMAL,"accept a new link success");
                // //5、使用accept的返回值sock進行通信,均為文件操作
                pid_t id=fork();
                if(id==0)//子進程
                {
                    close(_listenSocket);//子進程的
                    if(fork()>0) exit(0);//讓子進程退出,孫子進程成為孤兒進程,交給1號進程托管回收其退出資源
                    ServerIO(sock);
                    close(sock);//必須關(guān)閉使用完畢的sock,否則文件描述符泄漏(雖然下一句代碼exit(0),孫子進程退出也會釋放文件描述符,最好還是手動關(guān)一下)
                    exit(0);
                }
                close(sock);//這是用于通信的套接字fd,父進程和孫子進程都有這個文件描述符,父進程關(guān)了,該文件描述符引用技術(shù)-1,直至孫子進程退出,該fd才會減為0,關(guān)閉
                //父進程
                //waitpid()
                pid_t ret=waitpid(id,nullptr,0);//這里不能用非阻塞等待,否則父進程先跑去執(zhí)行其他代碼,可能會被卡在accept出不來了(沒有新的客戶端來連接的話)
                if(ret>0)
                {
                    std::cout<<"waitsucceess"<<ret<<std::endl;
                }
            }
        }       
        void ServerIO(int sock)
        {
            char buffer[1024];
            while(1)
            {
                //服務(wù)器讀取客戶端數(shù)據(jù),通過套接字sock這個文件描述符讀取數(shù)據(jù)
                ssize_t n=read(sock,buffer,sizeof(buffer)-1);
                if(n>0)
                {
                    buffer[n]=0;
                    std::cout<<"recv message:"<<buffer<<std::endl;
                    std::string outBuffer=buffer;
                    outBuffer+="[server echo]";
                    //服務(wù)器將數(shù)據(jù)處理后發(fā)送回客戶端
                    write(sock,outBuffer.c_str(),outBuffer.size());
                }
                else if(0==n)//服務(wù)器read返回值為0,說明客戶端關(guān)閉了
                {
                    LogMessage(NORMAL,"client quit,server quit");
                    break;
                }
            }
        }
        ~TcpServer()
        {}
    private:
        int _listenSocket;//監(jiān)聽客戶端的連接請求,不用于數(shù)據(jù)通信
        uint16_t _port;//服務(wù)器端口號
        std::string _ip;//服務(wù)器ip地址
    };
}

區(qū)別在于這張圖里的代碼:

【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器

1、close(_listenSocket):關(guān)閉子進程的監(jiān)聽fd(雖然手動關(guān)不關(guān)都行,因為下一句代碼就讓子進程退出了,最好還是手動關(guān)一下)

2、if(fork()>0) exit(0):讓子進程創(chuàng)建孫子進程,子進程退出。提前干掉子進程,這樣父進程在外部就可以不用阻塞式等待子進程退出了。同時孫子進程成為孤兒進程,會被1號進程領(lǐng)養(yǎng),程序員無需關(guān)心孤兒進程的退出善后工作。

3、孫子進程close(sock):必須關(guān)閉使用完畢的sock,否則文件描述符泄漏(雖然下一句代碼exit(0),孫子進程退出也會釋放文件描述符,最好還是手動關(guān)一下)

4、父進程close(sock):這是用于通信的套接字fd,父進程和孫子進程都有這個文件描述符,父進程關(guān)了,該文件描述符引用計數(shù)-1,直至孫子進程退出,該fd才會減為0,關(guān)閉,所以父進程提前關(guān)閉該fd不會影響孫子進程。但是這里父進程如果不關(guān),客戶端連一個fd+1,存在文件描述符泄露。

5、pid_t ret=waitpid(id,nullptr,0):這里不能用非阻塞等待,否則父進程先跑去執(zhí)行其他代碼,可能會被卡在accept出不來了(如果沒有新的客戶端來連接的話,將一直卡在accept)

3、多線程版的TCP客戶端、服務(wù)器

更換tcpServer.hpp即可,其他文件和單進程版一樣。

#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include <cstdlib>
#include <pthread.h>
#include "log.hpp"
namespace Server
{
    enum 
    {
        USAGE_ERR=1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
    };
    static const uint16_t gport=8080;//缺省的端口號
    static const int gbacklog=5;//最大連接數(shù)=5+1
    const static std::string defaultIp="0.0.0.0";//缺省的IP
    class TcpServer;
    struct ThreadData//用于線程函數(shù)傳參
    {
        ThreadData(TcpServer* self,const int& sock)
            :_self(self)
            ,_sock(sock)
        {}
        TcpServer* _self;//this
        int _sock;//通信fd
    };
    class TcpServer
    {
    public:
        TcpServer(const uint16_t& port=gport,const std::string& ip=defaultIp )
            :_listenSocket(-1)
            ,_port(port)   
            ,_ip(ip)
        {

        }
        void InitServer()//初始化服務(wù)器
        {
            //1、創(chuàng)建sockrt套接字
            _listenSocket=socket(AF_INET,SOCK_STREAM,0);
            if(_listenSocket<0)
            {
                LogMessage(FATAL,"create socket error");
                exit(SOCKET_ERR);
            }
            LogMessage(NORMAL,"create socket success");
            //2、綁定端口號+ip地址
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_addr.s_addr=inet_addr(_ip.c_str());
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            if(bind(_listenSocket,(struct sockaddr*)&local,sizeof(local))<0)
            {
                LogMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }
            LogMessage(NORMAL,"bind socket success");
            //3、設(shè)置監(jiān)聽狀態(tài)
            if(-1==listen(_listenSocket,gbacklog))
            {
                LogMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            LogMessage(NORMAL,"listen socket success");
        }
        void Start()//啟動服務(wù)器
        {
            while(1)
            {
                //4、服務(wù)器獲取客戶端連接請求
                struct sockaddr_in peer;//輸出型參數(shù),拿到客戶端的信息
                socklen_t len=sizeof(peer);
                int sock=accept(_listenSocket,(struct sockaddr*)&peer,&len);  
                if(-1==sock)      
                {
                    LogMessage(ERROR,"accept error,next");
                    continue;
                }           
                LogMessage(NORMAL,"accept a new link success");
                //5、使用accept的返回值sock進行通信,均為文件操作
                //多線程版
                pthread_t tid;
                ThreadData* td=new ThreadData(this,sock);
                pthread_create(&tid,nullptr,threadRoutine,(void*)td);
            }
        }   
        static void* threadRoutine(void* args)
        {
            pthread_detach(pthread_self());//線程分離
            ThreadData* td=static_cast<ThreadData*>(args);
            td->_self->ServerIO(td->_sock);//線程調(diào)用服務(wù)函數(shù)
            close(td->_sock);
            delete td;
            return nullptr;
        }
        void ServerIO(int sock)
        {
            char buffer[1024];
            while(1)
            {
                //服務(wù)器讀取客戶端數(shù)據(jù),通過套接字sock這個文件描述符讀取數(shù)據(jù)
                ssize_t n=read(sock,buffer,sizeof(buffer)-1);
                if(n>0)
                {
                    buffer[n]=0;
                    std::cout<<"recv message:"<<buffer<<std::endl;
                    std::string outBuffer=buffer;
                    outBuffer+="[server echo]";
                    //服務(wù)器將數(shù)據(jù)處理后發(fā)送回客戶端
                    write(sock,outBuffer.c_str(),outBuffer.size());
                }
                else if(0==n)//服務(wù)器read返回值為0,說明客戶端關(guān)閉了
                {
                    LogMessage(NORMAL,"client quit,server quit");
                    break;
                }
            }
        }
        ~TcpServer()
        {}
    private:
        int _listenSocket;//監(jiān)聽客戶端的連接請求,不用于數(shù)據(jù)通信
        uint16_t _port;//服務(wù)器端口號
        std::string _ip;//服務(wù)器ip地址
    };
}

【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器

????????在一個進程中的所有線程都可以訪問到文件描述符表,屬于共享資源,一個線程所對應(yīng)的fd在使用完畢后需要進行關(guān)閉。

4、線程池版的TCP客戶端、服務(wù)器

????????其他文件和單進程版一樣。

4.1tcpServer.hpp

#pragma once
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string>
#include <cstring>
#include <cstdlib>
#include <pthread.h>
#include "log.hpp"
#include "Task.hpp"
#include "ThreadPool.hpp"
namespace Server
{
    enum 
    {
        USAGE_ERR=1,
        SOCKET_ERR,
        BIND_ERR,
        LISTEN_ERR,
    };
    static const uint16_t gport=8080;//缺省的端口號
    static const int gbacklog=5;//最大連接數(shù)=5+1
    const static std::string defaultIp="0.0.0.0";//缺省的IP
    class TcpServer;
    struct ThreadData//用于線程函數(shù)傳參
    {
        ThreadData(TcpServer* self,const int& sock)
            :_self(self)
            ,_sock(sock)
        {}
        TcpServer* _self;//this
        int _sock;//通信fd
    };
    class TcpServer
    {
    public:
        TcpServer(const uint16_t& port=gport,const std::string& ip=defaultIp )
            :_listenSocket(-1)
            ,_port(port)   
            ,_ip(ip)
        {

        }
        void InitServer()//初始化服務(wù)器
        {
            //1、創(chuàng)建sockrt套接字
            _listenSocket=socket(AF_INET,SOCK_STREAM,0);
            if(_listenSocket<0)
            {
                LogMessage(FATAL,"create socket error");
                exit(SOCKET_ERR);
            }
            LogMessage(NORMAL,"create socket success");
            //2、綁定端口號+ip地址
            struct sockaddr_in local;
            memset(&local,0,sizeof(local));
            local.sin_addr.s_addr=inet_addr(_ip.c_str());
            local.sin_family=AF_INET;
            local.sin_port=htons(_port);
            if(bind(_listenSocket,(struct sockaddr*)&local,sizeof(local))<0)
            {
                LogMessage(FATAL,"bind socket error");
                exit(BIND_ERR);
            }
            LogMessage(NORMAL,"bind socket success");
            //3、設(shè)置監(jiān)聽狀態(tài)
            if(-1==listen(_listenSocket,gbacklog))
            {
                LogMessage(FATAL,"listen socket error");
                exit(LISTEN_ERR);
            }
            LogMessage(NORMAL,"listen socket success");
        }
        void Start()//啟動服務(wù)器
        {
            //4、線程池初始化
            ThreadPool<Task>::getInstance()->run();//線程啟動
            while(1)
            {
                //5、服務(wù)器獲取客戶端連接請求
                struct sockaddr_in peer;//輸出型參數(shù),拿到客戶端的信息
                socklen_t len=sizeof(peer);
                int sock=accept(_listenSocket,(struct sockaddr*)&peer,&len);  
                if(-1==sock)      
                {
                    LogMessage(ERROR,"accept error,next");
                    continue;
                }           
                LogMessage(NORMAL,"accept a new link success");
                ThreadPool<Task>::getInstance()->push(Task(sock,ServerIO));
            }
        }   
        ~TcpServer()
        {}
    private:
        int _listenSocket;//監(jiān)聽客戶端的連接請求,不用于數(shù)據(jù)通信
        uint16_t _port;//服務(wù)器端口號
        std::string _ip;//服務(wù)器ip地址
    };
}

4.2ThreadPool.hpp?

#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
#include <unistd.h>
#include <mutex>
#include "Thread.hpp"
#include "LockGuard.hpp"
using namespace ThreadNs;
const int gnum =5;

template <class T>//聲明
class ThreadPool;

template <class T>
struct ThreadData
{
    ThreadData(ThreadPool<T>* tp,const std::string& s)
    :_threadPool(tp)
    ,_name(s)
    {}
    ThreadPool<T>* _threadPool;
    std::string _name;
};
template <class T>
class ThreadPool
{
private:
    //因為普通成員函數(shù)第一個參數(shù)是this指針,和回調(diào)方法不匹配,故改成static類型
    static void* handlerTask(void* args)//args是ThreadData對象指針
    {
        ThreadData<T>* td=static_cast<ThreadData<T>*>(args);
        while(1)
        {
            T t;
            {   //RAII,出了作用域LockGuard會銷毀,將析構(gòu)鎖
                LockGuard lockGuard(td->_threadPool->mutex());//加鎖
                while(td->_threadPool->IsQueueEmpty())//如果隊列為空,則等待
                {
                    td->_threadPool->ThreadWait();
                }
                //線程能走到這里,說明隊列一定有任務(wù)給線程
                t=td->_threadPool->Pop();//從隊列中取出任務(wù)
            }
            t();//Task的operator()
        }
        delete td;//析構(gòu)ThreadData對象
        return nullptr;
    }
    ThreadPool(const int& num=gnum)
    :_num(num)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_cond,nullptr);
        //創(chuàng)建線程
        for(int i=0;i<_num;++i)
        {
            _threads.push_back(new Thread());
        }
    }
    ThreadPool(const ThreadPool<T>&)=delete;//禁用拷貝構(gòu)造
    ThreadPool<T>& operator=(const ThreadPool<T>&)=delete;//禁用賦值運算符重載

public://解決靜態(tài)handlerTask是靜態(tài)函數(shù)的問題,這幾個都是偷家函數(shù)
    void LockQueue()   {pthread_mutex_lock(&_mutex);}
    void UnLockQueue() {pthread_mutex_unlock(&_mutex);}
    bool IsQueueEmpty(){return _taskQueue.empty();}
    void ThreadWait()  {pthread_cond_wait(&_cond,&_mutex);}
    T Pop()         
    {
        T t=_taskQueue.front();
        _taskQueue.pop();
        return t;
    } 
    pthread_mutex_t* mutex()
    {
        return &_mutex;
    }
public: 
    void run()//線程啟動
    {
        for(const auto& t:_threads)
        {
            ThreadData<T>* td=new ThreadData<T>(this,t->threadName());
            t->start(handlerTask,(void*)td);
            std::cout<<t->threadName()<<"start..."<<std::endl;
        }
    }
    void push(const T& in)
    {
        //RAII,出了作用域,鎖將會被釋放
        LockGuard lockGuard(&_mutex);
        _taskQueue.push(in);
        pthread_cond_signal(&_cond);
        std::cout<<"任務(wù)發(fā)送成功"<<std::endl;
    }
    ~ThreadPool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for(const auto& t:_threads)
        {
            delete t;
        }
    }
    static ThreadPool<T>* getInstance()//這里的static的作用是讓這個函數(shù)只有一份,獲取單例對象。tp是臨界資源,需要加鎖
    {
        if(nullptr==tp)//因為鎖只創(chuàng)建一次,防止線程進來被鎖阻塞
        {
            //只進來一次就夠了
            _singletonLock.lock();
            if(nullptr==tp)//說明對象還沒有被創(chuàng)建
            {
                tp=new ThreadPool<T>(); 
            }
            _singletonLock.unlock();
        }
        return tp;
    }
private:
    int _num;//線程個數(shù)
    std::vector<Thread*> _threads;//使用vector存放線程
    std::queue<T> _taskQueue;//任務(wù)隊列,往里面放任務(wù),它是共享資源,需要加鎖保護
    pthread_mutex_t _mutex;//互斥鎖
    pthread_cond_t _cond;//條件變量

    static ThreadPool<T>* tp;//單例模式靜態(tài)的對象指針
    static std::mutex _singletonLock;//獲取單例對象使用的鎖

};
template <class T>
ThreadPool<T>* ThreadPool<T>::tp=nullptr;

template <class T>
std::mutex ThreadPool<T>::_singletonLock;

4.3Task.hpp

#pragma once
#include <iostream>
#include <functional>
#include <string>
void ServerIO(int sock)
{
    char buffer[1024];
    while(1)//適應(yīng)快速響應(yīng)的任務(wù),這個任務(wù)while其實不太合適
    {
        //服務(wù)器讀取客戶端數(shù)據(jù),通過套接字sock這個文件描述符讀取數(shù)據(jù)
        ssize_t n=read(sock,buffer,sizeof(buffer)-1);
        if(n>0)
        {
            buffer[n]=0;
            std::cout<<"recv message:"<<buffer<<std::endl;
            std::string outBuffer=buffer;
            outBuffer+="[server echo]";
            //服務(wù)器將數(shù)據(jù)處理后發(fā)送回客戶端
            write(sock,outBuffer.c_str(),outBuffer.size());
        }
        else if(0==n)//服務(wù)器read返回值為0,說明客戶端關(guān)閉了
        {
            close(sock);
            LogMessage(NORMAL,"client quit,server quit");
            break;
        }
    }
}
class Task
{
    //using func_t=std::function<int(int,int,char)>;
    typedef std::function<void(int)> func_t;//函數(shù)對象
public:
    Task()
    {}
    Task(int sock,func_t func)
    :_sock(sock)
    ,_callBack(func)
    {}
    void operator()()//消費者調(diào)用
    {
        _callBack(_sock);
    }
private:
    int _sock;
    func_t _callBack;//回調(diào)函數(shù)
};

5、守護進程+多線程版的TCP客戶端、服務(wù)器

????????其他文件和單進程版一樣。文章來源地址http://www.zghlxwxcb.cn/news/detail-457606.html

5.1daemon.hpp

#pragma once
#include <iostream>
#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"http://數(shù)據(jù)黑洞,向它寫入的數(shù)據(jù)會被吃掉,讀取數(shù)據(jù)什么都讀不到(不會使進程退出)
void DaemonSele(const char* currrPath=nullptr)
{
    //1、讓調(diào)用進程屏蔽異常的信號
    //SIGPIPE信號會在進程向一個已經(jīng)關(guān)閉的socket連接寫數(shù)據(jù)時產(chǎn)生,如果不處理這個信號,進程會被強制退出。通過忽略SIGPIPE信號,可以避免進程因為這個信號而退出。
    signal(SIGPIPE,SIG_IGN);
    //2、讓自己不是組長,調(diào)用setsid
    if(fork()>0) exit(0);//守護進程也稱精靈進程,本質(zhì)就是一個孤兒進程
    pid_t n=setsid();
    assert(n!=-1);//失敗返回-1
    //3、守護進程脫離終端,所以要關(guān)閉或重定向進程默認打開的文件及文件描述符
    int fd=open(DEV,O_RDWR);//以讀寫的方式打開文件黑洞
    if(fd>=0)//創(chuàng)建成功:重定向
    {
        dup2(fd,0);//將fd覆蓋標準輸入
        dup2(fd,1);
        dup2(fd,2);
        close(fd);
    }
    else//創(chuàng)建失?。菏謩雨P(guān)閉文件描述符
    {
        close(0);
        close(1);
        close(2);
    }
    //4、進程執(zhí)行路徑更改(可改可不改)
    if(currrPath)
    {
        chdir(currrPath);
    }
}

5.2tcpServer.cc

#include "tcpServer.hpp"
#include "memory"
#include "daemon.hpp"
using namespace Server;
static void Usage(std::string proc)
{
    std::cout<<"Usage:\n\t"<<proc<<"serverPort\n\n";
}
//./tcpServer local_port
int main(int argc,char* argv[])
{
    if(argc!=2)//判斷外部傳入的參數(shù)是否為2
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port=std::stoi(argv[1]);
    std::unique_ptr<TcpServer> tsvr(new TcpServer(port));
    tsvr->InitServer();
    DaemonSele();//守護進程化,讓這個獨立的孤兒進程去啟動服務(wù)器
    tsvr->Start();
    return 0;
}

到了這里,關(guān)于【網(wǎng)絡(luò)編程】實現(xiàn)UDP/TCP客戶端、服務(wù)器的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

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

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

相關(guān)文章

  • 【網(wǎng)絡(luò)編程】基于UDP數(shù)據(jù)報實現(xiàn)回顯服務(wù)器/客戶端程序

    【網(wǎng)絡(luò)編程】基于UDP數(shù)據(jù)報實現(xiàn)回顯服務(wù)器/客戶端程序

    個人主頁:兜里有顆棉花糖 歡迎 點贊?? 收藏? 留言? 加關(guān)注??本文由 兜里有顆棉花糖 原創(chuàng) 收錄于專欄【網(wǎng)絡(luò)編程】【Java系列】 本專欄旨在分享學習網(wǎng)絡(luò)編程的一點學習心得,歡迎大家在評論區(qū)交流討論?? 前言 我們?nèi)绻胱寫?yīng)用程序進行網(wǎng)絡(luò)通信的話,就需要調(diào)用傳

    2024年02月04日
    瀏覽(28)
  • 【Java網(wǎng)絡(luò)編程】基于UDP-Socket 實現(xiàn)客戶端、服務(wù)器通信

    【Java網(wǎng)絡(luò)編程】基于UDP-Socket 實現(xiàn)客戶端、服務(wù)器通信

    ? 哈嘍,大家好~我是你們的老朋友: 保護小周??? 本期為大家?guī)淼氖蔷W(wǎng)絡(luò)編程的 UDP Socket 套接字,基于 UDP協(xié)議的 Socket 實現(xiàn)客戶端服務(wù)器通信 ,Socket 套接字可以理解為是,傳輸層給應(yīng)用層提供的一組 API,如此程序,確定不來看看嘛~~ 本期收錄于博主的專欄 : JavaEE_保

    2024年02月02日
    瀏覽(111)
  • C#實現(xiàn)簡單TCP服務(wù)器和客戶端網(wǎng)絡(luò)編程

    C#實現(xiàn)簡單TCP服務(wù)器和客戶端網(wǎng)絡(luò)編程

    在C#中進行網(wǎng)絡(luò)編程涉及許多類和命名空間,用于創(chuàng)建和管理網(wǎng)絡(luò)連接、傳輸數(shù)據(jù)等。下面是一些主要涉及的類和命名空間: System.Net 命名空間: 這個命名空間提供了大部分網(wǎng)絡(luò)編程所需的類,包括: IPAddress :用于表示IP地址。 IPEndPoint :表示IP地址和端口號的組合。 Socke

    2024年02月11日
    瀏覽(37)
  • python網(wǎng)絡(luò)編程:通過socket實現(xiàn)TCP客戶端和服務(wù)端

    python網(wǎng)絡(luò)編程:通過socket實現(xiàn)TCP客戶端和服務(wù)端

    目錄 寫在開頭 socket服務(wù)端(基礎(chǔ)) socket客戶端(基礎(chǔ)) 服務(wù)端實現(xiàn)(可連接多個客戶端)? 客戶端實現(xiàn) 數(shù)據(jù)收發(fā)效果 ? 近期可能會用python實現(xiàn)一些網(wǎng)絡(luò)安全工具,涉及到許多關(guān)于網(wǎng)絡(luò)的知識,逃不過的就是最基本的socket。本文將介紹如何通過python自帶的socket庫實現(xiàn)TCP客戶

    2024年03月21日
    瀏覽(27)
  • Socket網(wǎng)絡(luò)編程(TCP/IP)實現(xiàn)服務(wù)器/客戶端通信。

    Socket網(wǎng)絡(luò)編程(TCP/IP)實現(xiàn)服務(wù)器/客戶端通信。

    一.前言 回顧之前進程間通信(無名管道,有名管道,消息隊列,共享內(nèi)存,信號,信號量),都是在同一主機由內(nèi)核來完成的通信。 那不同主機間該怎么通信呢? 可以使用Socket編程來實現(xiàn)。 Socket編程可以通過網(wǎng)絡(luò)來實現(xiàn)實現(xiàn)不同主機之間的通訊。 二.Socket編程的網(wǎng)絡(luò)模型如

    2024年02月08日
    瀏覽(37)
  • 【網(wǎng)絡(luò)編程】——基于TCP協(xié)議實現(xiàn)回顯服務(wù)器及客戶端

    【網(wǎng)絡(luò)編程】——基于TCP協(xié)議實現(xiàn)回顯服務(wù)器及客戶端

    個人主頁:兜里有顆棉花糖 歡迎 點贊?? 收藏? 留言? 加關(guān)注??本文由 兜里有顆棉花糖 原創(chuàng) 收錄于專欄【網(wǎng)絡(luò)編程】【Java系列】 本專欄旨在分享學習網(wǎng)絡(luò)編程的一點學習心得,歡迎大家在評論區(qū)交流討論?? TCP提供的API主要有兩個類 Socket ( 既會給服務(wù)器使用也會給客

    2024年02月03日
    瀏覽(44)
  • MFC網(wǎng)絡(luò)編程-Udp客戶端

    MFC網(wǎng)絡(luò)編程-Udp客戶端

    目錄 1、UI的設(shè)計: 2、代碼的實現(xiàn): (1)、重寫CSocket虛函數(shù)OnReceive,并且傳入對話框的指針 (2)、初始化SOCKET (3)、綁定本地IP和端口 (4)、顯示本地IP和端口在界面 (5)、進入房間事件 (6)、離開房間事件 (7)、發(fā)送信息事件 (8)、接收到數(shù)據(jù)的處理函數(shù)Proces

    2024年02月06日
    瀏覽(21)
  • Socket實例,實現(xiàn)多個客戶端連接同一個服務(wù)端代碼&TCP網(wǎng)絡(luò)編程 ServerSocket和Socket實現(xiàn)多客戶端聊天

    Socket實例,實現(xiàn)多個客戶端連接同一個服務(wù)端代碼&TCP網(wǎng)絡(luò)編程 ServerSocket和Socket實現(xiàn)多客戶端聊天

    Java socket(套接字)通常也稱作\\\"套接字\\\",用于描述ip地址和端口,是一個通信鏈的句柄。應(yīng)用程序通常通過\\\"套接字\\\"向網(wǎng)絡(luò)發(fā)出請求或者應(yīng)答網(wǎng)絡(luò)請求。 使用socket實現(xiàn)多個客戶端和同一客戶端通訊;首先客戶端連接服務(wù)端發(fā)送一條消息,服務(wù)端接收到消息后進行處理,完成后再

    2024年02月12日
    瀏覽(89)
  • 多進程并發(fā)TCP服務(wù)器模型(含客戶端)(網(wǎng)絡(luò)編程 C語言實現(xiàn))

    摘要 :大家都知道不同pc間的通信需要用到套接字sockte來實現(xiàn),但是服務(wù)器一次只能收到一個客戶端發(fā)來的消息,所以為了能讓服務(wù)器可以接收多個客戶端的連接與消息的傳遞,我們就引入了多進程并發(fā)這樣一個概念。聽名字就可以知道--需要用到進程,當然也有多線程并發(fā)

    2024年02月17日
    瀏覽(105)
  • 網(wǎng)絡(luò)編程六--UDP服務(wù)器客戶端

    網(wǎng)絡(luò)編程六--UDP服務(wù)器客戶端

    UDP(User Datagram Protocol)稱為用戶數(shù)據(jù)報協(xié)議,是一種無連接的傳輸協(xié)議。 UDP的主要應(yīng)用在即使丟失部分數(shù)據(jù),也不影響整體效果的場景。例實時傳輸視頻或音頻時,即使丟失部分數(shù)據(jù),也不會影響整體效果,只是會有輕微的畫面抖動或雜音。 UDP服務(wù)器/客戶端不像TCP那樣,交

    2024年02月15日
    瀏覽(20)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包