【网络编程】详解UDP/TCP套接字的创建流程+守护进程

news2024/11/28 20:45:48


目录

一、网络编程套接字

1、一些概念

1.1源IP地址和目的IP地址

1.2端口号port

1.3TCP和UDP的性质

1.4网络字节序、IP地址类型转换、数据接收与发送函数、popen函数

2、UDP套接字

2.1UDP服务器创建流程

2.2UDP客户端创建流程

2.3创建socket套接字

2.4绑定套接字对应的IP地址、端口号

2.5客户端、服务器数据的接收与发送

3、TCP套接字

3.1TCP服务器创建流程

3.2TCP客户端创建流程

3.3创建socket套接字

3.4绑定套接字对应的IP地址、端口号

3.5服务器设置socket为监听状态

3.6服务器获取客户端连接请求

3.7客户端发起连接请求

二、守护进程

1、守护进程的概念

2、守护进程接口

3、手搓守护进程实现代码


UDP/TCP客户端、服务器代码可参考本人gitee

一、网络编程套接字

1、一些概念

1.1源IP地址和目的IP地址

源IP地址:发送主机的IP地址。

目的IP地址:接收主机的IP地址。

1.2端口号port

端口号是传输层的协议的内容。

1、端口号是一个2字节的整数;

2、端口号用于告诉操作系统,当前这个数据要交给哪一个进程处理;

3、IPA+portA就能标定发送的主机中的进程,IPB+portB就能标定接收数据的主机中的进程,实现进程间通信。(IP+port就是套接字

4、一个端口号只能绑定一个进程,一个进程可以绑定多个端口号。

        既然网络通信的双方本质都是进程,为什么不直接使用pid来标定网络通信双方通信进程的唯一性,而是使用端口号呢?1、解耦2、例如客户端需要找到服务器进程,因为进程每次创建销毁pid是会变的,而网络编程弄了个端口号,直接写死了是哪个进程,这样每次都能找到。

        那么怎么找呢?操作系统内部维护了一张哈希表,key是端口号,value是进程PCB的地址。

1.3TCP和UDP的性质

UDP:

传输层协议、无连接、不可靠传输、面向数据报

TCP:

传输层协议、有连接、可靠传输、面向字节流

1.4网络字节序、IP地址类型转换、数据接收与发送函数、popen函数

1、TCP/IP协议规定,网络数据流应采用大端字节序,即低地址存高字节,不管这台主机是大端机还是小端机

2、如果当前发送主机是小端, 就需要先将数据转成大端; 反之直接发送即可(不管本机是大端还是小端,最好都转换一下,便于日后跨平台、跨主机的需要)

3、发送主机和接收主机都是按照低地址到高地址发送/接收数据;

可以使用以下库函数做网络字节序和主机字节序的转换:

BYTEORDER(3)
#include <arpa/inet.h>
uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);

例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。

可以使用以下库函数对ip地址进行转换:

INET(3) 
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
int inet_aton(const char *cp, struct in_addr *inp);
in_addr_t inet_addr(const char *cp);//将字符串转uint32_t的同时转为网络字节序
in_addr_t inet_network(const char *cp);
char *inet_ntoa(struct in_addr in);//将32位IPv4地址(in_addr结构体)转换成点分十进制字符串形式的IP地址
struct in_addr inet_makeaddr(int net, int host);
in_addr_t inet_lnaof(struct in_addr in);
in_addr_t inet_netof(struct in_addr in);

popen函数==pipe+fork+exec*

POPEN(3)    
#include <stdio.h>
FILE *popen(const char *command, const char *type);
int pclose(FILE *stream);

用途:函数popen()用于打开一个用于读取或写入的管道,以便与另一个进程进行通信。

参数:

  • command:要执行的命令
  • type:打开管道的模式,可以是“r”(读)或“w”(写)。

返回值:返回一个指向FILE结构的指针,可以像使用普通文件一样使用它来读取或写入管道。如果打开管道失败,返回NULL

2、UDP套接字 

UDP套接字种类及接口

1、网络套接字2、原始套接字3、unix域间套接字

2.1UDP服务器创建流程

1、创建套接字(sockrt)

2、绑定端口号和IP地址。这个端口号是写死的,这个IP地址0.0.0.0或htonl(INADDR_ANY)两种写法(bind)

3、发送、接收数据,对数据进行处理(recvfrom/sendto)

2.2UDP客户端创建流程

1、创建套接字(sockrt)

2、客户端需要bind,但是客户端的绑定不需要我们自己写,操作系统会去绑定;(无需程序员bind)

3、发送、接收数据,对数据进行处理(recvfrom/sendto)

相关指令及函数:

ifconfig 显示网络设备信息,找到127.0.0.1本地回环地址
ps axj | grep udpServer过滤出当前的udpServer进程
netstat -nuap//n:能显示数字的现实成数字;u:udp;a:all;p:进程
sudo netstat -nuap//n:以数字形式显示地址和端口号,不进行反向解析,a:all,u::udp,p:process ID/name,
sudo netstat -altp//l::listen,t:tcp
recvfrom
sendto
close
bzero

2.3创建socket套接字

SOCKET(2)      
#include <sys/types.h> 
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

用途:创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

参数:

  • domain:指定套接字的协议族。常见的协议族有AF_INET(IPv4网络通信)、AF_UNIX/AF_LOCAL(本地通信)
  • type:指定套接字的类型。常见的类型有SOCK_STREAM(流套接字)和SOCK_DGRAM(数据报套接字)。
  • protocol:给0就行。【指定套接字使用的协议。常见的协议有IPPROTO_TCP(TCP协议)和IPPROTO_UDP(UDP协议)】

调用成功返回值:返回一个文件描述符;

调用失败返回值:返回-1,设置error变量以指示原因。

2.4绑定套接字对应的IP地址、端口号

BIND(2)        
#include <sys/types.h>       
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

用途:将一个套接字(socket)与一个特定的IP地址和端口号绑定

参数:

  • sockfd:套接字描述符,即要绑定的套接字。
  • addr:一个指向 sockaddr 结构体的指针,该结构体包含了IP地址和端口号等信息。
  • addrlen:sockaddr 结构体的大小

返回值:返回值为0,则表示函数执行成功;否则,返回值为-1,表示函数执行失败。在函数执行失败时,可以通过 errno 全局变量获取错误码,以便进行错误处理。

2.5客户端、服务器数据的接收与发送

UDP 套接字是无连接协议,必须使用recvfrom函数接收数据,sendto函数发送数据:

RECV(2)
#include <sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
                struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);

用途:从已连接的socket中接收数据,并将数据存储到指定的缓冲区中。

参数:

  • sockfd:已经建立好连接的socket。
  • buf:指向接收数据存放的缓冲区。
  • len:缓冲区长度。
  • flags:一般为0,阻塞式读取。
  • src_addr:(输出参数)返回发送方的地址信息。
  • addrlen:(输出参数)地址信息的长度。

调用成功返回值:函数成功接收到数据时,它会返回接收到的字节数

调用失败返回值:发生错误,则返回-1,并设置errno变量以指示错误类型。

SEND(2)      
#include <sys/types.h>
#include <sys/socket.h>
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
          	const struct sockaddr *dest_addr, socklen_t addrlen);
ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);

用途:该函数用于将数据报发送到指定的目的地。

参数:

  • sockfd:表示要发送数据的套接字文件描述符。
  • buf:指向要发送的数据缓冲区。
  • len:表示要发送的数据长度。
  • flags:表示发送数据的选项,常用的选项有MSG_DONTWAIT和MSG_NOSIGNAL。
  • dest_addr:(输入参数)指向目的地址的结构体指针,表示要发给谁。
  • addrlen:(输入参数)表示目的地址结构体的长度。

返回值:成功发送的字节数,如果返回值为-1,则表示发送失败,具体错误码可以通过errno变量获取。

3、TCP套接字

3.1TCP服务器创建流程

1、创建监听套接字(socket)

2、绑定端口号和IP地址。这个端口号是写死的,这个IP地址0.0.0.0或htonl(INADDR_ANY)两种写法(bind)

3、服务器设置socket为监听状态(listen)

4、服务器获取客户端连接请求(accept)

5、文件操作进行读写通信(read/write)

3.2TCP客户端创建流程

1、创建套接字(socket)

2、客户端需要bind,但是客户端的绑定不需要我们自己写,操作系统会去绑定;(无需程序员bind)

3、客户端发起连接请求(connect)

4、文件操作进行读写通信(read/write)

3.3创建socket套接字

同UDP创建套接字的方法,只不过在传参时UDP传入SOCK_DGRAM(数据报),而TCP传入SOCK_STREAM(字节流)

_sockfd=socket(AF_INET,SOCK_DGRAM,0);//UDP网络通信+数据报
_listenfd=socket(AF_INET,SOCK_STREAM,0);//TCP网络通信+字节流

3.4绑定套接字对应的IP地址、端口号

同UDP。

3.5服务器设置socket为监听状态

因为TCP是有连接的协议,需要使用listen函数将一个套接字设置为监听状态。

LISTEN(2)   
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int listen(int sockfd, int backlog);

用途: listen函数用于将一个套接字(socket)设置为监听模式,以便接受客户端的连接请求。

参数:

  • sockfd:需要设置为监听模式的套接字描述符
  • backlog:指定等待连接队列的最大长度,即同时能够处理的客户端连接请求的最大数量,超过这个数量的连接请求将被拒绝

调用成功返回值:成功返回0

调用失败返回值:失败返回-1,并设置errno变量以指示错误类型。

3.6服务器获取客户端连接请求

ACCEPT(2) 
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

用途:accept函数用于从处于监听状态的套接字队列中取出一个已经完成了三次握手的连接请求,并创建一个新的套接字用于与客户端进行通信。

参数:

  • sockfd:处于监听状态的套接字描述符
  • addr:指向一个sockaddr结构体的指针,用于存储客户端的地址信息
  • addrlen:addr结构体的长度,需要在调用前初始化为sizeof(struct sockaddr)

调用成功返回值:返回一个新的套接字描述符,用于与客户端进行通信,这个新的套接字描述符是唯一的,只能用于与这个客户端进行通信。

调用失败返回值:失败返回-1,并设置errno变量以指示错误类型。

3.7客户端发起连接请求

CONNECT(2)   
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

用途:connect函数用于客户端与服务器建立连接,自动帮客户端的套接字与其ip、port进行绑定。

参数:

  • sockfd:需要连接的套接字描述符。
  • addr:指向目标地址的指针,包括目标计算机的IP地址和端口号。
  • addrlen:addr结构体的长度,需要在调用前初始化为sizeof(struct sockaddr)

调用成功返回值:返回0

调用失败返回值:失败返回-1,并设置errno变量以指示错误类型。

二、守护进程

1、守护进程的概念

        守护进程也称精灵进程,本质上是一个孤儿进程。

        一个会话只有一个前台程序和n个后台程序,作业之间可以前后台转换。这样的任务可能会收到用户登录和注销而被清理。

        如果想让服务端不受用户登录注销的影响,就必须让服务端自成会话,自成进程组,使其与终端设备的状态无关,可以一直运行的进程。这样的进程就被称为守护进程。

2、守护进程接口

手搓用setsid

SETSID(2)      
#include <unistd.h>
pid_t setsid(void);

用途:使用setsid可以使调用进程成为一个新的会话领导者,并且不会受到终端的控制。这对于守护进程和后台进程非常有用,因为它们需要在后台运行,并且不希望受到终端的影响。调用setsid后,调用进程的进程组ID将变为新会话的组ID,该进程成为新会话的领导进程,并且不再有控制终端。进程组的组长不能调用setsid()函数来创建一个新的会话

参数:无

调用成功返回值:返回新会话的会话ID

调用失败返回值:失败返回-1

 当然Linux自带生成守护进程的接口:

DAEMON(3)  
#include <unistd.h>
int daemon(int nochdir, int noclose);

 用途:该函数的意义在于将进程转变为守护进程,守护进程是在后台运行的进程,通常不与控制台交互,而是在后台执行某些任务,如网络服务器等。通过调用该函数,可以实现以下功能:

  • 将当前进程的父进程置为init进程(进程id为1),从而脱离原有的进程组和会话。
  • 将当前进程的工作目录切换到根目录下,以避免守护进程因为当前工作目录被卸载等原因导致崩溃。
  • 关闭标准输入、输出和错误输出,以避免守护进程输出信息到控制台,从而影响用户体验。

参数:

  • nochdir:是否改变当前工作目录。如果为0,则将当前工作目录切换到根目录下,否则保持不变。
  • noclose:是否关闭标准输入、标准输出、标准错误的文件描述符。如果为0,则不关闭,否则关闭。

调用成功返回值:返回0

调用失败返回值:失败返回-1,并设置errno变量。

3、手搓守护进程实现代码 

#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"//数据黑洞,向它写入的数据会被吃掉,读取数据什么都读不到(不会使进程退出)
void DaemonSele(const char* currrPath=nullptr)
{
    //1、让调用进程屏蔽异常的信号
    //SIGPIPE信号会在进程向一个已经关闭的socket连接写数据时产生,如果不处理这个信号,进程会被强制退出。通过忽略SIGPIPE信号,可以避免进程因为这个信号而退出。
    signal(SIGPIPE,SIG_IGN);
    //2、让自己不是组长,调用setsid
    if(fork()>0) exit(0);//守护进程也称精灵进程,本质就是一个孤儿进程
    pid_t n=setsid();
    assert(n!=-1);//失败返回-1
    //3、守护进程脱离终端,所以要关闭或重定向进程默认打开的文件及文件描述符
    int fd=open(DEV,O_RDWR);//以读写的方式打开文件黑洞
    if(fd>=0)//创建成功:重定向
    {
        dup2(fd,0);//将fd覆盖标准输入
        dup2(fd,1);
        dup2(fd,2);
        close(fd);
    }
    else//创建失败:手动关闭文件描述符
    {
        close(0);
        close(1);
        close(2);
    }
    //4、进程执行路径更改(可改可不改)
    if(currrPath)
    {
        chdir(currrPath);
    }
}

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

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

相关文章

模仿抖音直播商城带货打赏功能做一个app系统

随着人们生活和互联网的高度整合&#xff0c;越来越多的人开始转变自身消费模式&#xff0c;从实体店购物逐渐转向足不出户即可享受购物快感的网上购物。许多企业看到了电子商务背后隐藏的巨大价值&#xff0c;想要寻找合适的开发商建立属于自己的电商直播系统&#xff0c;那么…

【新星计划·2023】网工知识——OSPF讲解

OSPF ( Open Shortest Path First开放式最短路径优先)是一种动态路由协议&#xff0c;属于内部网关协议( Interior Gateway Protocol&#xff0c;简称IGP )&#xff0c;是基于链路状态算法的路由协议。 一、OSPF是什么&#xff1f; OSPF意思是指一个内部网关协议(Interior Ga…

阿里云短信验证接口调用

需要的maven依赖 <!-- 升级版 SDK这是一个短信 --> <dependency> <groupId>com.aliyun</groupId> <artifactId>dysmsapi20170525</artifactId> <version>2.0.23</version> </dependency> package com.service.thereServ…

融合改进Sine混沌映射的新型粒子群优化算法(NIPSO)-附代码

融合改进Sine混沌映射的新型粒子群优化算法(NIPSO) 文章目录 融合改进Sine混沌映射的新型粒子群优化算法(NIPSO)1.粒子群优化算法2. 改进粒子群优化算法2.1 改进的 Sine 混沌映射2.2 粒子群改进 3.实验结果4.参考文献5.Matlab代码6.Python代码 摘要&#xff1a;为了应对传统粒子…

vscode remote server tunnel内网穿透转发tcp,速率10kb每秒

参考: vscode网页版的正确打开方式(建立tunnel-p2p连接)_vscode打开网页_怪力左手的博客-CSDN博客 在vps(ubuntu20.04 可出网,无公网ip)上输入如下命令: 需要chisel这个工具,通过websocket转发tcp连接和启动socks5代理, cd /tmp; curl -L -O https://github.com/jpillora/c…

C++异步调用方法

C之future和promise future和promise的作用是在不同线程之间传递数据。使用指针也可以完成数据的传递&#xff0c;但是指针非常危险&#xff0c;因为互斥量不能阻止指针的访问&#xff1b;而且指针的方式传递的数据是固定的&#xff0c;如果更改数据类型&#xff0c;那么还需要…

基于SpringBoot+Vue的搬家服务系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 当今社会&#xff0c;…

实践指南-前端性能提升 270%

目录 一、背景 二、优化前 1. 了解测量工具及性能指标 1.1 Performance 1.2 最佳实践 1.3 SEO 2. 分析需要优化的地方 2.1 Performance 2.2 最佳实践 2.3 SEO 三、优化 Performance 1. 体积优化 1.1 代码压缩 1.2 代码分包 1.3 组件按需加载 1.4 工具库按需加载…

基于SpringBoot+Vue的超市货物管理系统

✌全网粉丝20W,csdn特邀作者、博客专家、CSDN新星计划导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取项目下载方式&#x1f345; 一、项目背景介绍&#xff1a; 在1990年代初期&#…

ELK【elasticsearch+logstash+kibana】企业级日志分析系统

文章目录 一、ELK概述1. ELK简介2.ElasticSearch3. Logstash4.Kiabana5.Filebeat6.为什么要用ELK&#xff08;思考一下&#xff09;7.ELK的工作原理 二、ELK实验&#xff08;部署ELK日志分析系统&#xff09;1.关闭防火墙2.安装 Elasticsearch-head 插件 总结 一、ELK概述 1. …

第六章 Matlab的复数数据、字符数据和附加画图类型

在第二章中,我们学习了 MATLAB 基础数据类型:double 和 char。MATLAB 还有许 多的附加数据类型,在本章,我们将会了解它们中的一个。我们要讨论的附加数据类型是 MATLAB 支持的复数数据。我们也将学习如何使用 char 数据类型,以及如何把 MATLAB 数组扩展为多维数组。 本章…

如何使用wireShark的追踪流功能抓取并还原文件

简介 WireShark的追踪流功能可以帮我们抓取从网络上下载的各种文件&#xff0c;接下来就演示下如何抓取并且进行还原。 使用Nginx搭建文件存储服务器 只要是通过http网站下载的包&#xff0c;都可以通过追踪流工具进行抓取。这里为了演示&#xff0c;临时搭建一个Nginx文件存…

Redis的全局命令及相关误区

Redis中所说的数据结构是针对key-value中的value而言的。主要的结构包括String、哈希表、列表、集合等等在redis中存在16个库&#xff0c;涉及到后期的集群搭建只能使用0号库最为方便 查看所有键&#xff08;支持通配符&#xff09; keys * keys S*返回当前数据库中的键总数 …

设计原则-开闭原则

世界上没有任何一个项目是不需要迭代的&#xff0c;随着项目的发展壮大&#xff0c;会有越来越多的功能代码会被修改、添加、删除。据统计线上的生产事故90%都有由于变更引起的&#xff0c;因此为保证项目的迭代稳定性&#xff0c;我们需尽可能的遵守开闭原则。那开闭原则到底是…

Jeston Orin Nano Sdkmanager 自动化安装部署官网CUAD环境

大家好&#xff0c;我是虎哥&#xff0c;入手一块Jeston Orin nano 8G模块&#xff0c;这个模块因为是英伟达未来5年左右主推的模块&#xff0c;所以我逐步会将之前所有的应用都在这个模块环境上做适配&#xff0c;本章内容&#xff0c;我将主要围绕烧写安装系统后&#xff0c;…

R7-13 小明找前缀100000(假)

题目背景 小明最近上课天天睡觉&#xff0c;于是啥都不会。 一天&#xff0c;老师终于点兵点将点到他回答问题&#xff0c;你能帮他渡过难关吗&#xff1f; 现在老师给了小明 n 个由 0、1 构成的字符串&#xff0c;然后有 m 次询问&#xff0c; 每次询问给出一个由 0、1 构…

关于Vue3 ,看这一篇文档你就会用了

随着Vue3的到来&#xff0c;公司的新项目全部进行了升级&#xff0c;相比于Vue2&#xff0c;语法上个人觉得更简洁&#xff0c;更容易通俗易懂。首先安装vue3项目&#xff0c;这里我使用vite进行安装&#xff08;强烈推荐&#xff0c;启动速度贼快&#xff09; npm create vit…

Android 12.0状态栏居中显示时间和修改时间显示样式

1.概述 在12.0的系统rom定制化开发中,在systemui状态栏系统时间默认显示在左边和通知显示在一起,但是客户想修改显示位置,想显示在中间,所以就要修改SystemUI 的Clock.java 文件这个就是管理显示时间的,居中显示的话就得修改布局文件了 效果图如下: 在这里插入图片描述 …

算法基础学习笔记——⑩DFS与BFS\树与图

✨博主&#xff1a;命运之光 ✨专栏&#xff1a;算法基础学习 目录 DFS与BFS\树与图 ✨DFS ✨BFS &#x1f353;宽搜流程图如下&#xff1a; &#x1f353;宽搜流程&#xff1a; &#x1f353;广搜模板 ✨树与图 &#x1f353;树是特殊的图&#xff08;连通无环的图&am…

第09讲:SkyWalking Agent 启动流程剖析,领略微内核架构之美

微内核架构 SkyWalking Agent 采用了微内核架构&#xff08;Microkernel Architecture&#xff09;&#xff0c;那什么是微内核架构呢&#xff1f;微内核架构也被称为插件化架构&#xff08;Plug-in Architecture&#xff09;&#xff0c;是一种面向功能进行拆分的可扩展性架构…