04--网络属性设置与多路复用

news2025/4/13 7:46:51

一、TCP可靠性分析

二、 scoket 属性设置

1、socket 属性设置表

NAME
       getsockopt, setsockopt - get and set options on sockets
                                获取 和 设置 套接字属性 
SYNOPSIS
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
       int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
       sockfd:网络描述符 
       level: 层次 👉SOL_SOCKET
       optname:属性  
       optval:可变数据,根据不同的属性类型会改变
       optlen:可变数据的大小  
       返回值: 设置/获取 成功  0   设置/获取 失败  -1

2,开启地址复用属性

// 使套接字sockfd关联的地址在套接字关闭后立即释放
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
SO_REUSEADDR:端口与地址复用属性
on = 1:开启    on = 0:关闭

3.UDP 广播属性

只有给192.168.63.255 IP发送UDP广播数据包,当前局域网的所有相同端口的主机都可以接收到数据!

// 设定套接字的广播属性为真
int on = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
SO_BROADCAST:广播属性 💡只有UDP通信协议才支持广播
on = 1:开启    on = 0:关闭

----------------------------UDP发送广播例子--------------------------
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main()
{
    // 1.创建UDP 通信对象
    int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_socket < 0)
    {
        perror("创建UDP对象失败\n");
        return -1;
    }
    else
    {
        printf("创建UDP对象成功\n");
    }

    // 开启广播功能
    int on = 1;
    int ret = setsockopt(udp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));
    if (ret != 0)
    {
        printf("开启广播失败\n");
        return -1;
    }
    else
    {
        printf("开启广播成功\n");
    }

    // 2.发送UDP数据包
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;                          // IPV4网络协议
    addr.sin_port = htons(7777);                        // 设置端口号
    addr.sin_addr.s_addr = inet_addr("192.168.63.255"); // 设置广播地址

    char buf[1024] = {"hello"};
    int size = sendto(udp_socket, buf, 5, 0, (struct sockaddr *)&addr, sizeof(addr));

    printf("发送广播数据包成功: %d\n", size);

    // 3.关闭UDP 对象
    close(udp_socket);
}

4.发送/接收缓存区属性

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main()
{
    // 1.创建UDP 通信对象
    int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_socket < 0)
    {
        perror("创建UDP对象失败\n");
        return -1;
    }
    else
    {
        printf("创建UDP对象成功\n");
    }

    // UDP发送缓存区大小:163840   UDP接收缓存区大小:163840

    // 设置发送与接收缓存区大小
    int rev_size = 2048;
    int snd_size = 4096;
    setsockopt(udp_socket, SOL_SOCKET, SO_RCVBUF, &rev_size, sizeof(rev_size)); // 获取接收缓存区大小
    setsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &snd_size, sizeof(rev_size)); // 获取发送缓存区大小

    // 获取网络发送与接收缓存区大小
    int len = sizeof(rev_size);
    getsockopt(udp_socket, SOL_SOCKET, SO_RCVBUF, &rev_size, &len); // 获取接收缓存区大小
    int len1 = sizeof(snd_size);
    getsockopt(udp_socket, SOL_SOCKET, SO_SNDBUF, &snd_size, &len1); // 获取发送缓存区大小

    printf("UDP发送缓存区大小:%d   UDP接收缓存区大小:%d\n", snd_size, rev_size);

    // 3.关闭UDP 对象
    close(udp_socket);

    //tip:设置的缓存区大小,Linux系统会自动 * 2 
}

 

5.超时属性设置

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
int main()
{
    // 1.创建UDP 通信对象
    int udp_socket = socket(AF_INET, SOCK_DGRAM, 0);
    if (udp_socket < 0)
    {
        perror("创建UDP对象失败\n");
        return -1;
    }
    else
    {
        printf("创建UDP对象成功\n");
    }

    // 设置UDP超时属性
    struct timeval val;
    val.tv_sec = 3;  // 设置3秒
    val.tv_usec = 0; // 设置0毫秒

    if (setsockopt(udp_socket, SOL_SOCKET, SO_RCVTIMEO, &val, sizeof(val)) != 0)
    {
        perror("超时属性设置失败\n");
        return -1;
    }
    else
    {
        printf("超时属性设置成功3秒\n");
    }

    // 2.发送UDP数据包
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;         // IPV4网络协议
    addr.sin_port = htons(7777);       // 设置端口号
    addr.sin_addr.s_addr = INADDR_ANY; // 设置广播地址
    while (1)
    {
        char buf[1024] = {0};
        printf("等待客户端发送数据包.....\n");
        int size = recvfrom(udp_socket, buf, 1024, 0, NULL, NULL);

        printf("size=%d\n", size);
    }

    // 3.关闭UDP 对象
    close(udp_socket);
}

二、多路复用

多路复用的作用:实现Linux多个阻塞IO接口的数据读取操作,无需多线程或多进行处理阻塞IO,提高处理效率。

1.Linux系统的阻塞IO

阻塞IO就是在读写文件描述时会产生阻塞的状态,这种文件描述符就是阻塞IO。 
1.从键盘获取数据  scanf 
2.读取管道文件    read -> pipe 
3.读取网络socket  read -> tcp_socekt/udp_socket 
4.接收客户端连接请求 accpet  
...... 

--------💡如何解决多个IO的阻塞问题-------
1.利用并发技术(多线程/多进程),每一个阻塞IO都开一个线程或者进程去读取。  ✔️

2.把IO接口设置为非阻塞状态,并轮询读取 
long state = fcntl(sockfd, F_GETFL);
state |= O_NONBLOCK;  //设置为非阻塞状态  
fcntl(sockfd, F_SETFL, state);
while(1)
{
    read(socket,); //频繁系统调用,浪费资源
    read(socket1,);
    read(socket2,);
}

3.异步信号,注册一个信号处理函数,当有数据可读时,发送信号,触发读取函数。

4.select 多路复用去监听,活跃的描述符,当一个描述符活跃时,则读取数据。  ✔️

2.多路复用的设计流程图

NAME
       select, pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplexing

SYNOPSIS
       #include <sys/select.h>
        //开启多路监听 
       int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
        nfds:监听的最大描述符 + 1 
        readfds:读集合
        writefds:写集合 
        exceptfds:可执行集合
        timeout:超时检测
        返回值: 成功  大于   0   
               超时  等于    0   
               失败  小于    0 
            
       void FD_CLR(int fd, fd_set *set);  //把一个文件描述符从监听集合删除
       int  FD_ISSET(int fd, fd_set *set);//判断一个文件描述符是否活跃 
       void FD_SET(int fd, fd_set *set);  //把一个文件描述符添加到监听集合中
       void FD_ZERO(fd_set *set);         //清空监听集合

例子:多路复用设计TCP客户端

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>

int main()
{
    // 1.创建TCP通信对象
    int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (tcp_socket < 0)
    {
        perror("创建对象失败\n");
        return -1;
    }
    else
    {
        printf("创建对象成功\n");
    }

    // 2.设置服务器地址信息
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;                        // IPV4网络协议
    addr.sin_port = htons(7777);                      // 设置端口号
    addr.sin_addr.s_addr = inet_addr("192.168.63.1"); // 设置IP地址
    int ret = connect(tcp_socket, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        perror("连接失败\n");
        return -1;
    }
    else
    {
        printf("连接成功\n");
    }

#if 0
    // 读取网络数据
    while (1)
    {
        char buf[1024] = {0};
        read(tcp_socket, buf, 1024); // 阻塞-> tcp_socket描述 3
        printf("recv:%s\n", buf);
    }

    // 发送数据到网络中
    while (1)
    {
        printf("请输入需要发送的网络数据\n");
        char buf[1024] = {0};
        scanf("%s", buf); // 阻塞  -> 标准输入描述 0
        write(tcp_socket, buf, strlen(buf));
    }
#endif

    while (1)
    {
        // 1.清空集合
        fd_set set;
        FD_ZERO(&set);

        // 2.添加阻塞IO描述符到集合中
        FD_SET(0, &set);          // 添加标准输入描述符
        FD_SET(tcp_socket, &set); // 添加网络描述符 3

        // 3.select 开启监听
        printf("开启监听集合中的描述符......\n");
        int ret = select(tcp_socket + 1, &set, NULL, NULL, NULL); // 监听读集合

        if (ret > 0) // 有活跃描述符 /描述符有数据可读
        {
            printf("描述符有数据,请处理\n");

            // 判断是否为输入描述符活跃
            if (FD_ISSET(0, &set))
            {
                printf("0号描述符活跃\n");
                char buf[1024] = {0};
                read(0, buf, 1024);

                // 发送数据到网络中
                write(tcp_socket, buf, strlen(buf));
            }

            // 判断是否为TCP_SOCKET活跃
            if (FD_ISSET(tcp_socket, &set))
            {
                printf("tcp_socket描述符活跃\n");
                char buf[1024] = {0};
                read(tcp_socket, buf, 1024);

                printf("recv:%s\n", buf);
            }
        }
    }
}

3.select超时检测

#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>

int main()
{
    // 1.创建TCP服务器对象
    int tcp_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (tcp_socket < 0)
    {
        perror("创建对象失败\n");
        return -1;
    }
    else
    {
        printf("创建对象成功\n");
    }

    // 2.设置服务器地址信息
    struct sockaddr_in addr;
    addr.sin_family = AF_INET;   // IPV4网络协议
    addr.sin_port = htons(1688); // 设置端口号
    // addr.sin_addr.s_addr = inet_addr("192.168.63.1"); // 设置IP地址
    addr.sin_addr.s_addr = INADDR_ANY; // 绑定所有网卡
    int ret = bind(tcp_socket, (struct sockaddr *)&addr, sizeof(addr));
    if (ret < 0)
    {
        perror("绑定失败\n");
        return -1;
    }
    else
    {
        printf("绑定成功\n");
    }

    // 3.开启监听
    ret = listen(tcp_socket, 10);
    if (ret < 0)
    {
        perror("监听失败\n");
        return -1;
    }
    else
    {
        printf("监听成功\n");
    }

    while (1)
    {

        // 1.清空集合
        fd_set set;
        FD_ZERO(&set);

        // 2.添加阻塞IO描述符到集合中
        FD_SET(tcp_socket, &set); // 添加服务器描述到集合中

        // 设置监听的时间
        struct timeval timeout;
        timeout.tv_sec = 10; // 设置10秒
        timeout.tv_usec = 0;

        // 3.开始监听
        int ret = select(tcp_socket + 1, &set, NULL, NULL, &timeout);

        if (ret == 0) // 超时
        {
            printf("超时未有客户端连接\n");
        }

        if (ret > 0) // 有客户端连接
        {
            if (FD_ISSET(tcp_socket, &set))
            {
                printf("有新客户端连接,开启处理\n");

                int new_scoekt = accept(tcp_socket, NULL, NULL);

                printf("新客户端 %d\n", new_scoekt);
            }
        }
    }
}

 

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

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

相关文章

AI领域再突破,永洪科技荣获“2025人工智能+创新案例”奖

在2025年的今天&#xff0c;人工智能已从技术概念全面渗透至产业核心。中国作为全球AI技术应用的前沿阵地&#xff0c;正通过“人工智能”行动加速推进技术与实体经济深度融合。 这一背景下&#xff0c;永洪科技凭借其“国内某头部ICT人力资源板块GenAI项目”荣获“2025全国企业…

基于疾风大模型的新能源储能优化系统:方法、实现与案例分析

一、引言 随着可再生能源渗透率不断提高,储能系统在电力系统中的重要性日益凸显。传统储能控制方法主要基于规则策略和简单优化算法,难以应对高比例新能源场景下的复杂决策需求。本文将详细介绍如何利用疾风大模型(Gale Model)构建智能化的新能源储能优化系统,包含核心方…

菊风RTC 2.0 开发者文档正式发布,解锁音视频新体验!

重磅发布&#xff01; 开发者们&#xff0c;菊风实时音视频2.0文档已正式发布上线&#xff0c;为您提供更清晰、更高效的开发支持&#xff01;让菊风实时音视频2.0为您的音视频应用加速~ 菊风实时音视频2.0聚焦性能升级、体验升级、录制服务升级&#xff0c;助力视频通话、语…

OpenCv高阶(一)——图像金字塔(上采样、下采样)

目录 图像金字塔 一、上下采样原理 1、向下取样 2、向上采样 3、图像金字塔的作用 二、案例实现 1、高斯下采样 2、高斯金字塔中的上采样 3、对下采样的结果做上采样&#xff0c;图像变模糊&#xff0c;无法复原 4、拉普拉斯金字塔&#xff08;图片复原&#xff09; 图…

LEARNING DYNAMICS OF LLM FINETUNING【论文阅读笔记】

LEARNING DYNAMICS OF LLM FINETUNING 一句话总结 作者将LLM的学习动力机制拆解成AKG三项&#xff0c;并分别观察了SFT和DPO训练过程中​​正梯度信号​​和​​负梯度信号​​的变化及其带来的影响&#xff0c;并得到以下结论&#xff1a; ​​SFT通过梯度相似性间接提升无关…

数据集 | 沥青路面缺陷目标检测

文章目录 一、数据集概述1. 行业痛点与数据集价值2. 数据集技术规格 二、样本类别详解1. 裂缝 (Crack)2. 裂缝修补 (Crack Repair)3. 坑洞 (Pothole)4. 坑洞修补 (Pothole Repair)5. 井盖 (Manhole Cover)6. 其他 (Other) 三、标注工具四、下载地址 一、数据集概述 1. 行业痛点…

AllData数据中台升级发布 | 支持K8S数据平台2.0版本

&#x1f525;&#x1f525; AllData大数据产品是可定义数据中台&#xff0c;以数据平台为底座&#xff0c;以数据中台为桥梁&#xff0c;以机器学习平台为中层框架&#xff0c;以大模型应用为上游产品&#xff0c;提供全链路数字化解决方案。 ✨杭州奥零数据科技官网&#xf…

.net Core 和 .net freamwork 调用 deepseek api 使用流输出文本(对话补全)

.net Core 调用 deepseek api 使用流输出文本 简下面直接上代码&#xff08;.net core&#xff09;&#xff1a;最后再贴一个 .net Freamwork 4 可以用的代码TLS 的代码至关重要的&#xff1a;&#xff08;下面这个&#xff09; 简 在官网里面有许多的案例&#xff1a;我们通过…

springcloud整理

问题1.服务拆分后如何进行服务之间的调用 我们该如何跨服务调用&#xff0c;准确的说&#xff0c;如何在cart-service中获取item-service服务中的提供的商品数据呢&#xff1f; 解决办法&#xff1a;Spring给我们提供了一个RestTemplate的API&#xff0c;可以方便的实现Http请…

04-算法打卡-数组-二分查找-leetcode(69)-第四天

1 题目地址 69. x 的平方根 - 力扣&#xff08;LeetCode&#xff09;69. x 的平方根 - 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。注意&#xff1a;不允许使用任何内…

[Windows] 字体渲染 mactype v2025.4.11

[Windows] 字体渲染 mactype 链接&#xff1a;https://pan.xunlei.com/s/VONeCUP2hEgO5WIQImgtGUmrA1?pwdyruf# 025.4.11 Variable font support 可变字体支持已到来。 本版本将可变字体支持扩展到所有 GDI 应用程序。 所有 win32 程序中的字体&#xff0c;如 Noto Sans、Se…

VSCode CMake调试CPP程序

文章目录 1 安装C与CMake插件2 配置CMakeLists.txt3 使用CMake编译调试3.1 编译3.2 调试 4 自定义构建调试参考 1 安装C与CMake插件 C插件 CMake插件 2 配置CMakeLists.txt 编写测试程序 #include<iostream>int main(int argc, char const *argv[]) {int a 1, b 2;i…

Halo 设置 GitHub - OAuth2 认证指南

在当今数字化时代&#xff0c;用户认证的便捷性和安全性愈发重要。对于使用 Halo 搭建个人博客或网站的开发者而言&#xff0c;引入 GitHub - OAuth2 认证能够极大地提升用户登录体验。今天&#xff0c;我们就来详细探讨一下如何在 Halo 中设置 GitHub - OAuth2 认证。 一、为…

【unity游戏开发——Animator动画】Animator动画状态机复用——重写动画控制器 Animator Override Controller

注意&#xff1a;考虑到UGUI的内容比较多&#xff0c;我将UGUI的内容分开&#xff0c;并全部整合放在【unity游戏开发——Animator动画】专栏里&#xff0c;感兴趣的小伙伴可以前往逐一查看学习。 文章目录 一、状态机复用是什么&#xff1f;二、实战专栏推荐完结 一、状态机复…

C语言--汉诺塔问题

汉诺塔问题是一个典型的递归问题。 递归问题的基本思想&#xff1a;将问题逐步化简为相同思路但是规模更小的问题&#xff0c;直到问题可以直接解决 递归的关键在于基准情形和递归步骤&#xff0c;基准情形也就是退出条件&#xff0c;递归步骤也就是把问题简化为子问题的过程。…

301.找出3位偶数

2094. 找出 3 位偶数 - 力扣&#xff08;LeetCode&#xff09; class Solution {List<Integer> resnew ArrayList<>();List<Integer> linew ArrayList<>();public int[] findEvenNumbers(int[] digits) {Arrays.sort(digits);boolean[] numsnew boolea…

使用Python从零开始构建端到端文本到图像 Transformer大模型

简介&#xff1a;通过特征向量从文本生成图像 回顾&#xff1a;多模态 Transformer 在使用Python从零实现一个端到端多模态 Transformer大模型中&#xff0c;我们调整了字符级 Transformer 以处理图像&#xff08;通过 ResNet 特征&#xff09;和文本提示&#xff0c;用于视觉…

comfyui点击执行没反应一例

以前只遇到过执行工作流时出错的情况&#xff0c;从没试过说点了执行后一点反应都没有的情况。 今天下载 蓝色多脑盒《一键同时换头、换脸、发型、发色之双pulid技巧》分享的工作&#xff0c;第一次发现点击执行没反应。 发现左下角的地方连接错乱了。 更正连接后工作流能正常…

01-libVLC的视频播放器:环境搭建以及介绍

项目展示项目播放器 VLC简介VLC媒体播放器(VideoLAN Client)是一款开源、跨平台的自由多媒体播放器,由VideoLAN项目开发。它支持众多音频与视频格式(如MPEG-2、MPEG-4、H.264、MKV、WebM、WMV、MP3等),以及DVD、VCD和各种流媒体协议。 VLC的特点跨平台支持:Windows、mac…

用css画一条弧线

ui里有一条弧线&#xff0c;现在用css实现 关键代码 border-bottom-left-radius: 100% 7px 两个参数分别代表横向和纵向的深度border-bottom-right-radius: 100% 7px