tcp套接字的应用

news2024/12/23 22:12:17

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.coloradmin.cn/o/563828.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

DG4pros高楼区地籍建模项目报告

引言 据睿铂统计&#xff0c;目前约70%倾斜摄影相机都用于测量项目&#xff0c;其中绝大部分是地籍测量相关项目。例如黑龙江某客户已使用睿铂相机累计完成约1000平方公里的地籍项目。倾斜摄影技术虽然在农村地籍测量项目中应用较好&#xff0c;但却无法解决高楼区域地籍测量的…

使用 SD-WAN 实现企业级 WAN 敏捷性、简易性和性能

VMware SD-WAN 提高了敏捷性和成本效益&#xff0c;同时确保跨 WAN 的应用性能。 当今的分支机构用户正在使用更多的广域网 (WAN) 带宽&#xff0c;因为他们需要通过 Zoom、WebEx、Microsoft 365 等工具进行在线协作&#xff0c;更多地用到 “软件即服务”(SaaS) 和云计算服务…

【python资料】pandas的条件查询

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

「API接口的技术说明文档

API技术文档是指软件系统或应用程序的API接口的技术说明文档。它详细描述了API端点&#xff0c;资源&#xff0c;参数&#xff0c;请求和响应格式以及使用API的常见用例和最佳实践。 1.为什么需要API技术文档&#xff1f; API技术文档是API的唯一方法&#xff0c;以便开发人员…

分享18个好用的ChatGPT插件

上周ChatGPT又进化了&#xff0c;支持联网还有70几种第三方插件&#xff0c;不过还是老样子&#xff0c;只服务氪金玩家&#xff0c;免费端可能还得等等。之前只开放了俩插件&#xff0c;网络浏览器和代码解释器&#xff0c;只能说是真的不够用。 ChatGPT&#xff1a;不够&…

中间件(三)- Kafka(二)

Kafka 6. 高效读写&Zookeeper作用6.1 Kafka的高效读写6.2 Kafka中zookeeper的作用 7. 事务7.1 Producer事务7.2 Consumer事务 8. API生产者流程9. 通过python调用kafka9.1 安装插件9.2 生产者&#xff08;Producer&#xff09;与消费者&#xff08;Consumer&#xff09;9.3…

【实验】SegViT: Semantic Segmentation with Plain Vision Transformers

想要借鉴SegViT官方模型源码部署到本地自己代码文件中 1. 环境配置 官网要求安装mmcv-full1.4.4和mmsegmentation0.24.0 在这之前记得把mmcv和mmsegmentation原来版本卸载 pip uninstall mmcv pip uninstall mmcv-full pip uninstall mmsegmentation安装mmcv 其中&#xff…

你若在患难之日胆怯,你的力量便微小

如果你在做一件事情之前就过分放大它的困难&#xff0c;这就会逐渐降低自己去做它的动机和动力&#xff0c;还没开始你就已经削弱了自己的行动能力&#xff0c;在气势上就已经输了。 不要害怕困难&#xff0c;勇敢的去面对问题&#xff0c;解决问题&#xff0c;你就会在气势上更…

RK平台烧录固件的几种模式

在RK平台开发过程中&#xff0c;我们在使用烧录工具烧写固件的时候经常可以看到烧录工具会显示当前PC识别到的设备类型&#xff0c;一般有&#xff1a;MASKROM&#xff0c;LOADER&#xff0c;ADB&#xff0c;MSC等等。能烧录固件的模式有MASKROM模式和LOADER模式&#xff0c;下…

Python基础教程:第八章_Python文件操作

文件的编码 学习目标 掌握文件编码的概念和常见编码 思考&#xff1a;计算机只能识别&#xff1a;0和1&#xff0c;那么我们丰富的文本文件是如何被计算机识别&#xff0c;并存储在硬盘中呢&#xff1f; 答案&#xff1a;使用编码技术&#xff08;密码本&#xff09;将内…

STM32WB55_NUCLEO开发(12)----FUS 更新

概述 在 STM32WB 微控制器中&#xff0c;FUS&#xff08;Firmware Upgrade Services&#xff09;是用于固件升级的一种服务。这项服务可以让你更新设备上的无线栈固件&#xff08;如蓝牙、Zigbee或 Thread 栈&#xff09;&#xff0c;以及无线 MCU (microcontroller unit) 的系…

day5 - 利用阈值勾勒

阈值处理在计算机视觉技术中占有十分重要的位置&#xff0c;他是很多高级算法的底层逻辑之一。本实验将练习使用图像阈值处理技术来处理不同的情况的图像&#xff0c;并获得图像轮廓。 完成本期内容&#xff0c;你可以&#xff1a; 了解图像阈值处理技术的定义和作用 掌握各阈…

PyQt5 使用 pyinstaller打包文件(speed)

编写界面 import sys,math from PyQt5.QtWidgets import * from PyQt5.QtCore import Qt from PyQt5.QtGui import *class RightBottomButton(QWidget) :def __init__(self):super(RightBottomButton,self).__init__()self.setWindowTitle("界面One")self.resize(400…

1.8G专网工业路由器促进4G智能电力建设,赋能配电站远程监控管理

TD-LTE已是当下成熟的4G通信技术&#xff0c;应用无线专网的场景也越来越多&#xff0c;4G技术在电力物联网中也得到了广泛应用。依托传统的人工监管方式&#xff0c;效率低、成本高、维护难&#xff0c;为促进4G智能电力建设迫切需要方便快捷的在线监控方式来及时发现电力配网…

xss跨站,订单,shell箱子反杀记

打开一个常见的订单靶场&#xff0c;老师自己搭建的 这个是可以进行xss漏洞的测试&#xff0c;凡是有这种数据交互的地方&#xff0c;前端有一个数据的接受&#xff0c;后端是数据的显示&#xff0c;这个过程就符合漏洞产生的前提条件&#xff0c;将输入的数据进行个显示&#…

BUUCTF-Basic部分(4道)

目录 Linux Labs BUU LFI COURSE 1 BUU BRUTE 1 BUU SQL COURSE 1 Linux Labs 第一个界面&#xff0c;给出了SSH ssh 用户名&#xff1a;root 密码&#xff1a;123456 地址和端口为动态分配的 以及映射地址和端口&#xff08;这个地址端口是随机的&#xff09; node4.buuoj.c…

R语言实践——使用 rWCVP 生成自定义清单

使用 rWCVP 生成自定义清单 介绍1. 特有物种清单2. 近特有物种清单2.1 在塞拉利昂和另一地区出现的物种2.2 在塞拉利昂和相邻地区出现的物种 3. 生成自定义报告 介绍 除了允许用户从世界维管植物名录&#xff08;WCVP&#xff09;创建清单外&#xff0c;rWCVP还提供了修改清单…

在小公司“混”了2年,我只认真做了5件事,如今顺利拿到字节 Offer

前言 是的&#xff0c;我一家小公司工作了整整两年时间&#xff0c;在入职这家公司前&#xff0c;也就是两年前&#xff0c;我就开始规划了我自己的人生&#xff0c;所以在两年时间里&#xff0c;我并未懈怠。 现如今&#xff0c;我已经跳槽到了字节&#xff0c;入职字节测试…

傅里叶级数 傅里叶变换 及应用

傅里叶级数和傅立叶变换是傅里叶分析的两个主要工具&#xff0c;它们之间有密切的关系。 什么是傅里叶级数 傅里叶级数是将一个周期函数分解为一系列正弦和余弦函数的和。它适用于周期性信号&#xff0c;可以将周期函数表示为一组振幅和相位不同的谐波分量的和。傅里叶级数展…

Netty编解码机制(二)

1.Netty入站和出站机制 1.1.基本介绍 1>.netty的组件设计: Netty的主要组件有Channel、EventLoop、ChannelFuture、ChannelHandler、ChannelPipe等; 2>.ChannelHandler充当了处理入站和出站数据的应用程序逻辑的容器.例如,实现ChannelInboundHandler接口(或ChannelInb…