Linux 下网络套接字(Socket) 与udp和tcp 相关接口

文章目录

  • 1. socket常见API
  • 2 sockaddr结构体及其子类
    • 1. sockaddr结构体定义(基类)
    • 2. 子类 sockaddr_in结构体用于(IPv4)
    • 3 子类 sockaddr_un(Unix域套接字)
    • 4. 总结画出其结构体
  • 3.实现一个简单的tcp Echo 服务器和客户端(cpp)
    • 3.1 客户端
    • 3.2 服务器
    • 3.3 测试结果

1. socket常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);

  • domain:指定协议族,对于IPv4通常使用AF_INET
  • type:指定套接字类型,对于UDP使用SOCK_DGRAM
  • protocol:通常设置为0,表示使用默认协议。
  • return value: 如果成功,则返回新套接字的文件描述符。如果出现错误,则返回-1,并设置errno来指示错误。

// 绑定端口号 (TCP/UDP, 服务器)
int bind(int sockfd, const struct sockaddr *address, socklen_t address_len);

  • sockfd:套接字文件描述符。
  • sockaddr:指向sockaddr_in结构的指针,包含要绑定的IP地址和端口号。
  • address_len:地址结构的长度。

// 开始监听socket (TCP, 服务器)
int listen(int sockfd, int backlog);

  • sockfd:监听套接字的文件描述符。
  • backlog:连接队列的最大长度。

// 接收请求 (TCP, 服务器)
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

  • sockfd:监听套接字的文件描述符。
  • addr:用于存储接受到的连接请求的源地址(可以为NULL,如果不关心源地址)。
  • addrlen:指向源地址长度的指针(可以为NULL,如果不关心源地址长度)。
  • return value:成功时返回一个新的套接字文件描述符,用于与接受的连接进行通信;失败时返回-1并设置errno。

// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

  • sockfd:客户端套接字的文件描述符。
  • addr:指向服务器地址的指针。
  • addrlen:地址长度

//发送数据(TCP)

  • ssize_t send(int sockfd, const void *buf, size_t len, int flags);
  • sockfd:发送数据的套接字文件描述符。
  • buf:指向要发送的数据的指针。
  • len:数据长度。
  • flags:发送选项,通常设置为0。

//接收数据(TCP)

  • ssize_t recv(int sockfd, void *buf, size_t len, int flags);
  • sockfd:接收数据的套接字文件描述符。
  • buf:用于存储接收到的数据的缓冲区。
  • len:缓冲区长度。
  • flags:接收选项,通常设置为0。

//发送数据(UDP)

  • ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
  • sockfd:发送数据的套接字文件描述符。
  • buf:指向要发送的数据的指针。
  • len:数据长度。
  • flags:发送选项,通常设置为0。
  • dest_addr:目标地址,包含目标IP和端口号。
  • addrlen:目标地址的长度。

//接收数据(UDP)

  • ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • sockfd:接收数据的套接字文件描述符。
  • buf:用于存储接收到的数据的缓冲区。
  • len:缓冲区长度。
  • flags:接收选项,通常设置为0。
  • src_addr:用于存储源地址的指针(可以为NULL,如果不关心源地址)。
  • addrlen:指向源地址长度的指针(可以为NULL,如果不关心源地址长度)。

2 sockaddr结构体及其子类

1. sockaddr结构体定义(基类)

sockaddr
struct sockaddr 是一个通用的结构体,用于表示套接字地址。这个结构体是跨平台的,但它是抽象的,意味着它并不直接用于表示具体的地址类型(如IPv4或IPv6),而是作为一个基类,其他更具体的地址结构体(如 struct sockaddr_instruct sockaddr_in6)会基于它进行扩展。

下面是 struct sockaddr 的成员变量及其解释:

  1. sa_family_t sa_family;

    • 这是一个地址族字段,用来指示地址的类型。地址族决定了结构体中 sa_data 字段的解释方式。常见的地址族包括 AF_INET(用于IPv4地址)和 AF_INET6(用于IPv6地址)。其他可能的值还包括 AF_UNIX(用于本地套接字)等。
  2. char sa_data[14];

    • 这是一个字符数组,用于存储协议地址。对于不同的地址族,这个字段的解释方式不同。例如,对于IPv4地址(AF_INET),这个字段的前4个字节通常会被解释为一个32位的无符号整数,表示IPv4地址。然而,由于 struct sockaddr 是一个通用结构体,sa_data 字段的大小和布局可能不足以直接容纳所有类型的地址,因此在实际使用中,更具体的地址结构体(如 struct sockaddr_in)会提供额外的字段来正确存储和解释地址。

2. 子类 sockaddr_in结构体用于(IPv4)

 sockaddr_in
struct sockaddr_in 是一个结构体,这个结构体是IPv4地址和端口号的封装。下面是它的成员变量及其解释:

  1. __kernel_sa_family_t sin_family;

    • 这是一个地址族字段,用来指示地址的类型。对于IPv4地址,这个字段的值通常是AF_INET。地址族决定了结构体中其他字段的解释方式。
  2. __be16 sin_port;

    • 这个字段表示端口号,使用大端字节序(Big Endian)存储。端口号是一个16位的数字,用于区分同一台机器上的不同服务。
  3. struct in_addr sin_addr;

    • 这是一个结构体,包含了IPv4地址。struct in_addr结构体通常只包含一个32位的无符号整数,用于表示IP地址。这个整数通常使用点分十进制表示法(例如,192.168.1.1)转换为人类可读的格式。
  4. unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - sizeof(unsigned short int) - sizeof(struct in_addr)];

    • 这是一个填充字段,用于确保struct sockaddr_in的大小与更通用的struct sockaddr结构体相匹配。struct sockaddr是一个更大的结构体,设计用于包含各种不同类型的地址。__SOCK_SIZE__是一个宏,定义了struct sockaddr的大小。填充字段的大小是根据struct sockaddr的大小减去struct sockaddr_in中已知字段的大小来计算的。这样做是为了确保struct sockaddr_in可以被安全地转换为struct sockaddr,或者相反,而不会出现内存对齐或大小不匹配的问题。

3 子类 sockaddr_un(Unix域套接字)

sockaddr_un

struct sockaddr_un 是一个用于表示Unix域套接字地址的结构体。Unix域套接字是一种在同一台机器上的不同进程间进行通信的机制。与基于网络的套接字不同,Unix域套接字不涉及网络协议栈,因此它们通常具有更低的延迟和更高的带宽。

下面是 struct sockaddr_un 的成员变量及其解释:

  1. __kernel_sa_family_t sun_family;

    • 这是一个地址族字段,用于指示地址的类型。对于Unix域套接字,这个字段的值应该被设置为 AF_UNIX 或其同义词 AF_LOCAL。地址族决定了结构体中其他字段的解释方式。
  2. char sun_path[UNIX_PATH_MAX];

    • 这是一个字符数组,用于存储套接字文件的路径名。Unix域套接字可以通过文件系统路径名(也称为套接字文件)进行标识和访问。UNIX_PATH_MAX 是一个宏,定义了 sun_path 数组的最大长度,即套接字文件路径名的最大长度。这个长度在不同的系统和实现中可能有所不同,但通常足够长,可以容纳大多数文件系统路径名。

4. 总结画出其结构体

socket family

3.实现一个简单的tcp Echo 服务器和客户端(cpp)

3.1 客户端

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define PORT 12345
#define BUFFER_SIZE 1024

int main() {
   int sock_fd;
   struct sockaddr_in server_addr;
   char buffer[BUFFER_SIZE];

   // 创建套接字
   sock_fd = socket(AF_INET, SOCK_STREAM, 0);
   if (sock_fd == -1) {
       perror("Socket creation failed");
       return 1;
   }

   // 配置服务器地址结构
   server_addr.sin_family = AF_INET;
   server_addr.sin_port = htons(PORT);
   if (inet_pton(AF_INET, "127.0.0.1", &server_addr.sin_addr) <= 0) {
       perror("Invalid address");
       close(sock_fd);
       return 1;
   }

   // 连接服务器
   if (connect(sock_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
       perror("Connection failed");
       close(sock_fd);
       return 1;
   }
   std::cout << "Connected to server." << std::endl;

   // Echo 循环
   while (true) {
       std::cout << "Enter message: ";
       std::cin.getline(buffer, BUFFER_SIZE);

       if (std::strcmp(buffer, "exit") == 0) {
           std::cout << "Exiting..." << std::endl;
           break;
       }

       send(sock_fd, buffer, std::strlen(buffer), 0);
       memset(buffer, 0, BUFFER_SIZE);
       ssize_t bytes_received = recv(sock_fd, buffer, BUFFER_SIZE, 0);

       if (bytes_received > 0) {
           std::cout << "Echo from server: " << buffer << std::endl;
       } else {
           std::cout << "Server disconnected." << std::endl;
           break;
       }
   }

   close(sock_fd);
   return 0;
}

3.2 服务器

#include <iostream>
#include <cstring>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define PORT 12345
#define BUFFER_SIZE 1024

int main() {
    int server_fd, client_fd;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUFFER_SIZE];
    socklen_t addr_len = sizeof(client_addr);

    // 创建套接字
    server_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_fd == -1) {
        perror("Socket creation failed");
        return 1;
    }

    // 配置服务器地址结构
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);

    // 绑定套接字到端口
    if (bind(server_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
        perror("Bind failed");
        close(server_fd);
        return 1;
    }

    // 监听连接
    if (listen(server_fd, 5) == -1) {
        perror("Listen failed");
        close(server_fd);
        return 1;
    }
    std::cout << "Server is listening on port " << PORT << "..." << std::endl;

    // 接受客户端连接
    client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &addr_len);
    if (client_fd == -1) {
        perror("Accept failed");
        close(server_fd);
        return 1;
    }
    std::cout << "Client connected." << std::endl;

    // Echo 循环
    while (true) {
        memset(buffer, 0, BUFFER_SIZE);
        ssize_t bytes_received = recv(client_fd, buffer, BUFFER_SIZE, 0);
        if (bytes_received <= 0) {
            std::cout << "Client disconnected." << std::endl;
            break;
        }

        std::cout << "Received: " << buffer << std::endl;
        send(client_fd, buffer, bytes_received, 0);
    }

    close(client_fd);
    close(server_fd);
    return 0;
}

3.3 测试结果

test

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

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

相关文章

IPv6基础知识

IPv6是由IEIF提出的互聯網協議第六版&#xff0c;用來替代IPv4的下一代協議&#xff0c;它的提出不僅解決了網絡地址資源匱乏問題&#xff0c;也解決了多種接入設備接入互聯網的障礙。IPv6的地址長度為128位&#xff0c;可支持340多萬億個地址。如下圖&#xff0c;3ffe:1900:fe…

24首届数证杯(流量分析部分)

目录 流量分析 流量分析 1、分析网络流量包检材&#xff0c;写出抓取该流量包时所花费的秒数?(填写数字&#xff0c;答案格式:10) 3504相加即可 2、分析网络流量包检材&#xff0c;抓取该流量包时使用计算机操作系统的build版本是多少? 23F793、分析网络流量包检材&#x…

Linux(CentOS)安装达梦数据库 dm8

CentOS版本&#xff1a;CentOS 7&#xff0c;查看操作系统版本信息&#xff0c;请查阅 查看Linux内核版本信息 达梦数据库版本&#xff1a;dm8 一、获取 dm8 安装文件 1、下载安装文件 打开达梦官网&#xff1a;https://www.dameng.com/ 下载的文件 解压后的文件 2、上传安…

vue-i18n下载完报错

解决方法&#xff1a; 这是i18n版本太高了&#xff0c;与当前VUE版本不谦容&#xff1b; 查看版本&#xff1a;npm view vue-i18n versions 选择其中一个低版本&#xff0c;不要太低的 npm install vue-i18n7.3.22.可以删掉依赖包重新下载试试 报错类似如下&#xff1a; 1…/…

Docker环境搭建Cloudreve网盘服务(附shell脚本一键搭建)

Docker搭建Cloudreve Cloudreve介绍&#xff1a; Cloudreve 是一个基于 ThinkPHP 框架构建的开源网盘系统&#xff0c;旨在帮助用户以较低的成本快速搭建起既能满足个人也能满足企业需求的网盘服务。Cloudreve 支持多种存储介质&#xff0c;包括但不限于本地存储、阿里云OSS、…

凹凸/高度贴图、法线贴图、视差贴图、置换贴图异同

参考&#xff1a; 凹凸贴图、法线贴图、置换贴图-CSDN博客 视差贴图 - LearnOpenGL CN 1,Learn about Parallax(视差贴图) - 知乎 “视差贴图”的工作流程及原理(OpenGL) - 哔哩哔哩 法线与置换贴图原理讲解以及烘焙制作&#xff01; - 知乎 1. Bump Mapping 凹凸贴图 BumpMap…

Vant组件

结合项目学习下Vant组件。 Vue2&#xff1a;Vant 2 - Mobile UI Components built on Vue Vue3&#xff1a;Vant 4 - A lightweight, customizable Vue UI library for mobile web apps. 课程地址&#xff1a;【vue-vant组件库】 https://www.bilibili.com/video/BV1q5411E7…

【DEKF算法】DEKF(双扩展卡尔曼滤波算法)估计锂电池荷电状态,SOC与SOH联合仿真

摘要 本文研究了基于双扩展卡尔曼滤波&#xff08;DEKF&#xff09;算法对锂电池荷电状态&#xff08;SOC&#xff09;和健康状态&#xff08;SOH&#xff09;的估计问题。通过构建锂电池的等效电路模型&#xff08;ECM&#xff09;&#xff0c;将SOC与SOH联合估计&#xff0c…

4-3 AUTOSAR BSW IO抽象

返回总目录->返回总目录<- 目录 一、概述 二、示例接口 一、概述 在AUTOSAR中,IO抽象模块的主要作用是提供对硬件设备的控制和访问。它包括了以下几个主要模块: DIO(Digital Input/Output):用于控制数字输入和输出信号,例如控制LED灯的开关或读取按键状态…

【动手学深度学习Pytorch】1. 线性回归代码

零实现 导入所需要的包&#xff1a; # %matplotlib inline import random import torch from d2l import torch as d2l import matplotlib.pyplot as plt import matplotlib import os构造人造数据集&#xff1a;假设w[2, -3.4]&#xff0c;b4.2&#xff0c;存在随机噪音&…

【数据结构】树——顺序存储二叉树

写在前面 在学习数据结构前&#xff0c;我们早就听说大名鼎鼎的树&#xff0c;例如什么什么手撕红黑树大佬呀&#xff0c;那这篇笔记不才就深入浅出的介绍二叉树。 文章目录 写在前面一、树的概念及结构1.1、数的相关概念1.2、数的表示1.3 树在实际中的运用&#xff08;表示文…

Linux常用命令,持续更新钟

在Linux系统中&#xff0c;你可以使用多种命令来拷贝和移动文件及目录。以下是常用的几个命令及其用法&#xff1a; 一、拷贝文件或目录 cp 命令 cp 命令用于拷贝文件或目录。 拷贝文件&#xff1a; cp source_file destination_file 例如&#xff1a; cp file1.txt /hom…

计算机视觉中的双边滤波:经典案例与Python代码解析

&#x1f31f; 计算机视觉中的双边滤波&#xff1a;经典案例与Python代码解析 &#x1f680; Hey小伙伴们&#xff01;今天我们要聊的是计算机视觉中的一个重要技术——双边滤波。双边滤波是一种非线性滤波方法&#xff0c;主要用于图像去噪和平滑&#xff0c;同时保留图像的边…

Ubuntu 22.04 上快速搭建 Samba 文件共享服务器

Samba 简介 Samba 是一个开源软件&#xff0c;它扮演着不同操作系统间沟通的桥梁。通过实现 SMB&#xff08;Server Message Block&#xff09;协议&#xff0c;Samba 让文件和打印服务在 Windows、Linux 和 macOS 之间自由流动。 以下是 Samba 的特点&#xff1a; 跨平台兼…

在MATLAB中实现自适应滤波算法

自适应滤波算法是一种根据信号特性自动调整滤波参数的数字信号处理方法&#xff0c;其可以有效处理噪声干扰和信号畸变问题。在许多实时数据处理系统中&#xff0c;自适应滤波算法得到了广泛应用。在MATLAB中&#xff0c;可以使用多种方法实现自适应滤波算法。本文将介绍自适应…

AWTK-WIDGET-WEB-VIEW 发布

awtk-widget-web-view 是通过 webview 提供的接口&#xff0c;实现的 AWTK 自定义控件&#xff0c;使得 AWTK 可以方便的显示 web 页面。 项目网址&#xff1a; https://gitee.com/zlgopen/awtk-widget-web-view webview 提供了一个跨平台的 webview 接口&#xff0c;是一个非…

使用Web Workers提升JavaScript的并行处理能力

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Web Workers提升JavaScript的并行处理能力 使用Web Workers提升JavaScript的并行处理能力 使用Web Workers提升JavaScript的…

shell编程--传参与数学运算

探讨一下如何向shell脚本传递参数。 脚本传参 首先用vim创建一个脚本。 vim 脚本.sh 可以理解为其他编程语言的标准输出&#xff0c;例如C语言的输出%d,表标准输出数字。 用echo 执行文件名称是&#xff1a;$0 echo 第一个参数是&#xff1a;$1 echo 传递参数作为字符串显…

头歌-本关任务:使用GmSSL命令行,生成SM2私钥并对文件进行签名验证(第二关)。

第一关在网上找到了&#xff0c;但第二关没找到&#xff0c;在这里做一下补充:) 如果想认真学的话可以看看文档 国密SM2椭圆曲线密码标准http://gmssl.org/docs/sm2.html 内容为 GuetPython 的明文文件msg.txt 私钥sm2.pem 公钥sm2Pub.pem 使用sm2utl对msg.txt进行签名&…

elementui el-table中给表头 el-table-column 加一个鼠标移入提示说明

前言 在使用el-table 表格中有些表格的表头需要加入一些提示&#xff0c;鼠标移入则出现提示&#xff0c;非常实用&#xff0c;我是通过el-table中的el-tooltip实现的&#xff0c;以下的效果预览 代码实现 <el-table ref"multipleTable" :data"data"…