Linux——网络(udp)


文章目录

目录

文章目录

前言

一、upd函数及接口介绍

1. 创建套接字 - socket 函数

2. 绑定地址和端口 - bind 函数

3. 发送数据 - sendto 函数

4. 接收数据 - recvfrom 函数

5. 关闭套接字 - close 函数

二、代码示例

1.服务端

2.客户端

总结


前言

Linux——网络基础(1)-CSDN博客


一、upd函数及接口介绍

1. 创建套接字 - socket 函数

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

  • 参数说明:
    • domain:指定协议族,对于 UDP 编程,通常使用 AF_INET 表示 IPv4 协议族。
    • type:指定套接字类型,对于 UDP,使用 SOCK_DGRAM 表示数据报套接字。
    • protocol:指定具体的协议,一般设置为 0,让系统自动选择合适的协议(对于 SOCK_DGRAM 通常为 UDP)。
  • 返回值:
    • 成功时返回一个非负的套接字描述符;失败时返回 -1,并设置 errno 以指示错误类型。

2. 绑定地址和端口 - bind 函数

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

 

  • 参数说明:
    • sockfd:由 socket 函数返回的套接字描述符。
    • addr:指向 sockaddr 结构体的指针,该结构体包含要绑定的地址和端口信息。对于 IPv4,通常使用 sockaddr_in 结构体,并进行强制类型转换。
    • addrlenaddr 结构体的长度。
  • 返回值:
    • 成功时返回 0;失败时返回 -1,并设置 errno

3. 发送数据 - sendto 函数

#include <sys/socket.h>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:指向目标地址的 sockaddr 结构体指针,包含目标主机的地址和端口信息。
    • addrlendest_addr 结构体的长度。
  • 返回值:
    • 成功时返回实际发送的字节数;失败时返回 -1,并设置 errno

4. 接收数据 - recvfrom 函数

#include <sys/socket.h>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:指向源地址的 sockaddr 结构体指针,用于存储发送方的地址和端口信息。
    • addrlen:指向 src_addr 结构体长度的指针,调用前设置为该结构体的大小,调用后会被更新为实际接收到的地址信息的长度。
  • 返回值:
    • 成功时返回实际接收的字节数;失败时返回 -1,并设置 errno

5. 关闭套接字 - close 函数

#include <unistd.h>int close(int fd);

 

  • 参数说明:
    • fd:要关闭的套接字描述符。
  • 返回值:
    • 成功时返回 0;失败时返回 -1,并设置 errno

二、代码示例

1.服务端

#pragma once#include <iostream>
#include <string>
#include <strings.h>
#include <cstring>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"// using func_t = std::function<std::string(const std::string&)>;
typedef std::function<std::string(const std::string&)> func_t;Log lg;enum{SOCKET_ERR=1,BIND_ERR
};uint16_t defaultport = 8080;
std::string defaultip = "0.0.0.0";
const int size = 1024;class UdpServer{
public:UdpServer(const uint16_t &port = defaultport, const std::string &ip = defaultip):sockfd_(0), port_(port), ip_(ip),isrunning_(false){}void Init(){// 1. 创建udp socketsockfd_ = socket(AF_INET, SOCK_DGRAM, 0); // PF_INETif(sockfd_ < 0){lg(Fatal, "socket create error, sockfd: %d", sockfd_);exit(SOCKET_ERR);}lg(Info, "socket create success, sockfd: %d", sockfd_);// 2. bind socketstruct sockaddr_in local;bzero(&local, sizeof(local));local.sin_family = AF_INET;local.sin_port = htons(port_); //需要保证我的端口号是网络字节序列,因为该端口号是要给对方发送的local.sin_addr.s_addr = inet_addr(ip_.c_str()); //1. string -> uint32_t 2. uint32_t必须是网络序列的 // ??// local.sin_addr.s_addr = htonl(INADDR_ANY);if(bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0){lg(Fatal, "bind error, errno: %d, err string: %s", errno, strerror(errno));exit(BIND_ERR);}lg(Info, "bind success, errno: %d, err string: %s", errno, strerror(errno));}void Run(func_t func) // 对代码进行分层{isrunning_ = true;char inbuffer[size];while(isrunning_){struct sockaddr_in client;socklen_t len = sizeof(client);ssize_t n = recvfrom(sockfd_, inbuffer, sizeof(inbuffer) - 1, 0, (struct sockaddr*)&client, &len);if(n < 0){lg(Warning, "recvfrom error, errno: %d, err string: %s", errno, strerror(errno));continue;}inbuffer[n] = 0;std::string info = inbuffer;std::string echo_string = func(info);sendto(sockfd_, echo_string.c_str(), echo_string.size(), 0, (const sockaddr*)&client, len);}}~UdpServer(){if(sockfd_>0) close(sockfd_);}
private:int sockfd_;     // 网路文件描述符std::string ip_; // 任意地址bind 0uint16_t port_;  // 表明服务器进程的端口号bool isrunning_;
};
  • Init 方法用于初始化 UDP 服务器:
    • 调用 socket 函数创建一个 UDP 套接字,使用 AF_INET 表示 IPv4 协议族,SOCK_DGRAM 表示 UDP 套接字。
    • 如果套接字创建失败,使用日志记录错误信息并退出程序。
    • 创建一个 sockaddr_in 结构体 local,用于存储服务器的地址信息。
    • 使用 bzero 函数将 local 结构体清零。
    • 设置 local 结构体的 sin_family 为 AF_INETsin_port 为传入的端口号,并使用 htons 函数将其转换为网络字节序。
    • 使用 inet_addr 函数将传入的 IP 地址字符串转换为网络字节序的 32 位整数,并赋值给 sin_addr.s_addr
    • 调用 bind 函数将套接字绑定到指定的地址和端口。
    • 如果绑定失败,使用日志记录错误信息并退出程序。
  • Run 方法用于启动 UDP 服务器并处理客户端请求:
    • 将 isrunning_ 标志设置为 true,表示服务器正在运行。
    • 创建一个大小为 size 的字符数组 inbuffer,用于存储接收到的数据。
    • 进入一个无限循环,不断接收客户端发送的数据。
    • 调用 recvfrom 函数接收客户端发送的数据,并将客户端的地址信息存储在 client 结构体中。
    • 如果接收失败,使用日志记录错误信息并继续下一次循环。
    • 在接收到的数据末尾添加字符串结束符 '\0',将其转换为 std::string 类型的 info
    • 调用传入的函数对象 func 对接收到的数据进行处理,并将处理结果存储在 echo_string 中。
    • 调用 sendto 函数将处理结果发送回客户端。

2.客户端

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>using namespace std;void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}// ./udpclient serverip serverport
int main(int argc, char *argv[])
{if (argc != 3){Usage(argv[0]);exit(0);}std::string serverip = argv[1];uint16_t serverport = std::stoi(argv[2]);struct sockaddr_in server;bzero(&server, sizeof(server));server.sin_family = AF_INET;server.sin_port = htons(serverport); //?server.sin_addr.s_addr = inet_addr(serverip.c_str());socklen_t len = sizeof(server);int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){cout << "socker error" << endl;return 1;}// client 要bind吗?要!只不过不需要用户显示的bind!一般有OS自由随机选择!// 一个端口号只能被一个进程bind,对server是如此,对于client,也是如此!// 其实client的port是多少,其实不重要,只要能保证主机上的唯一性就可以!// 系统什么时候给我bind呢?首次发送数据的时候string message;char buffer[1024];while (true){cout << "Please Enter@ ";getline(cin, message);// std::cout << message << std::endl;// 1. 数据 2. 给谁发sendto(sockfd, message.c_str(), message.size(), 0, (struct sockaddr *)&server, len);struct sockaddr_in temp;socklen_t len = sizeof(temp);ssize_t s = recvfrom(sockfd, buffer, 1023, 0, (struct sockaddr*)&temp, &len);if(s > 0){buffer[s] = 0;cout << buffer << endl;}}close(sockfd);return 0;
}
  • argc 表示命令行参数的数量,argv 是一个字符串数组,存储了命令行参数。
  • 如果命令行参数数量不等于 3(程序名、服务器 IP 地址、服务器端口号),则调用 Usage 函数打印使用说明并退出程序。
  • 从命令行参数中获取服务器的 IP 地址和端口号。
  • std::stoi 函数将字符串类型的端口号转换为 uint16_t 类型。
  • 创建一个 sockaddr_in 结构体 server,用于存储服务器的地址信息。
  • bzero 函数将 server 结构体的内存清零。
  • server.sin_family 设置为 AF_INET,表示使用 IPv4 地址族。
  • server.sin_port 使用 htons 函数将端口号从主机字节序转换为网络字节序。
  • server.sin_addr.s_addr 使用 inet_addr 函数将字符串类型的 IP 地址转换为网络字节序的 32 位整数。
  • len 存储 server 结构体的大小。
  • socket 函数创建一个 UDP 套接字,使用 AF_INET 表示 IPv4 地址族,SOCK_DGRAM 表示 UDP 协议。
  • 如果套接字创建失败,输出错误信息并返回 1。
  • 创建一个 std::string 类型的 message 用于存储用户输入的消息,创建一个字符数组 buffer 用于存储从服务器接收的数据。
  • 使用 getline 函数从标准输入读取用户输入的消息。
  • sendto 函数将消息发送给服务器,指定套接字描述符、消息内容、消息长度、标志位、服务器地址结构体和地址结构体的大小。
  • 创建一个 sockaddr_in 结构体 temp 用于存储服务器的地址信息,len 存储 temp 结构体的大小。
  • recvfrom 函数从服务器接收数据,指定套接字描述符、接收缓冲区、缓冲区大小、标志位、服务器地址结构体指针和地址结构体大小指针。
  • 如果接收到的数据长度大于 0,在缓冲区末尾添加字符串结束符 '\0',并输出接收到的数据。

总结

该程序实现了一个简单的 UDP 客户端,通过命令行参数指定服务器的 IP 地址和端口号,从用户输入获取消息并发送给服务器,同时接收服务器的响应并输出。客户端不需要显式绑定端口,操作系统会在首次发送数据时自动分配一个可用的端口。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言学习强化

前言 数据的逻辑结构包括&#xff1a; 常见数据结构&#xff1a; 线性结构&#xff1a;数组、链表、队列、栈 树形结构&#xff1a;树、堆 图形结构&#xff1a;图 一、链表 链表是物理位置不连续&#xff0c;逻辑位置连续 链表的特点&#xff1a; 1.链表没有固定的长度…

【ArcGIS微课1000例】0141:提取多波段影像中的单个波段

文章目录 一、波段提取函数二、加载单波段导出问题描述:如下图所示,img格式的时序NDVI数据有24个波段。现在需要提取某一个波段,该怎样操作? 一、波段提取函数 首先加载多波段数据。点击【窗口】→【影像分析】。 选择需要处理的多波段影像,点击下方的【添加函数】。 在多…

css3 svg制作404页面动画效果HTML源码

源码介绍 css3 svg制作404页面动画效果HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果 效果预览 源码如下 <!doctype html> <html> <head> <meta charse…

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…

利用Qt5.15.2编写Android程序时遇到的问题及解决方法

文章目录 背景1.文件读写 背景 目前我用的是Qt5.15.2来编写Qt程序&#xff0c;环境的配置看我这篇文章【Qt5.15.2配置Android开发环境】 项目中的一些配置的截图&#xff1a; 1.文件读写 假如直接用 QFileDialog::getExistingDirectory来获取路径的话&#xff0c;会得到类…

【学术会议-第五届机械设计与仿真国际学术会议(MDS 2025) 】前端开发:技术与艺术的完美融合

重要信息 大会官网&#xff1a;www.icmds.net 大会时间&#xff1a;2025年02月28日-03月02日 大会地点&#xff1a;中国-大连 会议简介 2025年第五届机械设计与仿真国际学术会议&#xff08;MDS 2025) 将于2025年02月28-3月02日在中国大连召开。MDS 2025将围绕“机械设计”…

leetcode刷题记录(一百)——121. 买卖股票的最佳时机

&#xff08;一&#xff09;问题描述 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09;121. 买卖股票的最佳时机 - 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票&#xff0c;并…

亲测有效!解决PyCharm下PyEMD安装报错 ModuleNotFoundError: No module named ‘PyEMD‘

解决PyCharm下PyEMD安装报错 PyEMD安装报错解决方案 PyEMD安装报错 PyCharm下通过右键自动安装PyEMD后运行报错ModuleNotFoundError: No module named ‘PyEMD’ 解决方案 通过PyCharm IDE python package搜索EMD-signal&#xff0c;选择版本后点击“install”执行安装

上海亚商投顾:沪指冲高回落 大金融板块全天强势 上海亚商投

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一&#xff0e;市场情绪 市场全天冲高回落&#xff0c;深成指、创业板指午后翻绿。大金融板块全天强势&#xff0c;天茂集团…

【unity游戏开发之InputSystem——02】InputAction的使用介绍(基于unity6开发介绍)

文章目录 前言一、InputAction简介1、InputAction是什么&#xff1f;2、示例 二、监听事件started 、performed 、canceled1、启用输入检测2、操作监听相关3、关键参数 CallbackContext4、结果 三、InputAction参数相关1、点击齿轮1.1 Actions 动作&#xff08;1&#xff09;动…

ubuntu22安装issac gym记录

整体参考&#xff1a;https://blog.csdn.net/Yakusha/article/details/144306858 安装完成后的整体版本信息 ubuntu&#xff1a;22.04内核&#xff1a;6.8.0-51-generic显卡&#xff1a;NVIDIA GeForce RTX 3050 OEM显卡驱动&#xff1a;535.216.03cuda&#xff1a;12.2cudnn&…

Linux下Ubuntun系统报错find_package(BLAS REQUIRED)找不到

Linux下Ubuntun系统报错find_package(BLAS REQUIRED)找不到 这次在windows的WSL2中遇到了一个非常奇怪的错误&#xff0c;就是 CMake Error at /usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):Could NOT find BLAS (missing: BLAS_LIBRAR…

15天基础内容-5

day13 【String类、StringBuilder类】 主要内容 String类常用方法【重点】 String类案例【重点】 StringBuilder类【重点】 StringBuilder类常用方法【重点&#xff1a; append】 StringBuilder类案例【理解】 第一章String类 1.1 String类的判断方法 String类实现判断功能…

CommonAPI学习笔记-1

CommonAPI学习笔记-1 一. 整体结构 CommonAPI分为两层&#xff1a;核心层和绑定层&#xff0c;使用了Franca来描述服务接口的定义和部署&#xff0c;而Franca是一个用于定义和转换接口的框架&#xff08;https://franca.github.io/franca/&#xff09;。 ​ 核心层和通信中间…

单片机基础模块学习——DS18B20温度传感器芯片

不知道该往哪走的时候&#xff0c;就往前走。 一、DS18B20芯片原理图 该芯片共有三个引脚&#xff0c;分别为 GND——接地引脚DQ——数据通信引脚VDD——正电源 数据通信用到的是1-Wier协议 优点&#xff1a;占用端口少&#xff0c;电路设计方便 同时该协议要求通过上拉电阻…

Golang Gin系列-9:Gin 集成Swagger生成文档

文档一直是一项乏味的工作&#xff08;以我个人的拙见&#xff09;&#xff0c;但也是编码过程中最重要的任务之一。在本文中&#xff0c;我们将学习如何将Swagger规范与Gin框架集成。我们将实现JWT认证&#xff0c;请求体作为表单数据和JSON。这里唯一的先决条件是Gin服务器。…

< OS 有关 > 阿里云:轻量应用服务器 的使用 :轻量化 阿里云 vpm 主机

原因&#xff1a; &#xff1c; OS 有关 &#xff1e; 阿里云&#xff1a;轻量应用服务器 的使用 &#xff1a;从新开始 配置 SSH 主机名 DNS Tailscale 更新OS安装包 最主要是 清除阿里云客户端这个性能杀手-CSDN博客 防止 I/O 祸害系统 操作&#xff1a; 查看进程&#x…

设计模式的艺术-代理模式

结构性模式的名称、定义、学习难度和使用频率如下表所示&#xff1a; 1.如何理解代理模式 代理模式&#xff08;Proxy Pattern&#xff09;&#xff1a;给某一个对象提供一个代理&#xff0c;并由代理对象控制对原对象的引用。代理模式是一种对象结构型模式。 代理模式类型较多…

K8S极简教程(4小时快速学会)

1. K8S 概览 1.1 K8S 是什么 K8S官网文档&#xff1a;https://kubernetes.io/zh/docs/home/ 1.2 K8S核心特性 服务发现与负载均衡&#xff1a;无需修改你的应用程序即可使用陌生的服务发现机制。存储编排&#xff1a;自动挂载所选存储系统&#xff0c;包括本地存储。Secret和…

python3+TensorFlow 2.x(五)CNN

目录 CNN理解 code实现人脸识别 数据集准备&#xff1a; code实现 模型解析 结果展示 结果探讨 基于vgg16的以图搜图 数据准备 图库database 检索测试集datatest code实现 code解析 结果展示 CNN理解 卷积神经网络&#xff08;CNN&#xff09;是深度学习中最强大…