• TCP实现网络通信(多进程与多线程版本)


    1.TCP实现网络通信的过程

    1.1服务端

    ● 创建网络套接字:socket(),协议族为AF_INET,套接字类型为SOCK_STREAM。
    本质上是打开一个套接字文件,目前仅仅有与系统相关的内容(inode和blocks)。该套接字文件主要负责监听。
    ● 链接网络套接字与本机ip和端口号:bind(),需要建立输出型参数协议地址空间sockaddr_in
    本质上将本机网络信息内容和套接字文件信息相关联。
    ● 监听网络连接:listen(),参数为套接字的文件描述符。
    本质上是将套接字文件设置为监听状态,允许别人连接。
    ●获取新连接到应用层:accept(),返回值为一个新的套接字的文件描述符,参数为监听套接字的文件描述符。
    返回的套接字文件主要负责信息的传输。
    ●使用read()或者write函数对新套接字文件进行读写,实现网络通信。
    ●关闭套接字文件:close()

    1.2客户端

    ●创建网络套接字:socket(),协议族为AF_INET,套接字类型为SOCK_STREAM。
    ●连接服务端:connect()需要建立协议地址空间,并填入客户端的信息。
    ●使用read()或者write函数对新套接字文件进行读写,实现网络通信。
    ●关闭套接字文件:close()

    2.几个重要函数

    socket等函数以及协议地址空间在udp通信一文中已经详细说明网络套接字(Udp实现简单的网络通信),这里不多赘述。

    2.1 listen()与connect()

    int listen(int sockfd, int backlog);

    第一个参数代表用于监听的套接字文件的文件描述符。监听成功返回0,监听失败返回-1。

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

    第一个参数代表用于监听的套接字文件的文件描述符,第二个参数为服务端的协议地址空间,第三个参数为该协议地址空间的大小。

    2.2 ntohs()与inet_nota

    uint16_t ntohs(uint16_t netshort);

    将一个网络形式的port转化为字符串形式。

    char *inet_ntoa(struct in_addr in);

    将一个struct in_addr类型的结构体中的s.addr取出,并将该ip转化成点分十进制。

    3.基于多进程的TCP通信

    3.1服务端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include
    #include
    using namespace std;
    void Usage(string proc)
    {
        cout << proc << "port_in" << endl;
    }
    void service(int new_sock)
    {
        while (true)
        {
            char buffer[1024];
            memset(buffer, 0, sizeof(buffer));
            ssize_t s = read(new_sock, buffer, sizeof(buffer) - 1);
            if (s > 0)
            {
                buffer[s] = 0;
                cout << "client#" << buffer << endl;
                string echo_string = "server ";
                echo_string += buffer;
                write(new_sock, echo_string.c_str(), echo_string.size());
            }
            else if (s == 0)
            {
                cout << "client quit" << endl;
                break;
            }
            else
            {
                cerr << "read error" << endl;
                break;
            }
        }
    }
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            Usage(argv[0]);
            return 1;
        }
        //创建套接字
        int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (listen_sock < 0)
        {
            cerr << "socket error" << errno << endl;
            return 2;
        }
        //绑定套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(atoi(argv[1]));
        local.sin_addr.s_addr = INADDR_ANY;
        if ((bind(listen_sock, (struct sockaddr *)&local, sizeof(local))) < 0)
        {
            cerr << "bind error" << errno << endl;
            return 3;
        }
        //等待客户端建立链接
        const int back_log = 5;
        if (listen(listen_sock, back_log) < 0)
        {
            cerr << "listen error" << endl;
            return 4;
        }
        //signal(SIGCHLD,SIG_IGN);
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int new_sock = accept(listen_sock, (struct sockaddr *)&peer, &len);
            if (new_sock < 0)
            {
                continue;
            }
            cout << "get a new link..." ;
            uint16_t client_port=ntohs(peer.sin_port);
            string client_ip=inet_ntoa(peer.sin_addr);
            cout<< client_ip<<":"<<client_port<<endl;
            //提供服务
            pid_t id=fork();
            if(id<0)
            {
                continue;   
            }
            else if(id==0)
            {
                close(listen_sock);
                if(fork()>0) exit(0);
                service(new_sock);
                close(new_sock);
                exit(0);
            }
            else
            {
                waitpid(id,nullptr,0);
                close(new_sock);//do nothing
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109

    3.2客户端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    void Usage(string proc)
    {
        cout<<proc<<"ip_ "<<"port_ "<<endl;
    }
    int main(int argc,char* argv[])
    {
        if(argc!=3)
        {
            Usage(argv[0]);
            return 1;
        }
        int sock=socket(AF_INET,SOCK_STREAM,0);
        string svr_ip=argv[1];
        uint16_t port=atoi(argv[2]);
        if(sock<0)
        {
            cerr<<"socket error"<<endl;
            return 2;
        }
        struct sockaddr_in server;
        bzero(&server,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_addr.s_addr=inet_addr(svr_ip.c_str());
        server.sin_port=htons(port);
        if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0)
        {
            cout<<"connect fail"<<endl;
            return 3;
        }
        cout<<"connect success"<<endl;
        while(true)
        {
            cout<<"please Enter#"<<endl;
            char buffer[1024];
            fgets(buffer,sizeof(buffer)-1,stdin);
            write(sock,buffer,strlen(buffer));
            ssize_t s=read(sock,buffer,sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;
                cout<<"server echo#"<<buffer<<endl;
            }
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4.基于多线程的TCP通信

    我们使用线程池来完成多线程实现TCP通信:

    4.1服务端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include
    #include
    #include"Threadpool.hpp"
    using namespace std;
    using namespace ns_threadpool;
    void Usage(string proc)
    {
        cout << proc << "port_in" << endl;
    }
    
    int main(int argc, char *argv[])
    {
        if (argc != 2)
        {
            Usage(argv[0]);
            return 1;
        }
        //创建套接字
        int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
        if (listen_sock < 0)
        {
            cerr << "socket error" << errno << endl;
            return 2;
        }
        //绑定套接字
        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(atoi(argv[1]));
        local.sin_addr.s_addr = INADDR_ANY;
        if ((bind(listen_sock, (struct sockaddr *)&local, sizeof(local))) < 0)
        {
            cerr << "bind error" << errno << endl;
            return 3;
        }
        //等待客户端建立链接
        const int back_log = 5;
        if (listen(listen_sock, back_log) < 0)
        {
            cerr << "listen error" << endl;
            return 4;
        }
        //signal(SIGCHLD,SIG_IGN);
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            int new_sock = accept(listen_sock, (struct sockaddr *)&peer, &len);
            if (new_sock < 0)
            {
                continue;
            }
            cout << "get a new link..." ;
            uint16_t client_port=ntohs(peer.sin_port);
            string client_ip=inet_ntoa(peer.sin_addr);
            cout<< client_ip<<":"<<client_port<<endl;
            //提供服务
            Task t(new_sock);
            ThreadPool<Task>::getinstance()->Push(t);
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    4.2客户端

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    using namespace std;
    void Usage(string proc)
    {
        cout<<proc<<"ip_ "<<"port_ "<<endl;
    }
    int main(int argc,char* argv[])
    {
        if(argc!=3)
        {
            Usage(argv[0]);
            return 1;
        }
        int sock=socket(AF_INET,SOCK_STREAM,0);
        string svr_ip=argv[1];
        uint16_t port=atoi(argv[2]);
        if(sock<0)
        {
            cerr<<"socket error"<<endl;
            return 2;
        }
        struct sockaddr_in server;
        bzero(&server,sizeof(server));
        server.sin_family=AF_INET;
        server.sin_addr.s_addr=inet_addr(svr_ip.c_str());
        server.sin_port=htons(port);
        if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0)
        {
            cout<<"connect fail"<<endl;
            return 3;
        }
        cout<<"connect success"<<endl;
        while(true)
        {
            cout<<"please Enter#"<<endl;
            char buffer[1024];
            fgets(buffer,sizeof(buffer)-1,stdin);
            write(sock,buffer,strlen(buffer));
            ssize_t s=read(sock,buffer,sizeof(buffer)-1);
            if(s>0)
            {
                buffer[s]=0;
                cout<<"server echo#"<<buffer<<endl;
            }
        } 
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4.3任务

    #include 
    #include
    #include
    using namespace std;
    namespace ns_task
    {
        struct Task
        {
        private:
            int sock_;
        public:
            Task() : sock_(-1) {}
            Task(int sock) : sock_(sock) {}
            int Run()
            {
                while (true)
                {
                    char buffer[1024];
                    memset(buffer, 0, sizeof(buffer));
                    ssize_t s = read(sock_, buffer, sizeof(buffer) - 1);
                    if (s > 0)
                    {
                        buffer[s] = 0;
                        cout << "client#" << buffer << endl;
                        string echo_string = "server ";
                        echo_string += buffer;
                        write(sock_, echo_string.c_str(), echo_string.size());
                    }
                    else if (s == 0)
                    {
                        cout << "client quit" << endl;
                        break;
                    }
                    else
                    {
                        cerr << "read error" << endl;
                        break;
                    }
                }
                close(sock_);
            }
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    4.4线程池

    #include 
    #include 
    #include 
    #include 
    #include "task.hpp"
    using namespace std;
    using namespace ns_task;
    namespace ns_threadpool
    {
        template <class T>
        class ThreadPool
        {
        private:
            int num_;
            pthread_mutex_t mtx;
            pthread_cond_t cond;
            queue<T> Task;
            static ThreadPool<T>* ins;
        public:
            ThreadPool() : num_(5)
            {
                pthread_mutex_init(&mtx,nullptr);
                pthread_cond_init(&cond,nullptr);
            }
            void Lock()
            {
                pthread_mutex_lock(&mtx);
            }
            void unLock()
            {
                pthread_mutex_unlock(&mtx);
            }
            void Wait()
            {
                pthread_cond_wait(&cond, &mtx);
            }
            void Wakeup()
            {
                pthread_cond_signal(&cond);
            }
            void Push(T &task)
            {
                Lock();
                Task.push(task);
                unLock();
                Wakeup();
            }
            void Pop(T *task)
            {
                *task = Task.front();
                Task.pop();
            }
            bool IsEmpty()
            {
                return Task.empty();
            }
            static void *Routine(void *args)
            {
                pthread_detach(pthread_self());
                ThreadPool<T> *tp = (ThreadPool<T> *)args;
                while (true)
                {
                    tp->Lock();
                    if (tp->IsEmpty())
                    {
                        tp->Wait();
                    }
                    T t;
                    tp->Pop(&t);
                    tp->unLock();
                    t.Run();
                }
            }
            void InitThreadPool()
            {
                pthread_t tid;
                for (int i = 0; i < num_; i++)
                {
                    pthread_create(&tid,nullptr, Routine, (void *)this);
                }
            }
            static ThreadPool<T>* getinstance()
            {
                if(ins==nullptr)
                {
                    pthread_mutex_t mmtx=PTHREAD_MUTEX_INITIALIZER;
                    pthread_mutex_lock(&mmtx);
                    if(ins==nullptr)
                    {
                        ins=new ThreadPool<T>();
                        ins->InitThreadPool();
                    }
                    pthread_mutex_unlock(&mmtx);
                }
                return ins;
            }
            ~ThreadPool()
            {
                pthread_mutex_destroy(&mtx);
                pthread_cond_destroy(&cond);
            }
        };
        template<class T>
        ThreadPool<T>* ThreadPool<T>::ins=nullptr;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
  • 相关阅读:
    VHDL基础知识笔记(1)
    我遇到的bug(活动)
    6.5 XSS 获取 Cookie 攻击
    IBM MQ 通道数量查看,以及最大通道数的修改
    关于#php#的问题:在安装完wampserver后点击wampserver后弹出这个窗口
    IPV4优先于IPV6设置
    【如何让图片自适应盒子大小】
    基于机器学习LightGBM进行海洋轨迹预测 代码+数据
    spice VDAgent简介
    URAT串口通信协议
  • 原文地址:https://blog.csdn.net/qq_51492202/article/details/126311477