网络编程 - Linux socket编程

2023-05-16

前言

  socket(套接字)是网络编程编程的一种技巧。通过socket不仅可以实现跨进程通信,还可以实现跨主机的网络通信。使用这种技术,就可以实现全国各地的通讯。例如:深圳的一台电脑接收来自北京一台电脑发来的信息。
  本篇不涉及太底层的网络原理,仅说明socket的基本使用方法。主要参考《Linux网络编程》。

Socket的功能

  socket是通过标准的UNIX文件描述符和其他的程序通讯的一个方法。其可以实现同一主机不同进程间的通信;也可以实现不同主机间的通信。

Socket基础

Socket类型

  套接字有三种类型:流式套接字(SOCK_STREAM),数据报套接字(SOCK_DGRAM)和原始套接字。

流式套接字(SOCK_STREAM)
  流式的套接字可以提供可靠的、面向连接的通讯流。如果你通过流式套接字发送了顺序的数据:"1"、"2"。那么数据到达远程时候的顺序也是"1"、"2"。

面向连接的Socket工作流程

数据报套接字(SOCK_DGRAM)
  数据报套接字定义了一种无连接的服务,数据通过相互独立的报文进行传输,是无序的,并且不保证可靠,无差错。

无连接的socket工作流程

原始套接字(SOCK_RAM)
  原始套接字主要用于一些协议的开发,可以进行比较底层的操作。它功能强大,但是没有上面介绍的两种套接字使用方便,一般的程序也涉及不到原始套接字。

基本结构

  • struct sockaddr
    此结构用于存储套接字地址。在需要通信地址时,此结构体会被用到,例如connect()
struct sockaddr {
    unsigned short sa_family; /* address族, AF_xxx */
    char sa_data[14];         /* 14 bytes的协议地址 */
};

sa_family为指定协议族,通常使用到的有AF_INET、AF_UNIX等。sa_data为不同协议族通信时必要的数据。例如,sa_family为AF_INET时,sa_data要传IP地址和端口号。

  • struct sockaddr_insockaddr_in是用于存储AF_INET的套接字地址,其中in就代表Inet。
      介绍sockaddr时,说到在使用AF_INET需要传IP和端口号,但并不知道要将IP和端口号填到sockaddr的哪个地方。于是,设计了sockaddr_in,定义出地址和端口号成员。在使用时只需要填充sockaddr_in,传参时强转为sockaddr即可(两个结构体大小一致)。
struct sockaddr_in {
    short int sin_family;        /* Internet地址族 */
    unsigned short int sin_port; /* 端口号 */
    struct in_addr sin_addr;     /* Internet地址 */
    unsigned char sin_zero[8];   /* 添0(和struct sockaddr一样大小) */
};
  • struct in_addrin_addrsockaddr_in成员,用于存储4个字节的IP地址。需要注意的是,此值填写时需要按照网络字节来填充,可以通过一些转换函数完成。
struct in_addr {
    unsigned long s_addr;
};
  • struct sockaddr_unsockaddr_un是用于存储AF_UNIX的套接字地址,推测un就代表UNIX(没有求证)。
      和上述类似,当使用AF_UNIX时,需要填充AF_UNIX的地址结构体sockaddr_un,然后传参时强转为sockaddr
struct sockaddr_un
{
    uint8_t sun_len;
    sa_family_t sun_family;  /* AF_LOCAL */
    char sun_path[104];      /* null-terminated pathname */
};

基本转换函数

网络字节序转换
  上文描述填写IP和端口时要注意网络字节序,否则可能连接不到指定的设备。系统提供了如下几种函数方便转换:

  • htons()—— “Host to Network Short” 主机字节顺序转换为网络字节顺序(对无符号短型进行操作 4 bytes)
  • htonl()—— “Host to Network Long” 主机字节顺序转换为网络字节顺序(对无符号长型进行操作 8 bytes)
  • ntohs()—— “Network to Host Short” 网络字节顺序转换为主机字节顺序(对无符号短型进行操作 4 bytes)
  • ntohl()—— “Network to Host Long” 网络字节顺序转换为主机字节顺序(对无符号长型进行操作 8 bytes)

IP地址转换

  • inet_addr()—— 把一个用数字和点表示 IP 地址的字符串转换成网络字节序的无符号长整型。
  • inet_ntoa()—— “Network to ASCII” 将网络字节序的长整型转换成字符串。

inet_ntoa()返回一个字符指针,它指向一个定义在函数 inet_ntoa() 中的 static 类型字符串。所以每次调用 inet_ntoa(),都会改变最后一次调用 inet_ntoa() 函数时得到的结果。

基本Socket使用

  Linux同时支持面向连接和不连接类型的套接字。在面向连接的通讯中服务器和客户机在交换数据之前先要建立一个连接;在不连接通讯中数据被作为信息的一部分被交换。
  无论那一种方式,服务器总是最先启动,把自己绑定(Banding)在一个套接字上,然后侦听信息。

socket主要使用到如下函数:

  • socket()函数 —— 创建套接字。
  • bind()函数 —— 绑定socket地址信息。(Inet需要传入IP、端口;Unix 需要传入路径)
  • connect()函数 —— 连接指定服务器套接字。
  • listen()函数 —— 服务器监听连接上的套接字客户端。
  • accept()函数 —— 接受远程客户端套接字,会获取到远程连接客户端的地址信息。(阻塞接口)
  • send()函数/recv()函数 —— 连接的流式套接字进行通讯的函数。
  • sendto()函数/recvfrom()函数 —— 非连接的数据报套接字进行通讯的函数。
  • close()函数 —— 关闭套接字描述符所表示的连接。
  • shutdown()函数 —— 指定关闭套接字的方式。
  • setsockopt()函数/getsockopt()函数 —— 套接字设置项的设置和获取。
  • getpeername()函数 —— 取得一个已经连接上的套接字的远程信息。
  • getsockname()函数 —— 取得本地主机的信息。
  • gethostbyname()函数 —— 通过域名获取IP地址。
  • gethostbyaddr()函数 —— 通过一个IPv4的地址来获取主机信息。
  • getprotobyname()函数 —— 获得网络协议名。

TCP Socket实例

  TCP Socket可以理解为Inet使用流式套接字,为保证通讯稳定而采用TCP协议。其优点在于可靠、稳定。

TCP Socket 服务端

void DealClientMsgThread(int fd)
{
    while(1)
    {
        char buf[1024] = {0};
        int ret = read(fd, buf, sizeof(buf));
        if (ret > 0) {
            TSVR_LOG("# RECEIVE: %s.\n", buf);

            // response dstAddr msg
            char ack[20] = {0};
            snprintf(ack, sizeof(ack), "Ack [%ld]", strlen(buf));
            write(fd, ack, strlen(ack));
        } else {
            break;
        }
    }
    
    TSVR_LOG("Disconnect.\n");
}

int main(int argc, char *argv[])
{
    int i = 0;
    std::thread threads[MAX_NUM_THREAD];

    if (argc != 2)
    {
        TSVR_LOG("usage ./tcp_server 8080.\n");
        return -1;
    }

    string port = argv[1];

    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockFd == -1)
    {
        TSVR_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    int op = 1;
    if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) {
        TSVR_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        goto exit;
    }

    struct sockaddr_in myAddr;
    bzero(&myAddr, sizeof(myAddr));
    myAddr.sin_family = AF_INET;
    myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myAddr.sin_port = htons(atoi(port.c_str()));
    if (bind(sockFd, (struct sockaddr *)&myAddr, sizeof(myAddr)) == -1) {
        TSVR_LOGE("bind failed. (%s)", strerror(errno));
        goto exit;
    }

    if (listen(sockFd, MAX_SIZE_BACKLOG) == -1) {
        TSVR_LOGE("listen failed. (%s)\n", strerror(errno));
        goto exit;
    }

    while(1)
    {
        // accept
        struct sockaddr_in dstAddr;
        socklen_t addrSize = (socklen_t)sizeof(dstAddr);
        int conFd = accept(sockFd, (struct sockaddr *)&dstAddr, &addrSize);
        if (conFd < 0) {
            TSVR_LOGE("accept failed. (%s)\n", strerror(errno));
            continue;
        }
        
        if (i < MAX_NUM_THREAD)
        {
            threads[i] = std::thread(DealClientMsgThread, conFd);
            threads[i].detach();
            i++;
        } else {
            TSVR_LOG("The number of threads reaches max(%d).\n", MAX_NUM_THREAD);
        }
    }

exit:
    close(sockFd);
    return 0;
}

TCP Socket 客户端

int main(int argc, char *argv[])
{
    int op = 1024;

    if (argc != 3)
    {
        TCLT_LOG("usage ./tcp_client <ip> <port>.\n");
        return -1;
    }

    string ipAddr = argv[1];
    string port = argv[2];

    int sockFd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockFd == -1)
    {
        TCLT_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &op, sizeof(op)) < 0) {
        TCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    if (setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &op, sizeof(op)) < 0) {
        TCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    struct sockaddr_in dstAddr;
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
    dstAddr.sin_port = htons(atoi(port.c_str()));
    // Linux TCP repeat connect directly return EISCONN.
    if (   connect(sockFd, (struct sockaddr*)&dstAddr, sizeof(struct sockaddr_in)) < 0 
        && errno != EISCONN) 
    {
        TCLT_LOGE("connect %s:%d failed. (%s)\n", ipAddr.c_str(), atoi(port.c_str()), strerror(errno));
        close(sockFd);
        return -1;
    }

    thread rTh([&]() {
        char recvBuf[1024] = {0};
        TCLT_LOG("Start write thread.\n");

        while(1)
        {
            int ret = read(sockFd, recvBuf, sizeof(recvBuf));
            if (ret > 0) {
                TCLT_LOG("# RECEIVE: %s.\n", recvBuf);
            } else {
                break;
            }
        }
    });
    
    thread wTh([&]() {
        TCLT_LOG("Start read thread.\n");

        while(1)
        {
            char sndBuf[] = "Hello World";
            int ret = write(sockFd, sndBuf, strlen(sndBuf));
            if (ret > 0)
            {
                TCLT_LOG("# SEND > %s.\n", sndBuf);
            } else {
                break;
            }
            sleep(2);
        }
    });
    
    rTh.join();
    wTh.join();

    return 0;
}

代码是很简单的TCP通讯处理,为方便理解,不做过多封装。

UDP Socket实例

  UDP Socket可以理解为Inet使用数据报套接字,为了快速通讯,客户端与服务端约定采用的UDP的套接字通讯。

UDP Socket 服务端

int main(int argc, char *argv[])
{
    struct sockaddr_in dstAddr;
    socklen_t addrSize = sizeof(struct sockaddr_in);

    if (argc != 2)
    {
        USVR_LOG("usage ./udp_server 8080.\n");
        return -1;
    }
    
    string port = argv[1];

    int sockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockFd == -1)
    {
        USVR_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }
    
    int op = 1;
    if (setsockopt(sockFd, SOL_SOCKET, SO_REUSEADDR, &op, sizeof(op)) < 0) {
        USVR_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        goto exit;
    }

    struct sockaddr_in myAddr;
    bzero(&myAddr, sizeof(struct sockaddr_in));
    myAddr.sin_family = AF_INET;
    myAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    myAddr.sin_port = htons(atoi(port.c_str()));
    if (bind(sockFd, (struct sockaddr *)&myAddr, sizeof(struct sockaddr_in)) < 0) {
        USVR_LOGE("bind failed. (%s)\n", strerror(errno));
        goto exit;
    }

    while(1)
    {
        char buf[1024] = {0};
        int ret = recvfrom(sockFd, buf, sizeof(buf), 0, 
                    (struct sockaddr *)&dstAddr, &addrSize);

        if (ret > 0) {
            char ack[20] = {0};

            snprintf(ack, sizeof(ack), "Ack [%ld]", strlen(buf));
            USVR_LOG("# RECEIVE: %s.\n", buf);
            sendto(sockFd, ack, strlen(ack), 0, 
                    (struct sockaddr *)&dstAddr, addrSize);

        } else {
            USVR_LOG("recvfrom failed. (%s)\n", strerror(errno));
            break;
        }
    }

exit:
    close(sockFd);
    return 0;
}

UDP Socket 客户端

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        UCLT_LOG("usage ./udp_client <ip> <port>.\n");
        return -1;
    }

    string ipAddr = argv[1];
    string port = argv[2];

    int sockFd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockFd == -1)
    {
        UCLT_LOGE("socket failed. (%s)\n", strerror(errno));
        return -1;
    }

    int op = 1024;
    if (setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &op, sizeof(op)) < 0) {
        UCLT_LOGE("setsockopt failed. (%s)\n", strerror(errno));
        close(sockFd);
        return -1;
    }

    struct sockaddr_in dstAddr;
    bzero(&dstAddr, sizeof(struct sockaddr_in));
    dstAddr.sin_family = AF_INET;
    dstAddr.sin_addr.s_addr = inet_addr(ipAddr.c_str());
    dstAddr.sin_port = htons(atoi(port.c_str()));

    thread wTh([&]() {
        UCLT_LOG("Start write thread.\n");

        while(1)
        {
            char sndBuf[] = "Hello World";
            int ret = sendto(sockFd, sndBuf, strlen(sndBuf), 0, 
                        (struct sockaddr *)&dstAddr, sizeof(struct sockaddr_in));

            if (ret > 0) {
                UCLT_LOG("# SEND: %s.\n", sndBuf);
            } else {
                break;
            }

            sleep(2);
        }
    });
    
    thread rTh([&]() {
        struct sockaddr_in dstAddr;
        UCLT_LOG("Start read thread.\n");

        while(1)
        {
            char recvBuf[1024] = {0};
            socklen_t addrSize = sizeof(struct sockaddr_in);
            bzero(&dstAddr, addrSize);
            int ret = recvfrom(sockFd, recvBuf, sizeof(recvBuf), 0, 
                        (struct sockaddr *)&dstAddr, &addrSize);

            if (ret > 0)
            {
                UCLT_LOG("# RECEIVE: %s.\n", recvBuf);
            } else {
                break;
            }
        }
    });
    
    wTh.join();
    rTh.join();
    return 0;
}

疑难问题记录

  • TCP服务端和客户端如何精确地检测到对方下线或异常断开?
    ① 接收函数是阻塞的,当对方断开接收函数会返回异常。
    ② 通过错误码和信号判断,当一端异常断开,另一端会收到SIGPIPE信号,再通过getsockopt查询各个套接字确认哪一个断开。

  • UDP 如何保证通讯数据稳定
    UDP通讯因为不需要连接,从而比TCP通讯更快,但是由于其不确保数据是否安全到达,从而显得不靠谱。为了实现通讯靠谱,需要在应用层建立一套机制验证数据准确性,建立失误重传的约定。

总结

  • socket的实现非常优秀,将复杂的网络通信,封装成简单的socket的接口。使用者不用过多考虑TCP、UDP以及其他较底层的网络概念,而快速的实现一套网络通讯的流程。
  • 本文仅列举了socket用于inet地址族的例程,其还可以用于UNIX域的进程间通讯。
  • 网络编程非常有趣,能够实现天南海北之间的通讯,让远距离的人与人、人与物或者物与物之间产生联系,很有意思!
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

网络编程 - Linux socket编程 的相关文章

  • Linux——网络桥接

    什么是网络桥接 xff1f 在网络的使用中 xff0c 有时需要搭建网络桥来实现网络桥接 例如在一台主机上制作一台虚拟机 xff0c 虚拟机是没有物理网卡的 xff0c 这时虚拟机数据的发送和接收就需要通过主机上的物理网卡 xff0c 需要
  • STM32实战之LED循环点亮

    接着上一章讲 本章我们来讲一讲LED流水灯 xff0c 循环点亮LED 在LED章节有的可能没有讲到 xff0c 本章会对其进行说明 xff0c 尽量每个函数说一下作用 也会在最后说一下STM32的寄存器 xff0c 在编程中寄存器是避免不
  • 远程连接桌面到ubuntu登录闪退

    问题 xff1a 远程连接到Ubuntu的时候登录闪退 xff0c 密码正确 xff0c 且之前在本地登录过没有问题 xff0c ssh登录没有问题 原因 xff1a 就是因为之前在本地登录了没有登出 xff0c 只是锁屏了 xff0c 导
  • CSRF跨站请求伪造漏洞修复

    文章目录 一 漏洞描述二 解决建议二 解决方法Springboot 配置文件增加配置编写配置类编写过滤器 提示 xff1a 以下是本篇文章正文内容 xff0c 下面案例可供参考 一 漏洞描述 跨站请求伪造 xff08 Cross site
  • Linux挂载磁盘(扩容)

    磁盘相关介绍 xff1a fdisk l 查看磁盘占用情况 sda xff1a 代表一个磁盘 s SCSI d 磁盘 a 代表挂在在SCSI类型的硬盘的第一块 Linux文件系统 xff1a 都是用文件 形式描述的 SCSI xff1a 用
  • 动规例题C++代码

    动规题目 xff1a 字符串S由小写字母构成 xff0c 长度为n 定义一种操作 xff0c 每次都可以挑选字符串中任意的两个相邻字母进行交换 询问在至多交换m次之后 xff0c 字符串中最多有多少个连续的位置上的字母相同 xff1f 参考
  • Centos7下Samba服务器配置

    环境 vm下centos7 6 xff0c IP地址 xff1a 192 168 139 200 Samba概述 Samba是在Linux和UNIX系统上实现SMB协议的一个免费软件 xff0c 由服务器及客户端程序构成 SMB xff08
  • iOS 自定义tableView Cell、高度自适应

    1 xib方式创建 每个cell的显示的内容都是固定的 xff0c 也就是cell的高度都是相同的 加载数据 有plist文件数据结构如下 创建数据模型 Product span class token punctuation span h
  • Windows7修改socket默认缓冲区大小

    在工作中 xff0c 遇到游戏服通过UDP协议向日志服发送日志时 xff0c 日志服有时无法识别游戏服发送过来的日志消息 通过抓包发现 xff0c Windows收到的数据包大小 xff0c 比实例的数据包小 猜测是Windows sock
  • Windows10 上安装 Anaconda 后命令提示符(cmd)下无法执行python命令解决方案

    安装Anaconda后一段时间内能够在命令提示符 xff08 cmd xff09 界面运行python会进入python的交互界面 xff01 可是一段时间后突然间后突然运行不通过报错如图一所示 然后我们找到路径 C Program Fil
  • python实现视频转文字

    最近在做视频转文本的工作 xff0c 遇到了不少问题 xff0c 记录一下 本博客包括以下内容 xff1a 1 如何将视频转换成音频 2 如何调用科大讯飞API实现音频转文字 首先 xff0c 视频转文本 xff0c 如果调用科大讯飞API
  • centos7安装gitlab-ce

    安装gitlab ce 首先安装依赖 xff1a yum install curl openssh server openssh clients postfix policycoreutils python启动所需服务 systemctl
  • vue使用element-plus创建项目

    vue cli创建项目 报错 找到windows powershell 管理员 xff0c 必须以管理员身份执行 xff0c 输入 set ExecutionPolicy RemoteSigned 选择创建方式 Default Uue 3
  • java zip文件解压(含有密码解压)

    maven需要加入以下依赖 xff1a lt dependency gt lt groupId gt net lingala zip4j lt groupId gt lt artifactId gt zip4j lt artifactId
  • pcl用PCLVisualizer可视化ply数据,显示界面卡死问题

    pcl用PCLVisualizer可视化ply数据 xff0c 显示界面卡死问题 在addPointCloud后面加一句viwer gt spin
  • 2020-11-08

    超级好用的免费PDF转word网站 超级PDF https xpdf net 一个超级好用的PDF处理网站 xff0c 功能强大 这个网站提供了丰富的PDF转换 xff0c 处理功能 xff0c 支持OCR识别 操作简单 xff0c 速度快
  • 2021-04-23

    看起来像传指针的传值的函数参数传递 span class token keyword void span span class token function func span span class token punctuation sp
  • 3D slicer编译过程中遇到的问题总结

    3D slicer编译过程中遇到的问题总结系列一 1 xff0c 有关python部分编译 1 gt 已启动生成 项目 python setuptools 配置 Debug x64 1 gt Creating directories for
  • Haskell大世界+思考

    文章目录 基石般灵活表现自由的抽象范式编程语言是什么 xff1f 推荐论文大佬建议MetaHaskell 实现类型系统语言抽象 模式问题解决方案 Haskell在工业界有哪些实际的应用 xff1f 关于fp的一些思考递归是循环的超集 同样是
  • Promox VE(PVE) 连接wifi配置

    pve一个管理虚拟机和容器的平台 xff0c 由于是开源免费的 xff0c 被很多小伙伴用来搭建自己的 34 all in one 34 主机 我也看过很多相关文章和教程 xff0c 看着大家玩的不亦乐乎 xff0c 再看着自己半退役的笔记

随机推荐

  • vscode的conda环境切换和快捷键终端切换文件所在路径

    最近miniconda太多环境 xff0c vs code编辑切换太麻烦 xff0c 于是整个快捷键 cmd 43 shift 43 p设置user settingup json 34 terminal integrated shell w
  • SonarLint黄线警告python:S125

    SonarLint黄线警告python S125 刚安装了SonarLint到我的vscode上 xff0c 发现有黄线警告说我的代码风格不好 黄线的原因是 xff1a 程序员不应该注释掉代码 xff0c 因为它使程序膨胀 xff0c 降低
  • mark点Z3学习资料整理

    文章目录 Anything is NothingLess is MoreSMTz3 classeslogic programming Reasoning符号推理策略strategiesFixed point关系代数datalog程序分析验证
  • windows和wsl设置代理

    wsl查看host ip用脚本试试查看具体当下宿主机和wsl自身不同的两个ip或者 分配固定ip 或者cmd用ipconfig看或者localhost 127 0 0 1 xff0c 然后区分socks5还是http协议 xff0c 然后查
  • 数学物理计算机的思考

    一些关于数学物理计算机的妄言 如果说冥冥之中有一种真理 自然世界的运作规律 61 真理 61 自然科学 xff0c 致敬牛顿的那本著名的几何书 xff0c 我会把它叫做 自然哲学 以下我说的每句话 xff0c 都蕴涵着我自己的生活经历 xf
  • 一个知乎提问引发的(思考)[https://www.zhihu.com/question/263431508/answer/574084280]

    表示很喜欢这个问题 xff0c 深有同感 xff01 这个问题也让我这种杂家谈谈想法吧 xff0c 看题主应该是骨骼精奇的奇才 xff0c 我假想读者是 小学生 xff0c 所以 xff0c 觉得我啰嗦的大大 xff0c 忍忍吧 xff0c
  • Johnson算法PlantSimulation解决两机器多作业排版问题

    生产系统仿真应用教程PlantSimulation 周金平Johnson算法代码写错了的源代码 xff1a is i j m n y integer do y 61 Jobs ydim m 61 1 n 61 y for i 61 1 to
  • 组成原理---补码加减法,原码一两位乘法,补码一两位乘法,754标准

    翻转课堂 xff0c 学生讲课 xff0c 笔记顺便贴上来吧 万一有人需要呢 这里754标准其实可以看https blog csdn net xingqingly article details 18981671 xff0c 我没有把尾数规
  • POSIX 网络API原理

    1 POSIX 网络API 网络编程常用的API xff1a 2 IO函数的内部过程分析 2 1 Socket socket作为网络编程的第一个函数 xff0c 主要作用是用于创建句柄和对应的TCB控制块 xff1b 建立起文件描述符和内部
  • 卷积神经网络(CNN)的平移不变性和旋转不变性。

    文章目录 不变性的介绍不变性的原理 不变性的介绍 不变性意味着即使目标的外观发生了某种变化 xff0c 但是你依然可以把它识别出来 旋转不变性和平移不变性 xff1a 通俗的讲 xff0c 我给你一张图片 xff0c 你识别出来这是只狗 x
  • ubuntu22.04版本APPimage启动报错问题解决

    文章目录 前言 xff1a 报错信息解决方法结果展示你以为就完了 xff1f 天真 xff01 结果展示2结语 前言 xff1a 因为个人比较喜欢提前使用一些较新的软件 系统之类的东西 xff0c 所有在ubuntu22刚发行就选择了升级
  • 音视频封装原理简介

    1 什么是数据化封住和解封装 xff1f 2 视频数据的封装 3 什么是音视频的封装格式 4 封装格式
  • wsl 配置 java 环境以及使用 vscode 调试

    wsl 配置 java 环境以及使用 vscode 调试 原文 xff1a https blog csdn net huiruwei1020 article details 107775782 按照原文我无法运行 xff0c 按照Stack
  • L13. hrtimer使用实例(高精度定时器)

    1 简介 随着内核不断更新演进 xff0c 内核对定时器的分辨率要求越来越高 硬件的高速发展也逐渐能够满足内核的这一要求 xff0c 因此内核针对硬件提供的便利 xff0c 开始设计了更高分辨率的定时器 xff08 hrtimer xff0
  • 鸿蒙操作系统下载

    简介 华为最近开源了自产的操作系统 Harmony 凑一波热闹 xff0c 下载源码看看 横看成岭侧成峰 xff0c 远近高低各不同 由于目前水平有限 xff0c 所以不对鸿蒙操作系统做出过多评价 xff0c 只是下载来学习一下 愿景是希望
  • 5. C++ 抽象类

    1 简介 抽象类往往用来表征对问题领域进行分析 设计中得出的抽象概念 xff0c 是对一系列看上去不同 xff0c 但是本质上相同的具体概念的抽象 通常在编程语句中用 abstract 修饰的类是抽象类 在C 43 43 中 xff0c 含
  • C++并发编程 - 互斥锁(lock_guard和unique_lock)

    C 43 43 并发编程 互斥锁 在多线程的编程中 xff0c 共享数据的修改限制是必不可少的环节 期望的是 当一个线程访问共享数据期间 xff0c 此数据不应该被其他线程修改 xff1b 当某个线程修改了共享数据 xff0c 应通知其他线
  • CMake搭建编译环境总结

    前言 交叉编译算是每个嵌入式开发者都会经历的一道坎吧 xff0c 通俗的描述就是搭建Arm板代码编译环境 xff0c 让代码能够在Arm板子上跑起来 常用到的编译工具为Makefile和CMake xff0c 本篇记录下CMake的常用技巧
  • C++ lambda表达式

    lambda表达式 目录 一 开篇二 lambda初识三 lambda基本用法四 lambda表达式捕获列表五 总结六 参考 一 开篇 lambda表达式是C 43 43 11引进的一个新特性 xff0c 其写法比较新颖 xff0c 经常被
  • 网络编程 - Linux socket编程

    前言 socket 套接字 是网络编程编程的一种技巧 通过socket不仅可以实现跨进程通信 xff0c 还可以实现跨主机的网络通信 使用这种技术 xff0c 就可以实现全国各地的通讯 例如 xff1a 深圳的一台电脑接收来自北京一台电脑发