十九、socket套接字编程——udp

news/2024/5/18 16:37:09 标签: udp, 网络, tcp/ip

文章目录

  • 一、socket套接字编程接口
    • (一)socket头文件
    • (二)socket 常见API(套接字编程接口)
      • 1. 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器 )
      • 2.绑定网络信息 (TCP/UDP, 服务器 )
      • 3.开始监听 socket (TCP, 服务器 )
      • 4.接收请求 (TCP, 服务器 )
      • 5.建立连接 (TCP, 客户端 )
    • (三)sockaddr结构(套接字的地址结构类型定义)
    • (四)一些相关函数
      • 1.inet_ntoa
      • 2.地址转换函数
      • 2.网络服务 recvfrom 与 sendto
        • (1)udp特有的 recvfrom读取套接字中的信息
        • (2)sendto向套接字发送信息
  • 二、简单的UDP网络程序
    • (一)实现一个简单的英译汉的功能
      • 1.服务器
      • 2.客户端

一、socket套接字编程接口

(一)socket头文件

man socket,man htons,man inet_ addr查看所有头文件
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>

(二)socket 常见API(套接字编程接口)

1. 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器 )

int socket(int domain, int type, int protocol);

domain:socket网络通信的域——网络通信 (AF_INET /PF_INET )(或 本地通信
(AF_UNIX))。现在只用AF_INET 网络通信(有的地方把AF_INET写成PF_INET也是正确的)
type:套接字类型——决定了我们通信的时候对应的报文类型(流式 / 用户数据报式)

    流式套接:SOCK_STREAM ——用于TCP协议

    用户数据报式套接:SOCK_DGRAM ——用于UDP协议

protocol:协议类型——网络应用中设置为0。(因为AF_INET+SOCK_STREAM—默认是TCP套接字;AF_INET+SOCK_DGRAM—默认是UDP套接字)

返回值:成功返回文件描述符(套接字描述符),错误返回-1并设置错误码(套接字类型本质就是文件描述符)

2.绑定网络信息 (TCP/UDP, 服务器 )

nt bind(int socket, const struct sockaddr *address,socklen_t address_len);

sockfd:套接字这个文件描述符。addr:传入我们自己创建的信息 struct sockaddr_in local
的地址,然后把它强转成struct
sockaddr类型结构体,内部会自动识别是什么类型的套接字做绑定。
addrlen:sockaddr类型结构体 的大小

返回值:成功返回0,失败返回-1

例如:if (bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) == -1)

3.开始监听 socket (TCP, 服务器 )

int listen(int socket, int backlog);

4.接收请求 (TCP, 服务器 )

int accept(int socket, struct sockaddr* address,socklen_t* address_len);

5.建立连接 (TCP, 客户端 )

int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

(三)sockaddr结构(套接字的地址结构类型定义)

socket API是一层抽象的网络编程接口 , 适用于各种底层网络协议 , 如 IPv4 、 IPv6, 以及后面要讲的 UNIX Domain Socket. 然而 , 各种网络协议的地址格式并不相同。
两个地址结构类型:

  • struct sockaddr_ in——网络套接字,用于网络通信;
  • struct sockaddr_ un——域间套接字,用于UNIX本地通信;
  • 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 DomainSocket各种类型的sockaddr结构体指针做为参数;

在这里插入图片描述
sockaddr 结构
在这里插入图片描述
sockaddr_in 结构
在这里插入图片描述
虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址。
in_addr结构
在这里插入图片描述

(四)一些相关函数

1.inet_ntoa

char *inet_ntoa(struct in_addr in);4字节IP地址转为字符串风格的IP地址并返回。

返回值:inet_ntoa 这个函数返回了一个 char*(错误返回nullptr), 很显然是这个函数自己在内部为我们申请了一块内存来保存 ip的结果。
inet_ntoa 函数 把这个返回结果放到了静态存储区static char buffer[] , 这个时候不需要我们手动进行释放。
注意:这类函数在转变IP风格时都会自动进行主机字节序和网络字节序之间的转换。

例子: std::string peerIp = inet_ntoa(peer.sin_addr); //拿到了对方的IP
在这里插入图片描述
因为inet_ntoa把结果放到自己内部的一个静态存储区, 这样第二次调用时的结果会覆盖掉上一次的结果。

    思考: 如果有多个线程调用 inet_ntoa, 是否会出现异常情况呢 ?——不一定
    在APUE 中 , 明确提出 inet_ntoa 不是线程安全的函数 ;
    但是在centos7 上测试 , 并没有出现问题 , 可能内部的实现加了互斥锁 ;
    自己写程序验证一下在自己的机器上inet_ntoa 是否会出现多线程的问题 ;
    在多线程环境下, 推荐使用 inet_ntop, 这个函数由调用者提供一个缓冲区保存结果 , 可以规避线程安全问题;

2.地址转换函数

基于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!

2.网络服务 recvfrom 与 sendto

udp_recvfrom_120">(1)udp特有的 recvfrom读取套接字中的信息

 man recvfrom

在这里插入图片描述

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • 从特定套接字 sockfd中读取数据到缓冲区buf中,buf大小为len,flags设为0——阻塞式读取

  • src_addr:(输出型参数)当服务器读取客户端发送的消息时——哪个客户端给你发的消息,就把这个客户端套接字信息存入src_addr中。(src_addr的类型是套接字类型指针struct sockaddr*,传入的网络套接字类型struct sockaddr_in需要强转成此类型指针 struct sockaddr。)

  • addrlen:(输入输出型参数)客户端这个缓冲区大小。(socklen_t就是unsigned int)

  • 返回值:返回读到的字节数,错误就返回-1错误码被设置

当客户端使用recvfrom读取服务器返回发送的消息时——src_addr和addrlen没意义,但是还是要定义一个套接字类型结构体添上占位。

(2)sendto向套接字发送信息

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

通过客户端的指定套接字sockfd,发送buf中的数据,buf的大小是len,flags=0 默认阻塞式发送。

  • dest_addr:(输入型参数)向哪个主机发消息,套接字类型指针struct sockaddr*,传入的网络套接字类型struct sockaddr需要强转成此类型指针 struct sockaddr

  • addrlen:(输入型参数)主机这个缓冲区大小。(socklen t就是unsigned int)

  • 返回值:返回读到的字节数,错误就返回-1错误码被设置

(首次调用sendto函数的时候,我们的client会自动bind自己的ip和port)

二、简单的UDP网络程序

(一)实现一个简单的英译汉的功能

1.服务器

2.客户端


http://www.niftyadmin.cn/n/467309.html

相关文章

设计模式之备忘录模式笔记

设计模式之备忘录模式笔记 说明Memento(备忘录)目录白箱备忘录模式备忘录模式示例类图游戏角色类备忘录角色类备忘录对象管理对象测试类 黑箱备忘录模式备忘录模式示例类图备忘录接口游戏角色类备忘录对象管理对象测试类 说明 记录下学习设计模式-备忘录模式的写法。JDK使用版…

开窗函数之聚合、取特定值、排名

一&#xff0c; 聚合开窗函数sum(score) over(partition by name ) 二&#xff0c;开窗函数之first_value&#xff0c;last_value&#xff0c;lead&#xff0c;lag 三&#xff0c;排名开窗函数ROW_NUMBER、DENSE_RANK、RANK 一&#xff0c;开窗函数的语法 开窗函数的语法为&am…

【kotlin笔记04】kotlin之单例模式、伴生对象、委托机制、异常处理、集合框架

这篇文章,主要介绍kotlin之单例模式、伴生对象、委托机制、异常处理、集合框架。 目录 一、kotlin笔记 1.1、kotlin单例模式 (1)单例类 (2)伴生对象 1.2、委

unity 性能优化学习笔记——静态资源的导入

1 Audio导入设置检查与优化 根据平台选择合理的音频设置&#xff0c;原始音频资源尽量采用未压缩WAV格式 - 移动平台对音乐音效统一采用单通道设置&#xff08;Force to Mono&#xff09;,并将音乐采样频率设置为22050Hz - 移动平台大多数声音尽量采用Vorbis压缩设置&#xff0…

JDBC和数据库应用总结

文章目录 1. JDBC介绍2. 相关jar包引入3. JDBC与数据库基本连接4. JDBC API 详解4.1 Connection 接口4.2 Statement 接口4.3 ResultSet 5. PreparedStatement 详解 1. JDBC介绍 JDBC是一套标准接口&#xff0c;这套接口用于操作所有的数据库&#xff0c;不同的数据库厂商对迎合…

《kafka 核心技术与实战》课程学习笔记(六)

生产者消息分区机制原理剖析 为什么分区&#xff1f; Kafka 有主题&#xff08;Topic&#xff09;的概念&#xff0c;它是承载真实数据的逻辑容器&#xff0c;而在主题之下还分为若干个分区&#xff0c;也就是说 Kafka 的消息组织方式实际上是三级结构&#xff1a;主题 - 分区…

体验Vue神奇的响应式原理:让你的应用更快、更流畅

文章目录 I. 引言介绍Vue.js的响应式原理及其重要性概述本文的内容 II. 数据劫持解释什么是数据劫持Vue如何实现数据劫持示例说明 II. 依赖收集解释什么是依赖收集Vue如何实现依赖收集示例说明 IV. 派发更新解释什么是派发更新Vue如何实现派发更新示例说明 V. 响应式原理运作流…

APP/小程序嵌入游戏,游戏飞跃的赛道

APP/小程序接入游戏运营已不是新鲜事&#xff0c;然而&#xff0c;其仍具有巨大的发展潜力&#xff0c;尤其是社交类APP&#xff0c;多以加入娱乐游戏增加互动&#xff0c;获取目标客户&#xff0c;同时为产品增加变现渠道&#xff0c;实现双赢。 对于APP嵌入式游戏&#xff0…