Tcp协议讲解与守护进程

TCP协议:面向链接,面向字节流,可靠通信

创建tcp_server

1.创建套接字


域:依旧选择AF_INET
连接方式:  


选择SOCK_STREAM 可靠的

2.bind

3.监听装置    
  
      


client要通信,要先建立连接,client主动建立连接,所以服务端要一直等待连接


4.获取连接
  


成功返回新的sockfd,失败返回-1


  
我们在使用UDP时,我们的sockfd一直都是同一个,但是在TCP这里我们收到了一个新的sockfd,那我们客户端服务端通信的时候是用哪一个socket呢?
一个故事:有一家饭店,有一个叫张三的员工在外面拉客,拉到客后就进入餐馆叫服务员A给顾客A提供服务,所以顾客A的所有要求都由服务员A提供。
所以我们在通信时用的是返回的新的socket,我们创建的socket理论上叫Listensocket
如果失败了,返回-1,我们得让循环退出吗?
不,我们的continue让socket持续监听

提供服务
调用read write进行读写
read如果读到了0,表示读到了文件结尾,表明(对端关闭了连接)

#pragma once
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>

#include <unistd.h>
#include <errno.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include "Log.hpp"
#include "Comm.hpp"
using namespace std;
const int defaultblacklog = 5;
class TcpServer
{
public:
    TcpServer(const uint16_t &port) : _port(port)
    {
    }
    void Server(int sockfd)
    {
        while (true)
        {
            char buff[1024];
            int n = read(sockfd, buff, sizeof(buff) - 1);
            if (n > 0)
            {
                //读取成功
                buff[n]=0;
                lg.LogMessage(Info,"read success");
                cout<<"#Client say:"<<buff<<endl;

                // string sendbuff;
                // cout<<"#Please Enter"<<endl;
                // getline(cin,sendbuff);
                // int m=write(sockfd,sendbuff.c_str(),sizeof(sendbuff));
                // if(m<0)
                // {
                //     lg.LogMessage(Fatal,"write failed errno:%d :%s",errno,strerror(errno));
                // }
                // lg.LogMessage(Info,"Write success.......");
            }
            else if(n==0)
            {
                break;
                lg.LogMessage(Info,"Client quit.......");
            }
            else
            {
                lg.LogMessage(Fatal,"read failed errno:%d :%s",errno,strerror(errno));
            }
        }
    }
    void Init()
    {
        // 创建套接字
        _listensocket = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensocket < 0)
        {
            lg.LogMessage(Fatal, "create socket failed errno %d:%s\n", errno, strerror(errno));
        }
        lg.LogMessage(Debug, "create socket success _socket:%d\n", _listensocket);
        // bind

        struct sockaddr_in addr;
        bzero(&addr,sizeof(addr));
        addr.sin_family = AF_INET;
        addr.sin_port = _port;
        addr.sin_addr.s_addr = INADDR_ANY;

        int n = bind(_listensocket, CONV(&addr), sizeof(addr));
        if (n < 0)
        {
            lg.LogMessage(Fatal, "create socket failed errno %d:%s\n", errno, strerror(errno));
        }
        lg.LogMessage(Debug, "bind socket success _socket:%d\n", _listensocket);
        // 监听装置
        int m = listen(_listensocket, defaultblacklog);
        if (m < 0)
        {
            lg.LogMessage(Fatal, "listen  failed errno %d:%s\n", errno, strerror(errno));
        }
        lg.LogMessage(Debug, "listen success _socket:%d\n", _listensocket);
    }
    void Start()
    {
        // 获取连接
        while (true)
        {
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            int wrsockfd = accept(_listensocket, CONV(&peer), &peerlen);
            if (wrsockfd > 0)
            {
                // 获取连接成功  提供服务
                Server(wrsockfd);
            }
            else
            {
                // 获取连接失败 但是一直获取
                continue;
            }
            // 提供服务
            close(wrsockfd);
        }
    }

    ~TcpServer()
    {
    }

private:
    uint16_t _port;
    int _listensocket;
};

netstat -nltp 查看服务器
  


客户端


1.创建套接字 (同sever端)


2.建立连接 连接后自动进行bind


  
inet_pton:更安全
  

#include <iostream>
#include <cstring>

#include <sys/types.h>
#include <sys/socket.h>

#include <unistd.h>
#include <errno.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include "Log.hpp"
#include "Comm.hpp"
using namespace std;
void Usage(std::string proc)
{
    std::cout << "Usage : \n\t" << proc << "server_ip server_port\n"
              << std::endl;
}
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        cerr << "Usage error" << endl;
        exit(Usage_Err);
    }

    // 创建套接字
    int _socket = socket(AF_INET, SOCK_STREAM, 0);
    if (_socket < 0)
    {
        lg.LogMessage(Fatal, "create socket failed errno %d:%s\n", errno, strerror(errno));
    }
    lg.LogMessage(Debug, "create socket success _socket:%d\n", _socket);
    // 建立连接

    string serverip=argv[1];
    uint16_t serverport=stoi(argv[2]);
    struct sockaddr_in serveraddr;
    bzero(&serveraddr,sizeof(serveraddr));
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=serverport;
    if(inet_pton(AF_INET,(serverip.c_str()),&serveraddr.sin_addr));

    int n=connect(_socket,CONV(&serveraddr),sizeof(serveraddr));
    if(n<0)
    {
        lg.LogMessage(Fatal, "connect failed errno %d:%s\n", errno, strerror(errno));
    }
    lg.LogMessage(Debug, "connect success _socket:%d\n", _socket);

    // 输入信息
    while(true)
    {
        string buff;
        cout<<"Please Enter:"<<endl;
        getline(cin,buff);
        int n=write(_socket,buff.c_str(),sizeof(buff));
    }
}


  
main,cc

#include "TcpServer.hpp"
#include "Comm.hpp"
#include "Daemon.hpp"
void Usage(std::string proc)
{
    std::cout << "Usage : \n\t" << proc << "local_port\n" << std::endl;
}
int main(int argc,char* argv[])
{
    if(argc!=2)
    {
        Usage(argv[0]);
        cerr<<"Usage error"<<endl;
        exit(Usage_Err);
    }
    
    uint16_t port=stoi(argv[1]);
    TcpServer *tcps=new TcpServer(port);
    tcps->Init();
    tcps->Start();
    Daemon(true,false);
    lg.Enable(ClassFile);
}

udp面向数据报和tcp面向字节流有什么区别?
数据报:数据和数据是有边界的    sendto一次对应着recv一次
字节流:write 一次十次一百次,read可能一次就读完,也可能几十次,但是read端与write端无关
我们编写IO代码,尤其是网络IO时,我们的read和write是有BUG的

我们的服务器得以后台进程的方式运行,真正的服务,是以后台进程以守护进程(精灵进程)的方式运行

守护进程


进程组ID 会话ID
  


同时启动的进程可以是一个进程组的,进程组id通常是其中的某一个进程的pid
  

每次我们登入linux->OS默认提供1.bash2.提供一个终端->给用户提供命令解释的服务->叫做一个会话组
在一个命令行启动的所有进程,最终都是这个会话内的一个进程组。

会话内的进程组,任何时候,一个会话内部存在很多个进程组,但是默认法人和时刻只允许一个进程组在前台(前台进程组)。

前台进程:可以接受IO的是前台进程、

jobs查看
  
fg task_number 前台
  
ctrl+Z bg task_number 后台  或者进程+&
  

守护进程自己是一个独立的会话,他不属于任何的bash会话。
谁启动setsid,谁就是会话的所属进程。
  
调用setsid的进程不能是组长,启动多个进程时,第一个启动进程就是组长,启动一个进程时,这个进程就是组长
  
所以我们一般要创建子进程,让父进程直接退出,所以守护进程一般都是孤儿进程

创建守护进程


1.忽略可能引起异常退出的信号
例如SIG_CHLD SIG_PIPE


2.让父进程退出


3.让自己成为一个新的会话setsid


4.将进程的CWD更改为/根目录     提高效率
chdir


5.独立的会话组,也就是说没有bash进程了,所以可以将所有文件dup(nullfd,1/0/2)
/dev/null 

tips:1.命名守护进程我们都以d结尾
       2.kill -9
ls /proc/pid -l

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

using namespace std;

const char *rootdic = "/";
const char *nulldic = "/dev/null";
void Daemon(bool isroot, bool isclose)
{
    // 忽略可能引起异常的型号
    signal(SIGCHLD, SIG_IGN);
    signal(SIGPIPE, SIG_IGN);

    // 守护进程不能是组长,所以得创建孤儿进程
    pid_t id = fork();
    if (id != 0)
        exit(0);

    // 创建一个新的会话
    setsid();

    // 根目录
    if (isroot)
    {
        chdir(rootdic);
    }

    if (isclose)
    {
        close(0);
        close(1);
        close(2);
    }
    else
    {
        int nullfd = open(nulldic, O_WRONLY);
        if (nullfd > 0)
        {
            dup2(nullfd, 0);
            dup2(nullfd, 1);
            dup2(nullfd, 2);
            close(nullfd);
        }
    }
}

系统有没有将进程守护化的方法?
daemon
  
将服务器守护化,但企业一般都自己会实现进程守护化

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

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

相关文章

Allegro怎么批量将弧形线改成45度角的线?

Allegro如何将弧形线改成45度角的线? 在用Allegro进行PCB设计时,有时候需要将弧形线改为45度角的线。 具体操作方法如下: 1、选择菜单栏Route 选择Unsupported Prototypes(不支持的原型)→AICC 2、在Options选项卡选择45度 3、在Find选项卡选择Nets,选择网络可以批量转换…

浮动练习(3)

##每台电脑分辨率不同&#xff0c;数值高度宽度需要自己调&#xff0c;仅供参考 <!DOCTYPE html> <html> <head> <meta charset"UTF-8"> <title></title> <style> div{ …

JMeter详细介绍和相关概念

JMeter是一款开源的、强大的、用于进行性能测试和功能测试的Java应用程序。 本篇承接上一篇 JMeter快速入门示例 &#xff0c; 对该篇中出现的相关概念进行详细介绍。 JMeter测试计划 测试计划名称和注释&#xff1a;整个测试脚本保存的名称&#xff0c;以及对该测试计划的注…

《使用Gin框架构建分布式应用》阅读笔记:p108-p126

《用Gin框架构建分布式应用》学习第8天&#xff0c;p108-p126总结&#xff0c;总计18页。 一、技术总结 1.Redis eviction policy (1)什么是 eviction policy? The eviction policy determines what happens when a database reaches its memory limit. (2)配置示例 在r…

Dockerfile样例

一、基础jar镜像制作 ## Dockerfile FROM registry.openanolis.cn/openanolis/anolisos:8.9 RUN mkdir /work ADD jdk17.tar.gz fonts.tar.gz /work/ RUN yum install fontconfig ttmkfdir -y && yum clean all && \chmod -R 755 /work/fonts ADD fonts.conf …

docker配置mysql8报错 ERROR 2002 (HY000)

通过docker启动的mysql&#xff0c;发现navicat无法连接&#xff0c;后来进入容器内部也是无法连接&#xff0c;产生以下错误 root9f3b90339a14:/var/run/mysqld# mysql -u root -p Enter password: ERROR 2002 (HY000): Cant connect to local MySQL server through socket …

二叉树中的最长交错路径

题目链接 二叉树中的最长交错路径 题目描述 注意点 每棵树最多有 50000 个节点每个节点的值在 [1, 100] 之间起点无需是根节点 解答思路 要找到最长交错路径&#xff0c;首先想到的是深度优先遍历因为起点无需是根节点&#xff0c;所以对于任意一个节点&#xff0c;其可以…

4个在线音频剪辑工具,让你的声音更加动听。

最近我开始接触音乐剪辑&#xff0c;想把一些歌曲进行剪辑创作&#xff1b;于是在网上好多了很多的音频剪辑软件进行试用&#xff0c;一番下来&#xff0c;发现了4款使用起来体验感比较好的专业剪辑工具&#xff0c;在这里跟大家分享分享。这些工具都可以被应用于歌曲创作&…

Linux系统基础-进程间通信(3)_模拟实现匿名管道

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Linux系统基础-进程间通信(3)_模拟实现匿名和命名管道 收录于专栏[Linux学习] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&a…

【优先算法】--双指针1

“一念既出&#xff0c;万山无阻。”加油陌生人&#xff01; 目录 1.双指针--移动零 2.双指针-复写零 ok&#xff0c;首先在学习之前&#xff0c;为了方便大家后面的学习&#xff0c;我们这里需要补充一个知识点&#xff0c;我这里所谓的指针&#xff0c;不是之前学习的带有…

dolphinscheduler创建工作流及工作流中DataX的使用(简单操作)

一、在项目管理中创建项目&#xff1a;点击创建项目 用哪个用户登录的&#xff0c;所属用户就是哪个&#xff0c;直接输入项目名即可 二、点击项目&#xff0c;在项目中创建工作流&#xff0c;用DataX同步数据 按照图片的步骤依次填写完成&#xff0c;注意 图片中的第九步是写…

2024年双十一腾讯阿里云香港服务器优惠活动汇总

2024年双11狂欢节终于来了&#xff0c;按照往年的惯例&#xff0c;各大云服务器厂商通常会在10月20号左右开始上线新的活动&#xff0c;今年双11期间国内各大云服务器厂商都有哪些活动呢&#xff1f;有哪些活动包括香港云服务器呢&#xff1f;是否有海外服务器的优惠折扣呢&…

HelpLook联合MarketUP发布《2024企业内容营销实战》白皮书!(内附下载链接)

B2B内容营销为什么值得反复讲&#xff1f; 这是一个技术创新、客户聚焦、回归内容的B2B时代&#xff0c;B2B市场源源不断地诞生新故事&#xff0c;从短视频到AIGC&#xff0c;从新产品到新技术&#xff0c;内容始终是所有B2B活动的核心&#xff0c;需要更新更深的内容营销塑造…

Xmind一款极简思维导图和头脑风暴软件,支持PC和移动端,Xmind 2024.10.01101版本如何升级到Pro版?简单操作,最新可用!

文章目录 Xmind下载安装Xmind免费升级到Pro Xmind 是一款全功能的思维导图和头脑风暴软件&#xff0c;不限制节点和文件数&#xff0c;创新无限&#xff0c;界面纯净简洁无广告&#xff0c;支持PC和移动端&#xff0c;思维导图和大纲视图自由切换&#xff0c;可本地化文档存储&…

新版idea菜单栏展开与合并

新版idea把菜单栏合并了看着很是不习惯&#xff0c;找了半天原来在这里展开 ① 点击文件 -> 设置 ② 点击外观与行为 -> 外观 -> 合并主菜单和窗口标题 然后确定&#xff0c;重启即可

【LeetCode每日一题】——523.连续的子数组和

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 前缀和 二【题目难度】 中等 三【题目编号】 523.连续的子数组和 四【题目描述】 给你一个…

【不要离开你的舒适圈】:猛兽才希望你落单,亲人总让你回家,4个维度全面构建舒适圈矩阵

单打独斗的英雄时代已经落幕 抱团取暖才是社会寒冬的良策 自然界中&#xff0c;每个物种都占据着自己的领地和生存空间。 生态位的差异决定了它们的生存方式&#xff0c;一旦离开领地&#xff0c;失去群体的庇护&#xff0c;就会沦为野兽的美餐。 人类社会同样存在隐形圈层…

Nginx16-Lua扩展案例

零、文章目录 Nginx16-Lua扩展案例 1、ngx_lua案例 &#xff08;1&#xff09;需求 请求地址&#xff1a;http://192.168.119.161/getByGender?name张三&gender1Nginx接收到请求后&#xff0c;根据gender传入的值 如果gender传入的是1&#xff0c;则在页面上展示张三先…

初阶数据结构【3】--单链表(比顺序表还好的一种数据结构!!!)

本章概述 前情回顾单链表实现单链表彩蛋时刻&#xff01;&#xff01;&#xff01; 前情回顾 咱们在上一章博客点击&#xff1a;《顺序表》的末尾&#xff0c;提出了一个问题&#xff0c;讲出了顺序表的缺点——有点浪费空间。所以&#xff0c;为了解决这个问题&#xff0c;我…

Java项目-基于springboot框架的线上买菜系统项目实战(附源码+文档)

作者&#xff1a;计算机学长阿伟 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、ElementUI等&#xff0c;“文末源码”。 开发运行环境 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBoot、Vue、Mybaits Plus、ELementUI工具&#xff1a;IDEA/…