【网络】:网络套接字(UDP)

news2024/10/7 2:22:51

网络套接字

  • 一.网络字节序
  • 二.端口号
  • 三.socket
    • 1.常见的API
    • 2.封装UdpSocket
  • 四.地址转换函数

网络通信的本质就是进程间通信。

一.网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分,网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  1. 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  2. 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  3. 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  4. TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  5. 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  6. 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。

在这里插入图片描述

这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回 ; 如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。

二.端口号

在进行网络通信中,下三层主要解决的是数据可靠的传输到远端机器,而应用层主要是来处理数据的。而应用层有很多程序,例如:微信,抖音…底层如何知道这个数据传给哪一个呢?这时就要引入端口号了。

在这里插入图片描述

端口号(port)是传输层协议的内容:

  1. 端口号是一个2字节16位的整数;
  2. 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  3. IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  4. 一个端口号只能被一个进程占用

在这里插入图片描述

IP地址能表示唯一的主机,port端口号能标识该主机上唯一的进程。当两者连在一起时,我们就能准确的找到目的机器的具体接收信息的应用了。这种IP+port方式就叫做socket.

三.socket

1.常见的API

在这里插入图片描述

socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4,IPv6,以及后面要讲的UNIX DomainSocket. 然而, 各种网络协议的地址格式并不相同

在这里插入图片描述

  1. IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.
  2. IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
  3. socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数;

2.封装UdpSocket

#pragma once

#include<iostream>
#include<sys/types.h>
#include<sys/socket.h>
#include<strings.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<string.h>
#include "log.hpp"

extern Log log;

std::string defaultip="0.0.0.0";
uint16_t defaultport=8080;
const int size=1024;

enum{
  SOCKET_ERR=1,
  BIND_ERR
};

class UdpServer
{
public:
  //初始化端口号,ip号
  UdpServer(const uint16_t &port=defaultport,const std::string &ip=defaultip): port_(port),ip_(ip)
  {}
  void init()
  {
    //创建udp socket
    sockfd_=socket(AF_INET,SOCK_DGRAM,0);
    if(socket<0)//创建失败
    {
      log(Fatal,"socket create error: %d",sockfd_);
      exit(SOCKET_ERR);
    }
    log(Info,"create socket sucess:%d",sockfd_);

    //绑定端口号
    struct sockaddr_in local;
    //将该结构体内部清零
    bzero(&local,sizeof(local));
    //填充结构体

    local.sin_family=AF_INET;//表明自己的结构体类型
    local.sin_port=htons(port_);//绑定的端口号,需要保证我的端口号是网络字节序列(大端),因为要发送给对方,所以htos转换
    local.sin_addr.s_addr=inet_addr(ip_.c_str());//绑定的ip,1.ting->uint_32 2.必须是网络序列的

    //上面的全部定义在用户栈上,并没有与内核绑定
    //绑定内核
    int n=bind(sockfd_,(const struct sockaddr*)&local,sizeof(local));
    if(n<0)//绑定失败
    {
      log(Fatal,"bind error,error:%s",strerror(errno));
      exit(BIND_ERR);
    }
    log(Info,"bind sucess:%d",sockfd_);
  }

  void run()
  {
    isrunning=true;

    while(isrunning)
    {
      char inbuffer[size];
      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)
      {
        log(Warning,"recvform err,err string:%s",strerror(errno));
        continue;
      }
      inbuffer[n]=0;

      //简单的数据处理
      std::string info=inbuffer;
      std::string echo_string="server echo"+info;

      //将数据发回
      sendto(sockfd_,echo_string.c_str(),echo_string.size(),0,(const sockaddr*)&client,len);
    }

  }


  ~UdpServer()
  {}

private:
  int sockfd_;//网络文件描述符
  uint16_t port_;//端口号
  std::string ip_;//ip号
  bool isrunning;
};

可以使用netstat -naup查看是否启动成功。

在这里插入图片描述

四.地址转换函数

本节只介绍基于IPv4的socket网络编程,sockaddr_in中的成员struct in_addr sin_addr表示32位 的IP 地址但是我们通常用点分十进制的字符串表示IP 地址,以下函数可以在字符串表示 和in_addr表示之间转换;

字符串转in_addr的函数:

在这里插入图片描述

in_addr转字符串的函数:

在这里插入图片描述

其中inet_pton和inet_ntop不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此函数接口是void*addrptr。

关于ntoa

inet_ntoa这个函数返回了一个char*, 很显然是这个函数自己在内部为我们申请了一块内存来保存ip的结果.
那么是否需要调用者手动释放呢?

在这里插入图片描述

man手册上说, inet_ntoa函数, 是把这个返回结果放到了静态存储区. 这个时候不需要我们手动进行释放.

那么问题来了, 如果我们调用多次这个函数, 会有什么样的效果呢? 参见如下代码:

在这里插入图片描述

在这里插入图片描述

因为inet_ntoa把结果放到自己内部的一个静态存储区, 这样第二次调用时的结果会覆盖掉上一次的结果.

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

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

相关文章

中间件安全

中间件安全 vulhub漏洞复现&#xff1a;https://vulhub.org/操作教程&#xff1a;https://www.freebuf.com/sectool/226207.html 一、Apache Apache(音译为阿帕奇)是世界使用排名第一的Web服务器软件。它可以运行在几乎所有广泛使用的计算机平台上&#xff0c;由于其跨平台和…

解决ubuntu 在VMware Workstation Pro下显示不完整的问题

步骤一 ctrlaltT 打开终端&#xff0c;输入&#xff1a; xrandr -s 1920x1080如果报错就输入xrandr,从里面选择适合的分辨率 注意是字母x不是乘号 步骤二 按win键&#xff0c;在搜索框搜索resolution更改显示器分辨率&#xff1a; 选择与电脑相同的分辨率&#xff0c;点击…

构造器模式

构造器模式 意图 将一个复杂对象的构建和表示分离&#xff0c;使得相同的构建能创建不同的表示。 解释 案例&#xff1a;想象一个角色扮演游戏的特征生成器。最简单的选择是让计算机为你创建角色。如果你想手动选择特征的细节像职业、性别、头发的颜色等。特征的产生是一个循…

基于java与vue的生鲜物流系统的设计与实现-计算机毕业设计源码13339

摘要 生鲜产品易于腐烂、难贮存、不易长时间运输&#xff0c;生产者所面临的市场风险很大&#xff0c;很多生鲜产品无法实现“货畅其流”和“物尽其值”&#xff0c;适宜的生鲜产品物流体系就显得尤为重要。本文将广东省生鲜产品物流体系的构建作为一个例子进行系统研究。首先对…

Stable Diffusion 笔记一:网络结构拆解

SD由三大组件组成&#xff1a;VAE&#xff0c;CLIP&#xff0c;Unet。 一VAE&#xff1a; VAE是Variational Autoencoder的缩写&#xff0c;中文名变分自编码器&#xff0c;是一种基于深度学习的生成模型。 &#xff11;潜空间图片与像素图片&#xff1a; 像素图片是正常使…

(九)springboot实战——springboot3下的webflux项目参数验证及其全局参数验证异常处理

前言 在上一节内容中&#xff0c;我们介绍了如何在webflux项目中自定义实现一个全局的异常处理器ErrorWebExceptionHandler&#xff0c;正常情况下其可以处理我们系统的运行时异常&#xff0c;但是无法处理参数验证的异常WebExchangeBindException&#xff0c;所以这里提供另外…

Amazon CodeWhisperer 代码提示——Golang 测评

前言 官网链接&#xff1a; 亚马逊云科技 Amazon CodeGuru Reviewer 中的 CodeWhisperer 是一种代码提示工具&#xff0c;它使用机器学习和人工智能技术来提高开发人员的代码质量和效率。它可以通过分析代码库中的历史代码和最佳实践&#xff0c;为开发人员提供有关如何改进其…

vue预览pdf文件的几种方法

文章目录 vue预览pdf集中方法方法一&#xff1a;方法二&#xff1a;展示效果&#xff1a;需要包依赖&#xff1a;代码&#xff1a; 方法三&#xff1a;展示效果&#xff1a;需要包依赖&#xff1a;代码&#xff1a;自己调参数&#xff0c;选择符合自己的 vue预览pdf集中方法 我…

selenium-Web界面搜索功能测试

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号&#xff1a;互联网杂货铺&#xff0c;回复1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;薪资嘎嘎涨 测试环境准备&#xff1a; 1、安装Python 2、安装Ch…

C++面试宝典第25题:阶乘末尾零的个数

题目 给定一个整数n,返回n!(n的阶乘)结果尾数中零的个数。 示例 1: 输入:3 输出:0 解释:3! = 6,尾数中没有零。 示例 2: 输入:5 输出:1 解释:5! = 120,尾数中有1个零。 解析 这道题主要考察应聘者对于数学问题的分析和理解能力,以及在多个解决方案中,寻求最优…

Python 拼接字符串的 7 种方式

忘了在哪看到一位编程大牛调侃&#xff0c;他说程序员每天就做两件事&#xff0c;其中之一就是处理字符串。相信不少同学会有同感。 几乎任何一种编程语言&#xff0c;都把字符串列为最基础和不可或缺的数据类型。而拼接字符串是必备的一种技能。今天&#xff0c;我跟大家一起来…

Github 2024-01-28 开源项目日报Top10

根据Github Trendings的统计&#xff0c;今日(2024-01-28统计)共有10个项目上榜。根据开发语言中项目的数量&#xff0c;汇总情况如下&#xff1a; 开发语言项目数量Python项目3TypeScript项目2Rust项目1HTML项目1JavaScript项目1Cuda项目1C#项目1非开发语言项目1 Nuxt&#…

Spring Boot通过配置文件支持数据库自定义表名

直接上干货&#xff1a; 例如一个叫xxx的项目&#xff0c;yml文件里加上这段 xxxproject:db:xxxTable: xxx_dbname #自定义的数据库表名创一个Configuration类放表名和Mapper // XxxProjectAutoConfiguration.javaConfiguration MapperScan(basePackages "cn.com.xxxp…

蓝牙----蓝牙连接建立_连接建立

蓝牙----蓝牙连接建立_连接建立 蓝牙连接建立过程图1.主机扫描到广播包1.1判断是否是自己关心的广播包1.2广播地址添加到扫描列表 2.主机扫描结束&#xff0c;建立连接3.主从连接成功后&#xff0c;执行连接建立后事件3.1.主机将连接句柄和设备地址添加到连接列表3.2.主机进行G…

ad18学习笔记十六:v割

所谓“V割”是印刷电路板&#xff08;PCB&#xff09;厂商依据客户的图纸要求&#xff0c;事先在PCB的特定位置用转盘刀具切割好的一条条分割线&#xff0c;其目的是为了方便后续SMT电路板组装完成后的分板之用&#xff0c;因为其切割后的外型看起来就像个英文的“V”字型&…

msfconsole实战使用(结合靶场演示)

msfconsole实战使用 前言 MSFconsole&#xff08;Metasploit Framework Console&#xff09;是Metasploit框架的一部分&#xff0c;是一个功能强大的渗透测试工具。Metasploit框架是一个开源的安全工具&#xff0c;旨在开发、测试和执行针对计算机系统的攻击。MSFconsole是Me…

SpringMvc切换Json转换工具

SpringBoot切换使用goolge的Gson作为SpringMvc的Json转换工具 <!-- gson依赖 --> <dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId> </dependency>Configuration public class JsonWebConfig {B…

ThreadLocal学习笔记

ThreadLocal类图 ThreadLocal/InheritableThreadLocal/ \TransmittableThreadLocal(阿里巴巴) TransmissibleThreadLocal(阿里巴巴)ThreadLocal 这是Thread类的局部变量&#xff0c;每个线程私有。 它主要用于解决多线程中的数据共享问题&#xff0c;保…

把数组中的key都取出来然后去重

今日接到一个小需求&#xff0c;一张表有类似这样的数据&#xff1a;&#xff08;下面是一行&#xff09; 但是每行的数据&#xff0c;主要是key不一样&#xff0c;我们想把所有的key取出来&#xff0c;并且做个去重。 首先我先在mysql中&#xff0c; SELECT GROUP_CONCAT(RE…

在租户内启用SharePoint Embedded

要开启 SharePoint Embedded&#xff0c;你得是管理员&#xff0c;然后按照这些步骤操作&#xff1a; 登录到你的 SharePoint 管理中心。在左边的菜单里找到“设置”选项&#xff0c;点进去。 3. 在设置页面里找到“SharePoint Embedded 应用”。 4.如果这个功能还没开启&…