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

网络套接字

  • 一.网络字节序
  • 二.端口号
  • 三.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把结果放到自己内部的一个静态存储区, 这样第二次调用时的结果会覆盖掉上一次的结果.

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

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

相关文章

数据结构----链表介绍、模拟实现链表、链表的使用

文章目录 1. ArrayList存在的问题2. 链表定义2.1 链表的概念及结构2.2 链表的组合类型 3. 链表的实现3.1 单向、不带头、非循环链表的实现3.2 双向、不带头节点、非循环链表的实现 4.LinkedList的使用4.1 什么是LinkedList4.2 LinkedList的使用4.2.1. LinkedList的构造4.2.2. L…

npm 淘宝镜像正式到期

由于node安装插件是从国外服务器下载&#xff0c;如果没有“特殊手法”&#xff0c;就可能会遇到下载速度慢、或其它异常问题。 所以如果npm的服务器在中国就好了&#xff0c;于是我们乐于分享的淘宝团队干了这事。你可以用此只读的淘宝服务代替官方版本&#xff0c;且同步频率…

Docker 数据管理、容器互联、网络与资源控制

一、docker数据管理 管理 Docker 容器中数据主要有两种方式&#xff1a;数据卷(Data volumes)和数据卷容器(Datavolumes containers)。 1、数据卷 数据卷是一个供容器使用的特殊目录&#xff0c;位于容器中。可将宿主机的目录挂载到数据卷上&#xff0c;对数据卷的修改操作立…

seata 分布式

一、下载安装seata 已经下载好的朋友可以跳过这个步骤。这里下载的是seata1.6.1这个版本。 1、进入seata官网 地址&#xff1a; https://seata.io/zh-cn/index.html 2、进入下载 3、点击下载地址 下载地址&#xff1a; https://github.com/seata/seata 二、配置seata 进入c…

​ PaddleHub 首页图像 - 文字识别chinese_ocr_db_crnn_server​

PaddleHub 便捷地获取PaddlePaddle生态下的预训练模型&#xff0c;完成模型的管理和一键预测。配合使用Fine-tune API&#xff0c;可以基于大规模预训练模型快速完成迁移学习&#xff0c;让预训练模型能更好地服务于用户特定场景的应用 零基础快速开始WindowsLinuxMac Paddle…

MacOS安装反编译工具JD-GUI以及解决无法打开的问题

目录 一.下载地址 二.安装 三.问题 四.解决办法 1.显示包内容 2.找到Contents/MacOS/universalJavaApplicationStub.sh 3.修改sh文件 4.保存后再次打开即可 一.下载地址 Java Decompiler 二.安装 将下载下来的 jd-gui-osx-1.6.6.tar 解压&#xff0c;然后将 JD-GUI.a…

驾驭AI绘画:《AI魔法绘画》带你秒变顶级画手!

大家好&#xff0c;我是herosunly。985院校硕士毕业&#xff0c;现担任算法研究员一职&#xff0c;热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名&#xff0c;CCF比赛第二名&#xff0c;科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的…

C++笔试强训选择题7

1.对于以下代码&#xff0c;说法正确的是&#xff08;&#xff09; char * p new char[100]&#xff1b;A p 和 new出来的内存都在栈上 B p 和 new出来的内存都在堆上 C p在栈上 new出来的在堆上 D p在堆上 new出来的在栈上 new默认情况下申请的空间在堆上 2. 类模板的使用…

微信小程序~上推加载更多组件

本组件使用的是TaroReact 实现的 &#xff0c;具体代码如下 一共分为tsx和less文件 //index.tsx /** RefreshLoading* description 上推加载更多组件* param loading boolean* param style* returns*/import { View } from "tarojs/components"; import React, { FC…

Ubuntu 20.04 Server 使用命令行设置 IP 地址

1、编辑 /etc/netplan/ 目录下的配置文件00-installer-config.yaml (修改之前&#xff0c;把原来的文件备份) 按照对应的配置进行修改IP地址和网关 2、运行命令使其生效 sudo netplan apply 修改完成后&#xff0c;永久有效。重启后配置不会丢失

ElasticSearch重建/创建/删除索引操作 - 第501篇

历史文章&#xff08;文章累计500&#xff09; 《国内最全的Spring Boot系列之一》 《国内最全的Spring Boot系列之二》 《国内最全的Spring Boot系列之三》 《国内最全的Spring Boot系列之四》 《国内最全的Spring Boot系列之五》 《国内最全的Spring Boot系列之六》 E…

ROS学习笔记11——ROS中的重名问题

一、ros功能包重名——ros工作空间覆盖 功能包重名时&#xff0c;会按照 ROS_PACKAGE_PATH 查找&#xff0c;在前的会优先执行。ROS 会解析 .bashrc 文件&#xff0c;并生成 ROS_PACKAGE_PATH ROS包路径&#xff0c;即调用功能包的顺序&#xff0c;该变量中按照 .bashrc 中配置…

三、ElasticSearch集群搭建实战

本篇ES集群搭建主要是在Linux VM上&#xff0c;未使用Docker方式, ES版本为7.10 ,选择7.10版本原因可以看往期文章介绍。 一、ElasticSearch集群搭建须知 JVM设置 Elasticsearch是基于Java运行的&#xff0c;es7.10可以使用jdk1.8 ~ jdk11之间的版本&#xff0c;更高版本还没…

【JVM】运行时数据区域,内存如何分配和对象在内存中的组成

目录 一.运行时数据区域 1.线程独享 2.线程共享 二.内存如何分配 1.指针碰撞法 2.空闲列表法 3.TLAB 三.对象在内存中的组成 ​编辑1.对象头 2.实例数据 3.对齐填充 一.运行时数据区域 1.线程独享 &#xff08;1&#xff09;栈 虚拟机栈&#xff1a;每个 Java 方法在…

c++入门语法—————引用,内联函数,auto关键字,基于范围的for循环,nullptr

文章目录 一.引用1.引例2.注意事项3.应用场景1.做参数&#xff08;a:输出型参数b:内容较大参数&#xff09;2.做返回值&#xff08;a:修改返回值&#xff0c;b:减少拷贝&#xff09; 4.引用和指针的区别 二.内联函数1.为什么有内联函数2.用法和底层3.特性 三.auto关键字1.基础示…

计网Lesson11 - 虚拟机网络环境及socket概述

文章目录 虚拟机的简述socket概述 虚拟机的简述 放张图在这&#xff0c;根本没明白是啥对啥&#xff0c;以后学了Linux再来吧 &#x1f626; socket概述 s o c k e t socket socket 是一种用于应用层的用户态与应用层以下的内核态交互的工具&#xff0c;本意为“插座”。 也就是…

聚醚醚酮(Polyether Ether Ketone)PEEK在粘接使用时使用UV胶水的优势有哪些?要注意哪些事项?

使用UV胶水在聚醚醚酮&#xff08;Polyether Ether Ketone&#xff0c;PEEK&#xff09;上进行粘接可能具有一些优势&#xff0c;但同时也需要注意一些事项。以下是使用UV胶水的优势和需要考虑的事项&#xff1a; 优势&#xff1a; 1.快速固化&#xff1a; UV胶水通常具有快速…

来聊聊大厂面试题:求Java对象的大小

写在文章开头 日常使用Java进行业务开发时&#xff0c;我们基本不关心一个Java对象的大小&#xff0c;所以经常因为错误的估算导致大量的内存空间在无形之间被浪费了&#xff0c;所以今天笔者就基于这篇文章来聊聊一个Java对象的大小。 你好&#xff0c;我叫sharkchili&#x…

部分地级市收入泰尔指数数据,shp/excel格式,附数据可视化图及计算公式

泰尔指数的计算方式&#xff1a;分别计算城镇和农村收入份额与人口份额之比的自然对数&#xff0c;然后再以城乡收入份额作为权数&#xff0c;进行加权平均求和。 数据名称: 部分地级市收入泰尔指数数据 数据格式: Shp、excel 数据时间: 2010-2019年 数据几何类型: 面 数…

c++学习记录 多态—案例2—电脑组装

#include<iostream> using namespace std;//抽象不同的零件//抽象的cpu类 class Cpu { public://抽象的计算函数virtual void calculate() 0; };//抽象的显卡类 class VideoCard { public://抽象的显示函数virtual void display() 0; };//抽象的内存条类 class Memory …