Linux下UDP编程

一.概念介绍

1.socket 是什么?

  socket(套接字)本质上是一个抽象的概念,它是一组用于网络通信的 API,提供了一种统一的接口,使得应用程序可以通过网络进行通信。在不同的操作系统中,socket 的实现方式可能不同,但它们都遵循相同的规范和协议,可以实现跨平台的网络通信。

2.socket实现通信的原理是基于网络协议栈。

  协议栈是一个由多个层次协议组成的网络协议体系结构,它负责对数据进行封装和解封装,并确保数据能够在网络上正确传输。

  当应用程序通过 socket 发送数据时,操作系统会将数据传递给协议栈的上层协议,该协议会对数据进行封装并添加一些必要的信息,例如目标 IP 地址和端口号等。然后将封装后的数据传递给下一层协议,直到数据最终被封装成一个网络包并通过网络发送到目标主机。

  当目标主机收到网络包后,协议栈会对数据进行解封装,并将数据传递给操作系统中的套接字。如果该套接字是一个监听套接字,操作系统会创建一个新的套接字来处理连接请求,并将新的套接字加入到协议栈中。如果该套接字是一个已连接套接字,操作系统会将数据传递给应用程序处理。

3.socket 是一个系统接口函数,由操作系统提供,用于实现网络编程的功能。通过 socket 函数,应用程序可以创建套接字、绑定地址、监听连接、发送和接收数据等操作,从而实现网络通信。

二.API介绍

1.创建套接字的函数是socket()

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

/*

- 其中 “int domain”参数表示套接字要使用的协议簇,协议簇的在“linux/socket.h”里有详细定义,常用的协议簇:

AF_UNIX(本机通信)

AF_INET(TCP/IP – IPv4)

AF_INET6(TCP/IP – IPv6)

- 其中 “type”参数指的是套接字类型,常用的类型有:

SOCK_STREAM(TCP流)

SOCK_DGRAM(UDP数据报)

SOCK_RAW(原始套接字)

- 最后一个 “protocol”一般设置为“0”,也就是当确定套接字使用的协议簇和类型时,这个参数的值就为0,但是有时候创建原始套接字时,并不知道要使用的协议簇和类型,也就是domain参数未知情况下,这时protocol这个参数就起作用了,它可以确定协议的种类。

socket是一个函数,那么它也有返回值,当套接字创建成功时,返回套接字,失败返回“-1”,错误代码则写入“errno”中。

*/

// 实例

#include <sys/types.h>

#include <sys/socket.h>

#include <linux/socket.h>

int sock_fd_tcp;

    int sock_fd_udp;

    sock_fd_tcp = socket(AF_INET, SOCK_STREAM, 0);     // 创建tcp通讯的套接字

    sock_fd_udp = socket(AF_INET, SOCK_DGRAM, 0);    // 创建udp通讯的套接字

    if(sock_fd_tcp < 0) {

        perror("TCP SOCKET ERROR!\n");

        exit(-1);

     }

    if(sock_fd_udp < 0) {

        perror("UDP SOCKET ERROR!\n");

        exit(-1);

     }

2.地址与端口设置的结构体 sockaddr_in

#include <netinet/in.h>

   

struct sockaddr_in{

     unsigned short         sin_family;    

     unsigned short int     sin_port;      

     struct in_addr         sin_addr;      

     unsigned char          sin_zero[8];   

};

struct in_addr{

     unsigned long     s_addr;  // 这是一个无符号32位整数,用于存储IPv4地址

};

/*

sin_family表示地址类型,对于基于TCP/IP传输协议的通信,该值只能是AF_INET;

sin_prot表示端口号,例如:21 或者 80 或者 27015,总之在0 ~ 65535之间;

sin_addr表示32位的IP地址,例如:192.168.1.5 或 202.96.134.133;

sin_zero表示填充字节,一般情况下该值为0;

Socket数据的赋值实例:

*/

// 实例

 struct sockaddr_in addr;

 memset(&addr, 0, sizeof(addr));  // 将结构体清零  主要是sin_zero表示填充字节为零

 addr.sin_family = AF_INET; //(TCP/IP – IPv4)

 addr.sin_port = htons(port_out);    // 绑定端口号 htons将一个无符号短整型数值转换为网络字节序

 addr.sin_addr.s_addr = htonl(INADDR_ANY);  // 绑定IP htonl就是把ip字节顺序转化为网络字节顺序

                                            

// INADDR_ANY 泛指机器所有的IP因为有些电脑不只有一个网卡;INADDR_ANY 是一个宏,表示“任意地址”,通常用于服务器在绑定套接字时指定其愿意监听的地址。通常被赋值为 0.0.0.0 的网络字节序表示。

3.把名字和套接字相关联 bind()

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

/*

当用socket()函数创建套接字以后,套接字在名称空间(网络地址族)中存在,但没有任何地址给它赋值。bind()把用addr指定的地址赋值给用文件描述符代表的套接字sockfd。addrlen指定了以addr所指向的地址结构体的字节长度。一般来说,该操作称为“给套接字命名”。

通常,在一个SOCK_STREAM套接字接收连接之前,必须通过bind()函数用本地地址为套接字命名。

*/

// 实例

#include <sys/types.h>

#include <sys/socket.h>

sockfd = socket(AF_INET, SOCK_DGRAM, 0);

struct sockaddr_in addr;

socklen_t addr_len = sizeof(addr);

if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){

    printf("Failed to bind socket on port %d\n", port_out);

    close(sockfd);

    return false;

}

4.接收消息的函数recvfrom()

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

/*

recvfrom: 用于接收数据

- sockfd:用于接收UDP数据的套接字;

- buf:保存接收数据的缓冲区地址;

- len:可接收的最大字节数(不能超过buf缓冲区的大小);

- flags:可选项参数,若没有可传递0;

- src_addr:存有发送端地址信息的sockaddr结构体变量的地址;

- addrlen:保存参数 src_addr的结构体变量长度的变量地址值。

*/

5.发送消息的函数sendto()

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

/*

sendto:用于发送数据

- sockfd:用于传输UDP数据的套接字;

- buf:保存待传输数据的缓冲区地址;

- len:带传输数据的长度(以字节计);

- flags:可选项参数,若没有可传递0;

- dest_addr:存有目标地址信息的 sockaddr 结构体变量的地址;

- addrlen:传递给参数 dest_addr的地址值结构体变量的长度。

*/

注意:UDP套接字不会保持连接状态,每次传输数据都要添加目标地址信息,这相当于在邮寄包裹前填写收件人地址。

三.代码示例

1.udp server

#include<sys/select.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<arpa/inet.h>

#include<netinet/in.h>

#include <cstdlib>

#include <cstdio>

#include <cstring>

#include <iostream>

int main(){

    //同一台电脑测试,需要两个端口

    int port_in  = 12321;

    int port_out = 12322;

    int sockfd;

    // 创建socket

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(-1==sockfd){

        return false;

        puts("Failed to create socket");

    }

    // 设置地址与端口

    struct sockaddr_in addr;

    socklen_t addr_len = sizeof(addr);

    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;       // Use IPV4

    addr.sin_port = htons(port_out);    //

    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    

   // Time out

    struct timeval tv;

    tv.tv_sec  = 0;

    tv.tv_usec = 200000;  // 200 ms

    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    // Bind 端口,用来接受之前设定的地址与端口发来的信息,作为接受一方必须bind端口,并且端口号与发送方一致

    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){

        printf("Failed to bind socket on port %d\n", port_out);

        close(sockfd);

        return false;

    }

    char buffer[128];

    memset(buffer, 0, 128);

    int counter = 0;

    while(1){

        struct sockaddr_in src;

        socklen_t src_len = sizeof(src);

        memset(&src, 0, sizeof(src));

     // 阻塞住接受消息

        int sz = recvfrom(sockfd, buffer, 128, 0, (sockaddr*)&src, &src_len);

        if (sz > 0){

            buffer[sz] = 0;

            printf("Get Message %d: %s\n", counter++, buffer);

        }

        else{

            puts("timeout");

        }

    }

    close(sockfd);

    return 0;

}

2.udp client

#include<sys/select.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/socket.h>

#include<arpa/inet.h>

#include<netinet/in.h>

#include <cstdlib>

#include <cstdio>

#include <cstring>

#include <iostream>

int main(){

    int port_in  = 12321;

    int port_out = 12322;

    int sockfd;

    // 创建socket

    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    if(-1==sockfd){

        return false;

        puts("Failed to create socket");

    }

    // 设置地址与端口

    struct sockaddr_in addr;

    socklen_t  addr_len=sizeof(addr);

    memset(&addr, 0, sizeof(addr));

    addr.sin_family = AF_INET;       // Use IPV4

    addr.sin_port   = htons(port_in);    //

    addr.sin_addr.s_addr = htonl(INADDR_ANY);

    // Time out

    struct timeval tv;

    tv.tv_sec  = 0;

    tv.tv_usec = 200000;  // 200 ms

    setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof(struct timeval));

    

    // 绑定获取数据的端口,作为发送方,不绑定也行

    if (bind(sockfd, (struct sockaddr*)&addr, addr_len) == -1){

        printf("Failed to bind socket on port %d\n", port_in);

        close(sockfd);

        return false;

    }

    int counter = 0;

    while(1){

        

        addr.sin_family = AF_INET;

        addr.sin_port   = htons(port_out);

        addr.sin_addr.s_addr = htonl(INADDR_ANY);

        sendto(sockfd, "hello world", 11, 0, (sockaddr*)&addr, addr_len);

        printf("Sended %d\n", ++counter);

        sleep(1);

    }

    close(sockfd);

    return 0;

}

3.测试结果

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python系列】Jinja2 模板引擎

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

【软件测试】软件测试生命周期与Bug

目录 &#x1f4d5; 前言 &#x1f334;软件测试的生命周期 ​编辑&#x1f332;BUG &#x1f6a9; 概念 &#x1f6a9;描述bug的要素 &#x1f6a9;bug的级别 &#x1f6a9;bug的生命周期 &#x1f3c0;先检查自身&#xff0c;是否bug描述不清楚 &#x1f3c0;站在用…

Docker 安装 SqlServer

摘要&#xff1a;我们工作当中经常需要拉取多个数据库实例出来做集群&#xff0c;做测试也好&#xff0c;通过 Docker 拉取 SqlServer 镜像&#xff0c;再通过镜像运行多个容器&#xff0c;几分钟就可以创建多个实例&#xff0c;效率是相当的高。 1. docker 拉取镜像 注意&am…

[mysql]mysql的演示使用

mysql的演示使用 几个常见操作 1&#xff1a;show databases 这里第一个information_schema代表的是数据库的基本系统信息&#xff0c;数据库名称&#xff0c;表的名称&#xff0c;存储权限 第二个是mysql&#xff0c;保存的是我们数据库运行的时候需要的系统信息&#xff0…

数据中台即将消亡,数智基建取而代之?

数据中台即将消亡&#xff0c;数智基建取而代之&#xff1f; 前言数智基建 前言 在当今数字化浪潮汹涌澎湃的时代&#xff0c;企业的发展如同在浩瀚海洋中航行的巨轮&#xff0c;而数据则是推动这艘巨轮前行的强大动力。然而&#xff0c;如何有效地管理和利用数据&#xff0c;…

Kafka3.x 使用 KRaft 模式部署 不依赖 ZooKeeper

前言 Kafka 从 2.8.0 版本开始引入了 Kafka Raft Metadata Mode&#xff08;KRaft 模式&#xff09;&#xff0c;这个模式允许 Kafka 在不依赖 ZooKeeper 的情况下进行元数据管理。KRaft 模式在 Kafka 3.0.0 中进入了稳定版本,本文部署的 Kafka_2.12-3.6.0 单机模式 环境 Ce…

工厂andon暗灯系统数字化应用案例

在当今数字化浪潮席卷制造业的时代&#xff0c;工厂的高效运作和精益管理离不开先进的技术手段。Andon 暗灯系统作为精益制造执行中的核心工具和 MES 制造执行系统的重要组成部分&#xff0c;正以其强大的功能为工厂带来全新的变革。 某汽车零部件制造工厂&#xff0c;拥有多条…

Java设计模式之策略模式详细讲解和案例示范

Java设计模式之策略模式详细讲解和案例示范 在软件开发中&#xff0c;策略模式是一种常见且非常有用的设计模式。它允许定义一系列算法&#xff0c;将它们一个个封装起来&#xff0c;并且使它们可以互相替换。策略模式让算法可以独立于使用它们的客户端而变化。本篇文章将详细…

[MySql]保姆级上手教程

介绍 通过数据库管理系统, 编写执行SQL语句, 实现对数据库数据的管理 数据库(DataBase): 储存和管理数据的仓库数据库管理系统(DBMS): 操作和管理数据库的软件SQL语言: 操作关系型数据库的通用语言数据库可以分为关系型数据库和非关系型数据库 相关产品 常见的关系型数据库产…

【golang-入门】环境配置、VSCode开发环境配置

golang介绍基础信息 windows环境配置安装包下载安装环境变量设置检查 VSCode开发配置插件配置在 Visual Studio Code 中安装通义灵码go hello word 参考资料 golang介绍 基础信息 golang官网&#xff1a;https://go.dev/golang学习网&#xff1a;https://studygolang.com/使用…

android使用YOLOV8数据返回到JAVA方法(JAVA)

一、下载扩展文件(最耗时,所以放第一步) 1.opencv下载 1)官网:Releases - OpenCV 2)下载最新版本的android包 2.NCNN下载 1)NCNN下载地址(20220420版本):https://github.com/Tencent/ncnn/releases/download/20220420/ncnn-20220420-android-vulkan.zip 3.在你的…

【C++二分查找】2271. 毯子覆盖的最多白色砖块数

本文涉及的基础知识点 C二分查找 LeetCode2271. 毯子覆盖的最多白色砖块数 给你一个二维整数数组 tiles &#xff0c;其中 tiles[i] [li, ri] &#xff0c;表示所有在 li < j < ri 之间的每个瓷砖位置 j 都被涂成了白色。 同时给你一个整数 carpetLen &#xff0c;表…

使用 Jpom 自动化构建并部署项目

1、前言 Jpom 是一款专为开发者设计的轻量级运维工具。它提供了一整套从项目构建到自动部署&#xff0c;再到日常运维和项目监控的解决方案&#xff0c;帮助开发者更好地管理和维护项目。 Jpom 的目标是让开发者不再为复杂的运维流程头疼。它支持多种安装方式&#xff0c;灵活…

RoboCat: A Self-Improving Generalist Agent for Robotic Manipulation

发表时间&#xff1a;22 Dec 2023 论文链接&#xff1a;https://readpaper.com/pdf-annotate/note?pdfId4836882796542689281&noteId2413286807916664832 作者单位&#xff1a;Google DeepMind Motivation&#xff1a;受视觉和语言基础模型的最新进展的启发&#xff0c…

【教程】实测np.fromiter 和 np.array 的性能

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 函数简介 np.fromiter np.array 测试代码 实验结果 结果分析 实验总结 学长想说 函数简介 np.fromiter np.fromiter 是 NumPy 提供的一…

设计模式 -- 装饰者模式(Decorator Pattern)

1 问题引出 1.1 咖啡馆订单项目 咖啡种类/单品咖啡&#xff1a;Espresso(意大利浓咖啡)、ShortBlack、LongBlack(美式咖啡)、Decaf(无因咖啡) 调料&#xff1a;Milk、Soy(豆浆)、Chocolate 要求在扩展新的咖啡种类时&#xff0c;具有良好的扩展性、改动方便、维护方便 使用…

无人机之云台的作用

无人机云台在无人机技术中扮演着至关重要的角色&#xff0c;其作用主要体现在以下几个方面&#xff1a; 一、 确保拍摄稳定性 防抖动&#xff1a;无人机在飞行过程中&#xff0c;尤其是在复杂环境下&#xff0c;如遇到风力干扰或进行高速飞行时&#xff0c;机身容易产生震动和…

Beyond Compare忽略特定格式文本,忽略匹配正则表达式

一 概述 文本对比时忽略某些文本。比如有些生成的文件需要做差异对比&#xff0c;除了内容有差异外&#xff0c;自动生成的ID也不同&#xff0c;想忽略这些ID。特别是文件内容比较多的时候。 如上图&#xff0c;其中UUID“*”的部分我想忽略。 二 方法 方法1 通过Beyond Co…

MySQL 中间件 MySQL-Router

目录 1 MySQL-Router 的介绍 2 MySQL-Router 负载均衡 2.1 设计目的&#xff1a; 2.2 HAProxy 与 Nginx 和 MySQL-Router 之间的区别 2.3 MySQL-Router 的优势 3 MySQL-Router 的获取 3 MySQL-Router 的使用 3.1 实验环境 3.2 MySQL-Router 部署 3.3 MySQL-Router 配置 3.4 测…

HarmonyOS--合理使用动画

一、概述 动画是应用开发中必不可少的部分&#xff0c;它可以使应用程序更加生动和易于互动&#xff0c;一方面可以提升用户体验、增强视觉吸引力&#xff0c;另一方面可以引导用户操作、提高信息传达效率。应用程序中&#xff0c;页面层级间的转场、点击交互、手势操控都可以添…