tcp套接字的应用

tcp服务端流程

 tcp客户端流程

 客户端代码

tcpClient.hpp

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

using namespace std;

namespace szg
{
    class tcpClient
    {
    public:
        tcpClient(string ip, uint16_t port)
        :_ip(ip), _port(port)
        {
            _sock = socket(AF_INET, SOCK_STREAM, 0);
            if(_sock < 0)
            {
                cerr << "用户端创建套接字失败" << endl;
                exit(-1);
            }
            cout << "用户端创建套接字成功" << endl;
        }

        void start()
        {
            sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = inet_addr(_ip.c_str());


            if(connect(_sock, (sockaddr*)&server, sizeof(server)))
            {
                cerr << "客户端获取服务失败" << endl;
            }
            cout << "客户端获取服务成功" << endl;


            while(true)
            {
                string message;
                while(true)
                {
                    getline(cin, message);
                    write(_sock, message.c_str(), message.size());


                    char rvbuf[1024];
                    size_t n = read(_sock, rvbuf, sizeof(rvbuf) - 1);
                    rvbuf[n] = 0;
                    if(0 == n)
                    {
                        cerr << "server qiut , me too" << endl;
                        break;
                    }
                    cout << "server 回显:" << rvbuf << endl;

                }
            }
        }

    private:
        int  _sock;
        string _ip;
        uint16_t _port;
    };



}

tcpClient.cc

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


int main(int args, char* argv[])
{
    if(args != 3)
    {
        cout << "\nUsage:\n\t" << argv[0] << " serverip serverport\n\n";
    }

    string ip = argv[1];
    uint16_t port = atoi(argv[2]);

    unique_ptr<szg::tcpClient> tcpclient(new szg::tcpClient(ip, port));
    tcpclient->start();

    return 0;
}



客户端进程版

tcpServer.hpp

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

#include <string.h>
#include <errno.h>

using namespace std;

namespace szg
{
    string df_ip = "0.0.0.0";
    uint16_t df_port = 8080;
    class tcpServer
    {
    public:
        tcpServer(uint16_t port = df_port)
        : _port(port)
        {
            //1.创建套接字
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensock < 0)
            {
                cerr << "服务端创建套接字失败" << endl;
                exit(-1);
            }
            cout << "服务端创建套接字成功" << endl;
        }

        void start()
        {
            //2.绑定套接字
            sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = INADDR_ANY;
            if(-1 == bind(_listensock, (sockaddr*)&server, sizeof(server)))
            {
                cerr << "服务端绑定监听套接字失败" << endl;
                perror("server bind :");
                exit(1);
            }
            cout << "服务端绑定监听套接字成功" << endl;


            //3.设置套接字为监听状态
            if(listen(_listensock, 5))
            {
                cerr << "服务器监听状态设置失败" << endl;
                exit(2);
            }
            cout << "服务器监听状态设置成功" << endl;

            signal(SIGCHLD, SIG_IGN);


            
            while(true)
            {
                sockaddr_in peer;
                socklen_t len = sizeof(peer);

                //4.建立连接
                int newsock = accept(_listensock, (sockaddr*)&peer, &len);
                if(newsock < 0)
                {
                    cerr << "服务器监听客户端失败" << endl;
                }
                cout << "服务器监听客户端成功" << endl;
                if(0 == fork())
                {
                    char rdbuf[1024];
                    while (true)
                    {
                        size_t n = read(newsock, rdbuf, sizeof(rdbuf) - 1);
                        if(n == 0)
                        {
                            cout << "client offline,  me too" << endl;
                            break;
                        }
                        rdbuf[n] = 0;
                        
                        write(newsock, rdbuf, strlen(rdbuf));
                    }
                    exit(0);   
                }
                close(newsock);

            }
        }

    private:
        int  _listensock;
        uint16_t _port;
    };



}

tcpServer.cc

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


int main(int args, char* argv[])
{
    if(args != 2)
    {
        cout << "\nserver:\n\t" << argv[0] << " serverport\n\n";
    }

    uint16_t port = atoi(argv[1]);

    unique_ptr<szg::tcpServer> tcpserver(new szg::tcpServer(port));
    tcpserver->start();

    return 0;
}

客户端线程池版

MutexGuard.hpp

#pragma once
#include<pthread.h>

class MutexGuard
{
public:
    MutexGuard(pthread_mutex_t* pmutex)
    :_pmutex(pmutex)
    {
        pthread_mutex_lock(_pmutex);
    }

    ~MutexGuard()
    {
        pthread_mutex_unlock(_pmutex);
    }
private:
    pthread_mutex_t* _pmutex;
};

mythread.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstring>
#include <cassert>
#include <functional>
#include <pthread.h>

class Thread;

//context传递对象的地址,帮助静态成员函数可以使用类内成员变量
class context
{
public:
    context(Thread* t = nullptr, void* args = nullptr)
    :_this(t)
    ,_args(args)
    {}
    Thread* _this;
    void* _args;
};

class Thread
{
public:
    Thread(const std::function<void*(void*)>& f, void* args = nullptr, const std::string& name = "")
    :_func(f)
    ,_args(args)
    ,_name(name)
    {
        ++_num;
        if(_name.size() == 0)
        {
            _name += "thread  ";
            _name += std::to_string(_num);
        }
        //创建上下文结构体
        context* pcon = new context(this, _args);
        int n = pthread_create(&_tid, nullptr, route_start, pcon);
        assert(0 == n);
        (void)n;
    }
    static void* route_start(void* pcon)
    {
        context* cont = static_cast<context*>(pcon);
        void* ret = cont->_this->run(cont->_args);
        delete cont;
        return ret;
    }

    void* run(void* args)
    {
        return _func(args);
    }

    void join()
    {
        int n = pthread_join(_tid, nullptr);
        assert(n == 0);
        (void)n;
    }

    std::string name()
    {
        return _name;
    }

    ~Thread()
    {
        --_num;
    }
private:
    pthread_t  _tid;
    std::string _name;
    void* _args;
    std::function<void*(void*)> _func;
    static int _num;
};
int Thread::_num = 0;

mythreadpool.hpp

#pragma once
#include<vector>
#include<queue>
#include<mutex>
#include"mythread.hpp"
#include"MutexGuard.hpp"

const int maxnum = 5;

template<class T>
class threadpool;
//上下文
template<class T>
class condate
{
public:
    condate(T* t, int num)
    :_this(t), _num(num)
    {}
    T* _this;
    int _num;
};

template<class T>
class threadpool
{
private:
    static void* task_handler(void* args)
    {
        condate<threadpool<T>>* pcondate = static_cast<condate<threadpool<T>>* >(args);
        threadpool<T>* tp = pcondate->_this;
        while(true)
        {
            T t;
            tp->pop(t);
            std::cout << tp->_threads[pcondate->_num]->name() << " : ";
            t();
        }
        delete pcondate;
    }

    threadpool(int num = maxnum)
    :_num(num)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_cond, nullptr);
        for(int i = 0; i < _num; ++i)
        {

            condate<threadpool<T>>* ct = new condate<threadpool<T>>(this, i);
            _threads.push_back(new Thread(task_handler, ct));
        }
    }

public:
    void pop(T& t)
    {
        MutexGuard mg(&_mutex);
        while(_task.empty())
            pthread_cond_wait(&_cond, &_mutex);
        t = _task.front();
        _task.pop();
    }

    void push(const T& t)
    {
        MutexGuard mg(&_mutex);
        _task.push(t);
        pthread_cond_signal(&_cond);
    }

    ~threadpool()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_cond);
        for(auto& t : _threads)
        {
            delete t;
        }
    }

    static threadpool<T>* getinstance()
    {
        if(nullptr == _singleton)
        {
            _singletonlock.lock();
            if(nullptr == _singleton)
            {
                _singleton = new threadpool();
            }
            _singletonlock.unlock();
        }
        return _singleton;
    }


private:
    int _num;
    std::vector<Thread*> _threads;
    std::queue<T> _task;
    pthread_mutex_t _mutex;
    pthread_cond_t _cond;
    static std::mutex _singletonlock;
    static threadpool<T>* _singleton;

};

template<class T>
std::mutex threadpool<T>::_singletonlock;

template<class T>
threadpool<T>* threadpool<T>::_singleton = nullptr;

tcpServer.hpp

#include<iostream>
#include<string>
#include<cstring>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include"mythreadpool.hpp"
#include"log.hpp"

#include <string.h>
#include <errno.h>

using namespace std;

namespace szg
{

    class tcp_task
    {
        public:
        tcp_task(int sock = 0)
        :_sock(sock)
        {}

        void operator()()
        {
            char rdbuf[1024];
            while (true)
            {
                size_t n = read(_sock, rdbuf, sizeof(rdbuf) - 1);
                if(n == 0)
                {
                    cout << "client offline,  me too" << endl;
                    break;
                }
                rdbuf[n] = 0;
                
                write(_sock, rdbuf, strlen(rdbuf));
            }
            close(_sock);
        }

        int _sock;
    };


    string df_ip = "0.0.0.0";
    uint16_t df_port = 8080;
    class tcpServer
    {
    public:
        tcpServer(uint16_t port = df_port)
        : _port(port)
        {
            //1.创建套接字
            _listensock = socket(AF_INET, SOCK_STREAM, 0);
            if(_listensock < 0)
            {
                cerr << "服务端创建套接字失败" << endl;
                exit(-1);
            }
            cout << "服务端创建套接字成功" << endl;

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");

            logMessage(NORMAL, "accept a new link success, get new sock: %d", _listensock); // ?
            logMessage(DEBUG, "accept error, next");
            logMessage(WARNING, "accept error, next");
            logMessage(FATAL, "accept error, next");
            logMessage(NORMAL, "accept error, next");
        }

        void start()
        {
            //2.绑定套接字
            sockaddr_in server;
            memset(&server, 0, sizeof(server));
            server.sin_family = AF_INET;
            server.sin_port = htons(_port);
            server.sin_addr.s_addr = INADDR_ANY;
            if(-1 == bind(_listensock, (sockaddr*)&server, sizeof(server)))
            {
                cerr << "服务端绑定监听套接字失败" << endl;
                perror("server bind :");
                exit(1);
            }
            cout << "服务端绑定监听套接字成功" << endl;


            //3.设置套接字为监听状态
            if(listen(_listensock, 5))
            {
                cerr << "服务器监听状态设置失败" << endl;
                exit(2);
            }
            cout << "服务器监听状态设置成功" << endl;

            signal(SIGCHLD, SIG_IGN);


            
            while(true)
            {
                sockaddr_in peer;
                socklen_t len = sizeof(peer);

                //4.建立连接
                int newsock = accept(_listensock, (sockaddr*)&peer, &len);
                if(newsock < 0)
                {
                    cerr << "服务器监听客户端失败" << endl;
                }
                cout << "服务器监听客户端成功:" << newsock << endl;
                threadpool<tcp_task>::getinstance()->push(tcp_task(newsock));
                // if(0 == fork())
                // {
                //     char rdbuf[1024];
                //     while (true)
                //     {
                //         size_t n = read(newsock, rdbuf, sizeof(rdbuf) - 1);
                //         if(n == 0)
                //         {
                //             cout << "client offline,  me too" << endl;
                //             break;
                //         }
                //         rdbuf[n] = 0;
                        
                //         write(newsock, rdbuf, strlen(rdbuf));
                //     }
                //     exit(0);   
                // }
                // close(newsock);



            }
        }

    private:
        int  _listensock;
        uint16_t _port;
    };



}

日志记录文件

log.hpp

#pragma once

#include <iostream>
#include <string>
#include <cstdarg>
#include <ctime>
#include <unistd.h>

#define LOG_NORMAL "log.txt"
#define LOG_ERR "log.error"

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

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


void logMessage(int level, const char* formate, ...)
{
    char logprefix[1024];
    sprintf(logprefix, "[%s][time:%ld][pid:%d]",to_levelstr(level), (long long)time(nullptr), getpid());
    char logbackfix[1024];
    va_list arg;
    va_start(arg, formate);
    vsnprintf(logbackfix, sizeof(logbackfix) - 1, formate, arg);

    FILE *log =  fopen(LOG_NORMAL, "a");
    FILE *err = fopen(LOG_ERR, "a");
    if(log != nullptr && err != nullptr)
    {
        FILE *curr = nullptr;
        if(level == DEBUG || level == NORMAL || level == WARNING) curr = log;
        if(level == ERROR || level == FATAL) curr = err;
        if(curr) fprintf(curr, "%s%s\n", logprefix, logbackfix);

        fclose(log);
        fclose(err);
    }
}

守护进程

ctrl + z将前台引用放到后台(暂停)

jobs  查看作业

fg + 作业号(切到前台) <————> bg + 作业号(启动暂停的作业号) 

守护进程,精灵进程的本质是孤儿进程。

守护进程化

setsid: 中间新建一个会话,必须不是作业的组长才能使用

1. 让调用进程忽略掉异常的信号

2. 如何让自己不是组长,setsid且创建子进程

3. 守护进程是脱离终端的,关闭或者重定向以前进程默认打开的文件

4.更改可执行路径

#pragma once

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

#define DEV "/dev/null"

void daemonSelf(const char *currPath = nullptr)
{
    // 1. 让调用进程忽略掉异常的信号
    signal(SIGPIPE, SIG_IGN);

    // 2. 如何让自己不是组长,setsid
    if (fork() > 0)
        exit(0);
    // 子进程 -- 守护进程,精灵进程,本质就是孤儿进程的一种!
    pid_t n = setsid();
    assert(n != -1);

    // 3. 守护进程是脱离终端的,关闭或者重定向以前进程默认打开的文件
    int fd = open(DEV, O_RDWR);
    if(fd >= 0)
    {
        dup2(fd, 0);
        dup2(fd, 1);
        dup2(fd, 2);

        close(fd);
    }
    else
    {
        close(0);
        close(1);
        close(2);
    }

    // 4. 可选:进程执行路径发生更改

    if(currPath) chdir(currPath);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/23511.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2172. 最大公约数

Powered by:NEFU AB-IN Link 文章目录 2172. 最大公约数题意思路代码 2022年第十三届决赛真题 2172. 最大公约数 题意 给定一个数组, 每次操作可以选择数组中任意两个相邻的元素 x , y x, yx,y 并将其 中的一个元素替换为 gcd ⁡ ( x , y ) \operatorname{gcd}(x, y)gcd(x,y),…

117.【微信小程序】

微信小程序 (一)、微信小程序概括1.微信小程序简介(1).小程序与普通网页开发的区别 2.注册微信小程序账号(1).注册小程序账号(2).获取小程序的AppID 3.安装微信开发者工具(1).微信开发者工具的简介:(2).微信开发者工具的下载 4.创建第一个小程序(1).创建小程序步骤(2).开发者工…

新入职一个00后卷王,每天加班到2点,太让人崩溃了····

在程序员职场上&#xff0c;什么样的人最让人反感呢? 是技术不好的人吗?并不是。技术不好的同事&#xff0c;我们可以帮他。 是技术太强的人吗?也不是。技术很强的同事&#xff0c;可遇不可求&#xff0c;向他学习还来不及呢。 真正让人反感的&#xff0c;是技术平平&…

Java企业工程项目管理系统+spring cloud 系统管理+java 系统设置+二次开发

工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff1a;实现对数据字典标签的增删改查操作 2、编码管理&#xff1a;实现对系统编码的增删改查操作 3、用户管理&#xff1a;管理和查看用户角色 4、菜单管理&#xff1a;实现对系统菜单的增删改查操…

【C++】-string的介绍以及使用(迭代器的介绍和使用)

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点…

weblogic CVE-2023-21839 复现

影响版本 Weblogic 12.2.1.3.0 Weblogic 12.2.1.4.0 Weblogic 14.1.1.0.0 这里是用的docker下载的vulhub的CVE-2023-21839 靶机和攻击机都是192.168.85.131 docker 启动环境 ocker-compose up -d 然后看一下说明书 vim README.zh-cn.md 让你访问ip:7001/console 好&a…

如何利用CiteSpace快速锁定领域内最新研究热点并制作精美的可视化专题图

在科研工作中&#xff0c;我们常常需要面对海量的文献进行阅读和分析&#xff0c;如何在这些文献当中找出值得精读、细读的关键文献&#xff0c;挖掘学科前沿&#xff0c;找到研究热点就成为了开展研究之前首先需要解决的问题。CiteSpace作为一款优秀的文献计量学软件&#xff…

【Vue】二:Vue核心处理---事件处理

文章目录 1. 事件修饰符1.1 prevent1.2 stop1.3 capture - 添加事件侦听器时使用 capture 模式。1.4 self1.5 one1.6 passive 2.按键修饰符3.系统修饰符 1. 事件修饰符 1.1 prevent 当我们点击后&#xff0c;回去先执行关联的事件&#xff0c;然后再去执行默认行为&#xff0c…

本地电脑部署微力同步私人网盘,端口映射实现远程访问

文章目录 1.前言2. 微力同步网站搭建2.1 微力同步下载和安装2.2 微力同步网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 转发自CSDN远程穿透的文章&#xff1a;轻NAS搭建 - 使用微力同步搭建私人云盘&#xff0c…

spark安装

安装 su - root https://repo.anaconda.com/archive/ Anaconda3-2021.05-Linux-x86_64.sh sh ./Anaconda3-2021.05-Linux-x86_64.sh yes enter exit() exit() 重新登录 su - root 配置成功 (base) [rootnode1 ~]# python Python 3.8.8 (default, Apr 13 2021, 19:58:26) [GC…

CentOS 7安装redis

一、概述 1、redis介绍 Redis 全称 Remote Dictionary Server&#xff08;即远程字典服务&#xff09;&#xff0c;它是一个基于内存实现的键值型非关系&#xff08;NoSQL&#xff09;数据库 2、redis的特点 支持数据持久化 redis支持数据的持久化&#xff0c;可以将内存中的…

Java前缀和算法

一.什么是前缀和算法 通俗来讲&#xff0c;前缀和算法就是使用一个新数组来储存原数组中前n-1个元素的和&#xff08;如果新数组的当前元素的下标为n&#xff0c;计算当前元素的值为原数组中从0到n-1下标数组元素的和&#xff09;&#xff0c;可能这样讲起来有点抽象&#xff0…

UCIe技术——概览索引

一、Chiplet技术概述 chiplet技术顺应了芯片生产与集成技术发展的趋势&#xff0c;也开拓了半导体技术发展的新的发展方向&#xff0c;将创造出一种新的芯片设计和商业模式 1.1 芯片生产与集成技术发展的趋势 &#xff08;1&#xff09;低半径高带宽的物理连线(bandwidth / …

css定位模式

1. 为什么需要定位&#xff1f; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"…

【python资料】pandas的条件查询

一、说明 在使用Pandas的DataFrame进行数据挖掘的时候&#xff0c;需要形形色色的条件查询&#xff0c;但是这些查询的基本语法是啥&#xff0c;查询的灵活性如何&#xff0c;本文将对他们进行详细列出&#xff0c;便于以后查阅。 二、Pandas条件查询方法 2.1 简单条件查询 1、…

单视觉L2市场「鲶鱼」来了,掀起数据反哺高阶新打法

作者 | 张祥威编辑 | 德新 智驾方案的降本行动仍在推进。 早年&#xff0c;单视觉L2市场的玩家以Mobileye、博世为主&#xff0c;后来国内智驾公司加入&#xff0c;共同推动 1V、1R1V、nR1V等不同的方案兴起&#xff0c;L2近乎成为车辆的必备功能。 当下&#xff0c;在行业降低…

SpringBoot启动扩展应用:干预优化+加快启动时间

目录 一、SpringBoot启动配置原理简述 二、SpringBoot启动过程干预 &#xff08;一&#xff09;ApplicationContextInitializer扩展 修改Spring Boot默认的environment属性 添加自定义的PropertySource 注册自定义bean &#xff08;二&#xff09;SpringApplicationRunL…

Vue绑定class样式与style样式

1&#xff0c;回顾HTML的class属性 答&#xff1a;任何一个HTML标签都能够具有class属性&#xff0c;这个属性可能只有一个值&#xff0c;如class"happs"&#xff0c;也有可能存在多个属性值&#xff0c;如class"happs good blue"&#xff0c;js的原生DOM针…

KDZK-F水轮发电机转子测试仪

一、产品概述 KDZK-F水轮发电机转子测试仪是判断发电机转子绕组有无匝间短路的专用仪器&#xff0c;可以自动、手动&#xff08;单向或双向&#xff09;测量转子绕组的电压、电流、阻抗、功率、相位角等参数。 二、功能与特点 旋转鼠标&#xff0c;操作更方便。 可选择快速的…

【014】C++数组之一维字符数组和二维字符数组

C数组之一维字符数组和二维字符数组 引言一、一维字符数组1.1、一维字符数组的初始化1.2、字符数组的遍历1.3、从键盘获取字符串1.4、使用示例 二、二维字符数组2.1、定义2.2、初始化2.3、访问 总结 引言 &#x1f4a1; 作者简介&#xff1a;专注于C/C高性能程序设计和开发&…
最新文章