socket套接字编程---UDP通信流程和代码编写

2023-05-16

文章目录

    • 1.UDP通信流程和接口介绍
      • 1.1UDP通信流程:
      • 1.2接口介绍:
        • 1.2.1创建套接字
        • 1.2.2为套接字绑定地址信息
        • 1.2.3发送数据
        • 1.2.4接收数据
        • 1.2.5 关闭套接字 释放资源
    • 2.UDP通信代码实现

网络中通信的两端主机:客户端,服务端
客户端:是通信中主动发起请求的一端。
服务端:通信中针对请求提供服务的一端,也是被动接受请求的一端。
C/S –>客户端服务器架构 ; B/S -->浏览器服务器架构

1.UDP通信流程和接口介绍

UDP协议(用户数据报协议)特点:无连接(通信两端不需要先建立连接),不可靠(有可能数据丢包或者乱序),面向数据报。
应用于传输实时性高于安全性的场景,如 视屏音频传输。

1.1UDP通信流程:

服务端需要先启动等待客户端的请求,客户端需要先知道服务端的地址信息。

Server端:

  1. 创建套接字
    在内核中创建socket结构体---->网络通信的一个句柄

  2. 为套接字绑定地址信息。给创建的socket结构指定源端IP和端口,协议。(服务端的地址信息一般都写死在程序中了)
    作用:
    发:1.发送数据时指定源端地址信息
    收:2.告诉操作系统收到的哪条数据应该交给这个socket处理

    在这里插入图片描述

  3. 接收数据
    从指定的socket缓冲区中取出数据,

  4. 发送数据
    将数据放到指定的socket的发送缓冲区中。
    在这里插入图片描述

  5. 关闭套接字

Client端:

  1. 创建套接字
  2. 为套接字绑定地址信息(客户端通常不主动绑定地址
    反例eg:多个客户端的情况,如果第一个客户端绑定了固定的端口,其他的客户端则无法绑定这个端口(一个端口只能被一个进程占用)。
  3. 发送数据 (发送数据时,检测到若自己没绑定地址信息,则系统会自动的选择合适的地址信息(IP+PORT)进行绑定。)(服务端的地址一般会提前告诉客户端,比如QQ客户端里面就写有其服务端的地址信息,不用我们自己写。)
  4. 接收数据
  5. 关闭套接字.

1.2接口介绍:

头文件:

#include <sys/socket.h>  //socket接口头文件
#include <netinet/in.h>  //地址结构,协议类型头文件
#include <arpa/inet.h>   //字节序转换接口头文件

1.2.1创建套接字

int socket(int domain, int type, int protocol);
domain:地址域类型。 
	AF_INET : ipv4地址域类型  struct sockaddr_in
	AF_INET6: ipv6地址域类型  struct  sockaddr_in6
	AF_UNIX: 本地 地址域类型    struct  sockaddr_un	
type:套接字类型
		SOCK_STREAM:流式套接字—--提供字节流传输  默认协议为TCP
		SOCK_DGRAM:数据报套接字---提供数据包传输   默认协议为UDP
protocol:通信所使用的协议类型(常用TCP/UDP)
		0:表示套接字类型默认协议
		IPPROTO_TCP(0:TCP协议
		IPPROTO_UDP(17:UDP协议
返回值:成功返回一个文件描述符—>操作句柄,失败返回-1

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

1.2.2为套接字绑定地址信息

#include <sys/types.h>        
#include <sys/socket.h>
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);	
///使用一个接口绑定不同的地址,使用时定义对应类型的结构体,传参时进行类型强转。

sockkfd: 创建套接字返回的描述符
addr:  struct sockaddr 地址信息通用结构体
addrlen:指定地址结构长度
返回值:成功返回0,失败-1

如下图:sockaddr 和sockaddr_in、sockaddr_in6地址信息的长度和内部数据组织形式不同,但是函数接口里使用了统一的通用结构体来接受传入的地址,根据传addrlen(指定地址结构长度)就能解析出来你所传的是哪一种地址结构体。
在这里插入图片描述

sockaddr_in结构:----- /usr/include/linux/socket.h
常见操作:
addr.sin_port=htons(port);
addr.sin_addr.s_addr=inet_addr(ip)
在这里插入图片描述
我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址
sockaddr_in中:
short sin_family;/Address family一般来说AF_INET(地址族)PF_INET(协议族)/

unsigned short sin_port;/Port number(必须要采用网络数据格式,普通数字可以用htons()函数转换成网络数据格式的数字)/

struct in_addr sin_addr;/IP address in network byte order(Internet address)/

unsigned char sin_zero[8];/Same size as struct sockaddr没有实际意义,只是为了 跟SOCKADDR结构在内存中对齐/

其中sockaddr结构为:
在这里插入图片描述
sa_family_t:地址域类型
sa_data:通用结构体。
常见操作://addr.sin_family=AF_INET;
in_addr结构为:

在这里插入图片描述

in_addr用来表示一个IPv4的IP地址. 其实就是一个32位的整数.

1.2.3发送数据

Size_t sendto( int sockfd, void *data,int len , 
				int flag,struct sockaddr * peer_Addr,socklen_t addrlen);

sockfd:套接字描述符
data:要发送的数据的空间首地址
len:要发送的数据长度
flag:标志位  0表示阻塞发送(缓冲区数据满了则等待)
peer_Addr:获取指定对端的地址信息(发给谁)
addrlen:地址信息长度; 
返回值:成功返回实际发送的长度,失败返回-1

1.2.4接收数据

ssize_t recvfrom(int sockfd,void*buf , int len, int flag,
				struct sockaddr* peer_addr,socklen_t* addrlen);

sockfd:套接字描述符
buf	:缓冲区空间地址,用于存放接收的数据
	len:要获取数据的长度
flag: 0 默认为阻塞接收(无数据则阻塞等待)
peer_addr:用于获取发送端的地址信息(谁发的)
addrlen:输入输出型参数---指定想要获取多长的地址;返回实际长度。
返回值:返回实际接收到的数据长度,失败返回-1

使用UDP协议接收数时每次接收一条完整的数据,不一定将缓冲区中数据获取完。

1.2.5 关闭套接字 释放资源

 Int close(int fd);

2.UDP通信代码实现

头文件和UdpSocket类接口:udpsocket.hpp
封装l了一个UdpSocket类,通过实例化对象,调用自己的成员接口可以在外部更加简单的完成客户端与服务端的搭建。
封装使代码的耦合度降低,方便外部调用,且内部数据访问更加安全。

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

class UdpSocket{
  public:
    UdpSocket():_sockfd(-1)
    {}

    bool Socket(){
      _sockfd =socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP) ;
      if(_sockfd<0){
        perror("socket error\n");
        return false;
      }
      return true;
    }

    bool Bind(const std::string &ip, uint16_t port) {
      struct sockaddr_in addr;
      addr.sin_family= AF_INET;
      addr.sin_addr.s_addr = inet_addr(ip.c_str());
      addr.sin_port= htons(port);
      int ret = bind(_sockfd,(struct sockaddr*)&addr,
                    sizeof(struct sockaddr_in));
      if(ret<0){
        perror("bind error \n");
        return false;
      }
      return true;
    }

    bool Send(const std::string &data, 
        const std::string &ip, uint16_t port)
    {
      struct sockaddr_in peer_addr;
      peer_addr.sin_family = AF_INET;
      peer_addr.sin_port=htons(port); 
      peer_addr.sin_addr.s_addr=inet_addr(ip.c_str());
      size_t ret = sendto(_sockfd,data.c_str(),data.size(),0,
                (struct sockaddr*)&peer_addr,sizeof(struct sockaddr_in));
      if(ret<0){
        perror("send error \n");
        return false;
      }
      return true;
    }

    bool Recv(std::string *buf,std::string *ip=NULL, uint16_t *port=NULL)
     {
      struct sockaddr_in addr;
      socklen_t len =sizeof(struct sockaddr_in);
      char tmp[4096]={0};
      int ret = recvfrom(_sockfd,tmp,4096,0,
                      (struct sockaddr*)&addr,&len);
      if(ret<0){
        perror("recvfrom error\n");
        return false;
      }
      buf->assign(tmp, ret);//申请空间并拷贝数据到buf
      if(ip!=NULL){
        *ip=inet_ntoa(addr.sin_addr);
      }
      if(port!=NULL){
      *ip = ntohs(addr.sin_port);
      }
      return true;
    }

    bool Close() {
      if(_sockfd != -1) {
        close(_sockfd);
      }
      return true;
    }

  private:
    int _sockfd;

};

服务端:udp_server.c

#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>

int  main(){
  int sockfd= socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
  if(sockfd<0){
    perror("socket error\n");
    return -1;
  }
  
  struct sockaddr_in addr;
  addr.sin_family=AF_INET;
  addr.sin_port=htons(9999);  //端口号
  addr.sin_addr.s_addr =inet_addr("192.168.86.3");//ip
  socklen_t addrlen = sizeof(struct sockaddr_in);
  int ret= bind(sockfd,(struct sockaddr*)&addr,addrlen);
  if(ret <0){
    perror("bind error\n");
    return -1;
  }

  while(1){
    //接收数据
    char buf[1024]={0};
    struct sockaddr_in peer_addr;
    ret = recvfrom(sockfd, buf, 1023,0,(struct sockaddr*)&peer_addr,&addrlen);
    if(ret <0){
      perror("recvfrom error\n");
      close(sockfd);
      return -1;
    }
    printf("clent say:%s\n",buf);

    // 发送数据
    memset(buf,0,1024);
    printf("server say: ");
    fflush(stdout);
    fgets(buf,1024,stdin);
    ret=sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&peer_addr,addrlen);
    if(ret <0){
      perror("sendto error\n");
      close(sockfd);
      return -1;
    }
  }


  close(sockfd);
  return  0;
}

客户端:udp_client.cpp

#include "udpsocket.hpp"

#define CHECK_RET(q) if((q)==false){return -1;}


int main(){
  UdpSocket sock;
  CHECK_RET( sock.Socket());
  while(1){
     std:: string buf;
     std::cout<<"clent say:";
     std::cin>>buf;
         
    CHECK_RET( sock.Send(buf,"192.168.86.3",9999) );
    
    buf.clear();
   CHECK_RET(sock.Recv(&buf,NULL,NULL) );
   std:: cout<<"server say: "<<buf<<std::endl;
  }
  CHECK_RET(sock.Close());
  return 0;
}

在这里插入图片描述

结果演示:
这里之启动了一个server端,也可同时启动多个server端。

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

socket套接字编程---UDP通信流程和代码编写 的相关文章

  • Django(4)表单

    文章目录 一 概述二 GET方法三 POST方法四 Request对象五 QueryDict对象 此文章参考菜鸟教程 xff1a Django 表单 菜鸟教程 runoob com Django版本 xff1a span class tok
  • Django(5)视图

    文章目录 一 视图概述二 请求对象HttpRequest xff08 1 xff09 GET xff08 2 xff09 POST xff08 3 xff09 body xff08 4 xff09 path xff08 5 xff09 me
  • Django(6)路由

    文章目录 一 路由概述二 正则路径中的分组 xff08 1 xff09 正则路径中的无名分组 xff08 2 xff09 正则路径中的有名分组 xff08 3 xff09 路由分发 三 反向解析 xff08 使用reverse xff09
  • Django(7)Admin管理工具

    文章目录 一 概述二 使用管理工具 xff08 1 xff09 激活管理工具 xff08 2 xff09 使用管理工具 xff08 3 xff09 复杂模型 xff08 4 xff09 自定义表单 xff08 5 xff09 内联 xff0
  • Django(8)ORM单表实例

    文章目录 一 Django ORM 单表实例创建新模型 二 数据库操作 xff08 1 xff09 添加数据 xff08 2 xff09 查找数据 filter exclude get order by reverse count firs
  • Django(9)ORM多表实例

    文章目录 一 Django ORM 多表实例创建模型插入数据 二 ORM 插入数据一对多 外键 ForeignKey多对多 xff08 Many ToManyField xff09 xff1a 在第三张表添加数据 三 关联管理器 对象调用1
  • Django(10)ORM聚合查询

    文章目录 一 聚合查询 aggregate 二 分组查询 annotate 三 F 查询四 Q 查询 此文章参考菜鸟教程 xff1a Django ORM 多表实例 xff08 聚合与分组查询 xff09 菜鸟教程 runoob com D
  • Python类的常用魔法方法

    文章目录 一 96 init 96 二 96 str 96 三 96 del 96 四 96 repr 96 五 使用案例 一 init span class token comment 在Python类中 有一类方法 这类方法以 两个下划
  • ubuntu 升级内核实战

    ubuntu 12 04内核是linux 3 2 0 24 xff0c 其实升级到最新版本3 3 4也没什么很大意义 xff0c 主要是集成了一些新的驱动和一些普通用户用不到的功能 xff0c 所以基本上本文纯属折腾 xff0c 但不要随便
  • centos7安装python3不影响python2

    文章目录 一 前言二 安装python3 一 前言 Centos7中很多软件命令依赖于系统自带的python2 比如yum 卸载python2会造成yum不可用 所以没必要卸载python2 如果要使用python3 可以通过软链接的方式安
  • Python异常的传递以及完整结构

    文章目录 异常的传递 异常的完整结构 异常的传递 span class token triple quoted string string 34 34 34 异常的传递是异常处理的底层机制 是原理层面 异常传递 当一行代码发生异常后 会向外
  • Python互斥锁小技巧

    span class token triple quoted string string 34 34 34 需求 创建两个线程 其中一个输出 1 52 另一个输出 A Z 输出格式要求 12A 13B 56C 5151Z 34 34 34
  • Python-TCP服务端程序开发

    文章目录 一 TCP服务端程序开发二 端口复用三 判断客户端程序是否断开四 多任务版本 一 TCP服务端程序开发 span class token triple quoted string string 34 34 34 主动套接字 可以收
  • Python-TCP网络编程基础以及客户端程序开发

    文章目录 一 网络编程基础 什么是IP地址 什么是端口和端口号 TCP介绍 socket介绍 二 TCP客户端程序开发三 扩展 一 网络编程基础 什么是IP地址 IP地址就是标识网络中设备的一个地址 IP地址分为 IPv4 和 IPv6 I
  • HTML介绍

    文章目录 一 HTML介绍二 创建三 HTML结构四 常见的标签五 链接标签六 图片标签七 资源路径八 列表标签九 表格标签十 表单标签十一 表单提交 一 HTML介绍 HTML 超文本标记语言作用 书写前端页面前端三大技术 三大标准 HT
  • CSS介绍

    文章目录 一 CSS介绍二 CSS的引入方式三 CSS选择器 一 CSS介绍 定义 层叠样式表作用 美化界面 设置标签文字大小 颜色 字体加粗等样式控制页面布局 设置浮动 定位等样式 基本语法 选择器 样式规则 样式规则 属性名1 属性值1
  • JavaScript介绍

    文章目录 一 JavaScript介绍二 JavaScript的引入方式三 JavaScript的变量与数据类型四 JavaScript中的函数五 JavaScript变量的作用域六 JavaScript运算符七 JavaScript判断语
  • JQuery介绍

    文章目录 一 JQuery介绍二 JQuery使用三 JQuery选择器四 JQuery选择集过滤五 JQuery选择集转移六 JQuery获取和操作标签内容七 JQuery获取和设置元素属性八 JQuery事件九 JQuery事件代理 事
  • 树莓派操作系统烧录

    准备 硬件 xff1a 树莓派4BMicroSD卡 xff08 16GB xff09 SD卡读卡器 软件 xff1a SD卡格式化软件 xff08 SDFormatter xff09 系统烧录软件 xff08 balenaEtcher xf
  • 嵌入式系统开发必读经典书目

    读本科的时候就对嵌入式系统感兴趣 xff0c 虽然在校的时候积累了大量材料 xff0c 但是在较长的时间里都没有机会细读 xff0c 这学期终于静下心来 xff0c 系统学习一遍 xff0c 期间把以前积累的各类教材或粗粗浏览或仔细揣摩 x

随机推荐

  • 百度笔试题2018

    题外话 首先我要吐槽一下 xff0c csdn简直是在作死啊 xff0c 复制博文底下的那个引用太恶心了 xff0c 我复制自己的博客 xff0c 还有引用 xff0c 啥玩意啊 所以我决定换地方了 xff0c 以后github xff08
  • 统计计算——基于R语言的随机数生成

    统计计算 基于R语言的随机数生成 R中常见一元分布函数 代码展示 xff1a set seed 191206 设置随机数种子 xff0c 为了保证多次生成的随机数一致 xff0c 需要保证数据一样情况下进行再次实验时可用到 N 61 100
  • 第九章 Linux下的虚拟化部署

    第一步 查看CPU信息 打开虚拟机安装程序在四种方式中选择第一种 找到对应镜像 走安装流程 等待安装完成 点击协议 点击我同意 即可打开虚拟机
  • 第二本书 第一章 linux中的网络配置

    配置新网络 ifconfig ping ip 指令的使用 无图形模式生成新网络 nmcil指令的使用 dhcp服务配置 块网卡上配置多个IP 设定dns
  • 阿里云培训-负载均衡(CLB/ALB)

    什么是传统型负载均衡CLB 传统型负载均衡CLB xff08 Classic Load Balancer xff09 是将访问流量根据转发策略分发到后端多台云服务器 xff08 ECS实例 xff09 的流量分发控制服务 CLB扩展了应用的
  • 阿里云培训-AS(弹性伸缩)

    什么是弹性伸缩Auto Scaling 弹性伸缩 xff08 Auto Scaling xff09 是根据业务需求和策略自动调整计算能力 xff08 即实例数量 xff09 的服务 您可以指定实例的类型 xff0c 即ECS实例或ECI实例
  • php源码安装

    php源码安装 下载php的rpm包并解压 在解压之后的目录中 xff0c 查看是否有configure xff0c 如果有此文件 xff0c 使用 configure gt make gt make install方式进行源码安装 roo
  • K8S集群部署

    环境准备 由于k8s 集群比较吃配置 xff0c 使用 按量计费 来进行学习 xff0c 三台 4核8G 的费用大概再 1 6元 小时 三台云服务器 配置 xff1a 2核2G 三台服务器内网互通 xff08 内网可以互相访问 VPC xf
  • K8S Pod

    Pod管理 Pod是可以创建和管理Kubernetes计算的最小可部署单元 xff0c 一个Pod代表着集群中运行的一个进程 xff0c 每个pod都有一个唯一的ip 一个pod类似一个豌豆荚 xff0c 包含一个或多个容器 xff08 通
  • 物联网之嵌入式设备

    物联网自提出以来 xff0c 业界对其定义也不断的加深优化 xff0c 使其更具体 更容易与现实结合 xff0c 不再只停留在概念上 xff0c 这其中离不开从业者的探索与发现 物联网按字面理解分三个部分 xff1a 一 物 xff0c 与
  • WIFI模块接入ONENET步骤

    文章目录 前言思维导图一 onenet c文件1 产品IDONENET程序 2 鉴权信息ONENET程序 3 设备IDONENET程序 二 esp8266 c文件1 WIFI名称及密码程序 2 IP及端口 三 打包数据函数 在onenet
  • K8S 控制器 service ingress

    控制器 Pod 的分类 自主式 Pod xff1a Pod 退出后不会被创建 控制器管理的 Pod xff1a 在控制器的生命周期里 xff0c 始终要维持 Pod 的副本数目 控制器类型 Replication Controller和Re
  • K8s---网络通信 Configmap secrer volumesk8s

    k8s网络通信简介 k8s通过CNI接口接入其他插件来实现网络通讯 目前比较流行的插件有flannel xff0c calico等 CNI插件存放位置 xff1a cat etc cni net d 10 flannel conflist
  • Linux进程管理动态查看进程top

    目录 一 解读top命令的显示信息 1 上半部分解读 xff08 前五行 xff09 2 后半部分 xff08 进程信息 xff09 二 top常用内部指令 一 解读top命令的显示信息 命令 xff1a top 注意 xff1a 在top
  • ENSP基本命令和小实验

    ENSP基本命令和小实验 ENSP基本命令1 历史命令查询2 配置主机名3 状态信息查询4 进入接口模式并查看信息5 配置文件管理命令6 关闭华为的信息提示中心7 永不超时8 配置双工及速率命令9 保存配置10 用SecureCRT链接eN
  • 一个刚毕业大学生的四个月苦逼程序员经历

    先来一个自我介绍 大学时排名老三 就暂且叫老三吧 xff0c 毕业于河南的一个还算可以的二本院校 xff0c 专业 地球信息科学与技术 首先介绍一下我的专业 xff0c 听着名字很高大上 xff0c 其实 xff0c 我们都叫他四不像专业
  • windows10系统下基于pybind11库进行c++代码调用python(pytorch)代码

    最近在学习基于lidar mos进行slam激光点云动态物体剔除的相关内容 xff0c 经过调研准备基于pybind11库在实际项目 c 43 43 中调用salsaNext代码 python 使用cmake在测试项目中引入pybind11
  • 事件流是什么

    事件流分为事件冒泡和事件捕获 事件流 xff1a 就是事件的流向 xff0c 先捕获 xff0c 再到事件源 xff0c 最后再冒泡 xff0c 一共分三个阶段 xff1a 捕获阶段 xff0c 事件源 xff0c 冒泡阶段 从上至下再出来
  • 实现浏览器访问基于workman的异步任务

    准备工作 xff1a 安装workman xff0c 引入 目录 xff1a 进程任务服务端service php 提交任务服务端service transit php index php cli模式开启service php和servic
  • socket套接字编程---UDP通信流程和代码编写

    文章目录 1 UDP通信流程和接口介绍1 1UDP通信流程 xff1a 1 2接口介绍 xff1a 1 2 1创建套接字1 2 2为套接字绑定地址信息1 2 3发送数据1 2 4接收数据1 2 5 关闭套接字 释放资源 2 UDP通信代码实