当前位置: 首页 > news >正文

34.Socket编程(UDP)(上)

点分十进制字符串IP 转 32位网络序列IP

分析:1)IP转成4字节        2)4字节转成网络序列

思路:

  • "192.168.1.1" 进行字符串划分,以 "." 为分割符,分割出"192","168","1","1"
  • 将这些字符串转成8位的整型(字符),192,168,1,1
  • 网络字节序是大端,高权值位放在低地址,定义一个32位整型(变量内字节地址是依次增大,取地址是最小地址),192放取地址的第一个字节,168第二个字节,以此类推。

或者用 inet_addr(),将ip点分十进制字符串传入,返回值4字节网络字节序。

接口使用

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

  • sockfd:创建套接字打开的文件fd
  • buf:接受缓冲区
  • len:接受缓冲区大小
  • flags:0,表示阻塞式IO
  • src_addr:输出型参数,用来获取客户端的套接字信息(IP和端口)
  • addrlen:先是输入型参数,src_addr指向结构体大小,后是输出型参数,实际读到信息大小
  • 返回值:成功,返回接受到数据的字节数;失败-1返回

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

  • sockfd:创建套接字打开的文件fd
  • buf:发送缓冲区
  • len:发送缓冲区大小
  • flags:0,表示阻塞式IO
  • src_addr:输入型参数,指定发给哪一个客户端
  • addrlen:src_addr指向的结构体大小
  • 返回值:成功,发送的字节数;失败-1返回,错误码被设置

客户端如何知道服务端IP和端口

客户端和服务端是一家公司写的,内置了服务端的IP和端口

本地环回(localhost, 127.0.0.1)

        本地环回:要求客户端和服务端必须在一台机器上,表明我们是本地通信,client发送的数据,不会被推送到网络,而是在OS内部,转一圈直接交给对应的服务器端(经常用来进行网络代码的测试)

服务端bind时不显式绑定IP

bind公网IP,不行的原因:公网IP没有配置到IP上,同一主机绑定时,无法直接bind。

如果我们显式进行地址绑定,client未来访问时,就必须使用server绑定的信息。

为什么不建议手动绑定特定IP?

        因为一台主机可以有多个IP,绑定特定IP,只能接受该IP的数据,而发给其他本主机IP的数据接收不了。

做法:绑定IP时,值设置为 INADDR_ANY(任意IP地址bind,数值上为0)

客户端不用显式bind

  • client需不需要bind?需要bind
  • client需不需要显式bind?不需要,首次发送消息OS会自动给client进行bind,OS知道IP,端口号采用随机端口号的方式。(端口号是几不重要,唯一就行了)
  • 原因:
    1. 一个端口号只能被一个进程所持有(端口号要找到唯一一个进程)
    2.未来有很多应用,端口号固定可能会导致冲突,无法bind,必须由OS随机分配

UdpSocket编程V1(EchoServer)

Linux-remote: linux远程仓库

UdpServer.hpp

#pragma once#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <functional>
#include "Log.hpp"using namespace LogModule;#define BUFF_SIZE 1024
const int defaultfd = -1;class UdpServer
{using func_t = std::function<std::string(const std::string &)>;
public:UdpServer(uint16_t port, func_t func): _sockfd(defaultfd), _port(port), _isrunning(false), _func(func){// 1.创建套接字,(网络类型,UDP协议)获取网络文件描述符_sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (_sockfd < 0){LOG(LogLevel::FATAL) << "socket error";exit(1);}LOG(LogLevel::INFO) << "socket success, sockfd: " << _sockfd;// 2.bind,绑定(通信类型,端口号port,IP)// 2.1 创建结构sockaddr_in, (man inet_addr),填充字段struct sockaddr_in peer;peer.sin_family = AF_INET;peer.sin_port = htons(_port);// 2.2 ip地址是一个结构,结构存放一个32位无符号整数// ip是一个字符串,192.168.1.1, 1.转成数字 2.转成网络序列 -> inet_addr// peer.sin_addr.s_addr = inet_addr(_ip.c_str());peer.sin_addr.s_addr = INADDR_ANY; // 任意IP// 2.3 绑定int n = bind(_sockfd, (struct sockaddr *)&peer, sizeof(peer));if (n < 0){LOG(LogLevel::FATAL) << "bind error";exit(2);}LOG(LogLevel::INFO) << "bind success, sockfd: " << _sockfd;}void Start(){_isrunning = true;while (_isrunning){// 3.服务端收数据char buff[BUFF_SIZE];struct sockaddr_in peer;socklen_t addrlen = sizeof(struct sockaddr_in);ssize_t n = recvfrom(_sockfd, buff, BUFF_SIZE, 0,(struct sockaddr *)&peer, &addrlen);// 4.消息处理buff[n] = 0;std::string data = buff;LOG(LogLevel::INFO) << "client Says: " << data;std::string result = _func(data);// 5.服务端发送数据回客户端ssize_t ret = sendto(_sockfd, result.c_str(), result.size(), 0, (const struct sockaddr *)&peer, addrlen);(void)ret;}}~UdpServer(){}private:int _sockfd;uint16_t _port;// std::string _ip;  //不需要,任意IPbool _isrunning;func_t _func;
};

UdpClient.cc

#include <iostream>
#include <string>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"using namespace LogModule;// ./udpclient server_ip server_port
int main(int argc, char *argv[])
{if (argc != 3){std::cerr << "Usage: " << argv[0] << " server_ip server_port" << std::endl;return 1;}std::string ip = argv[1];uint16_t port = (uint16_t)(std::stoi(argv[2]));LOG(LogLevel::DEBUG) << "ip: " << ip << " port:" << port;// 1.创建socket,(网络类型,UDP)int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){LOG(LogLevel::FATAL) << "socket error";exit(1);}LOG(LogLevel::INFO) << "socket success, sockfd: " << sockfd;// 2.绑定参数,bind,不用显式绑定。// 首次发送消息时由OS自动绑定,OS知道IP,端口号由OS随机分配struct sockaddr_in peer;peer.sin_family = AF_INET;peer.sin_port = htons(port);peer.sin_addr.s_addr = inet_addr(ip.c_str());while (true){// 3.客户端发数据// 3.1 从标准输入按行读数据std::cout << "Please Enter# ";std::string data;std::getline(std::cin, data);// 3.2 发送数据给服务端ssize_t ret = sendto(sockfd, data.c_str(), data.size(), 0, (struct sockaddr *)&peer, sizeof(peer));(void)ret;// 4.接受服务端处理过的数据char buff[1024];struct sockaddr_in sin;socklen_t len = sizeof(struct sockaddr_in);ssize_t n = recvfrom(sockfd, buff, 1024, 0, (struct sockaddr *)&sin, &len);// 5.使用数据buff[n] = 0;std::cout << "Server handlered, data: " << buff << std::endl;}return 0;
}

UdpServer.cc

#include "UdpServer.hpp"
#include <iostream>
#include <memory>std::string Hello(const std::string &data)
{std::string hello("Hello, ");hello += data;return hello;
}// ./udpserver port
int main(int argc, char *argv[])
{if (argc != 2){std::cerr << "Usage: " << argv[0] << " port" << std::endl;return 1;}uint16_t port = (uint16_t)std::stoi(argv[1]);std::unique_ptr<UdpServer> udpserver = std::make_unique<UdpServer>(port, Hello);udpserver->Start();return 0;
}

文章转载自:

http://qJyS63pt.tdwgx.cn
http://TzI3QCxW.tdwgx.cn
http://3IPbcNUe.tdwgx.cn
http://uRMEN3bn.tdwgx.cn
http://8xYHZlcF.tdwgx.cn
http://ES2bITWA.tdwgx.cn
http://n7uFcMFI.tdwgx.cn
http://AycxKi8o.tdwgx.cn
http://Qc8ATWW1.tdwgx.cn
http://5wAvVkgF.tdwgx.cn
http://l2SR0p9n.tdwgx.cn
http://Hi2tbtWp.tdwgx.cn
http://IOZ1e9BQ.tdwgx.cn
http://LA6NZ152.tdwgx.cn
http://epSrgDIH.tdwgx.cn
http://t9CrW1fQ.tdwgx.cn
http://cIQVxcfH.tdwgx.cn
http://8eOotNym.tdwgx.cn
http://A4mSUTDQ.tdwgx.cn
http://GZ3Jz7SP.tdwgx.cn
http://VOwBOIko.tdwgx.cn
http://r52TYTmC.tdwgx.cn
http://fQM66TO7.tdwgx.cn
http://LvDJnFLB.tdwgx.cn
http://vOTGEfdX.tdwgx.cn
http://e5gWOCSZ.tdwgx.cn
http://sjGiKv9p.tdwgx.cn
http://dRWOWJ4s.tdwgx.cn
http://IhbBns7s.tdwgx.cn
http://ucsmAiji.tdwgx.cn
http://www.dtcms.com/a/384969.html

相关文章:

  • 综合篇| 智能体平台dify、coze和n8n对比
  • Crond服务
  • LazyVim设置tab
  • 【无标题】好吧
  • 【Git】零基础入门:配置与初始操作实战指南
  • 云手机兼容性对游戏的重要性
  • Vue-color:Vue.js 专业颜色选择器组件库 – 支持Vue2/3,TypeScript,暗色主题
  • IntelliJ IDEA 的 Git 功能
  • 【更新至2024年】2009-2024年上市公司排污环保费用数据
  • Nmap图形化扫描工具 | 集成资产定期监控功能
  • 讲一讲cot蒸馏以及grpo的方式训练模型
  • 面试之Java基础
  • LeetCode 3325.字符至少出现K次的子字符串 I
  • 【Linux命令从入门到精通系列指南】cp 命令详解
  • Oracle重做日志(Redo Log):数据一致性的“守护者“
  • Linux的生产者消费者模型
  • 深度学习基础、pytorch使用①
  • 国产化PDF处理控件Spire.PDF教程:在 ASP.NET Core 中创建 PDF的分步指南
  • 某村通信网络改造:从痛点到解决方案的全景分析
  • Elastic APM 入门指南:快速设置应用性能监控
  • 流式响应的demo , 前端markdown格式显示, 打字机效果展示
  • 【免费体验】旗讯 OCR手写识别:破解工厂数据处理痛点,实现从 “人工录入” 到 “AI读单” 的升级
  • 远程开机wakeonlan
  • 健康有益:车载健康化系统推动智能汽车健康管理新变革
  • JavaWeb--day6--MySQL(补漏)
  • 手机群控平台的智能管控技术深度解析
  • 什么是手持采集终端PDA?智慧移动工作的数字基石!
  • C语言中的递归问题——爬楼梯问题
  • LeetCode:2.字母异位词分组
  • 计算机视觉案例分享之实时文档扫描