linux网络编程——UDP编程

news2024/12/24 8:15:57

写在前边

本文是B站up主韦东山的4_8-3.UDP编程示例_哔哩哔哩_bilibili视频的笔记,其中有些部分博主也没有理解,希望各位辩证的看。

UDP协议简介

UDP 是一个简单的面向数据报的运输层协议,在网络中用于处理数据包,是一种无连接的协议。UDP 不提供可靠性的传输,它只是把应用程序传给 IP 层的数据报发送出去,但是并不能保证它们能到达目的地。由于 UDP 在传输数据报前不用在客户和服务器之间建立一个连接,且没有超时重发等机制,故而传输速度很快。

对于UDP网络编程步骤,这里借用韦山东老师的图:

图 3UDP 用户数据包模式

UDP相对于TCP编程来说简单了很多,因为UDP没有TCP那些可靠连接的东西,所以编程相对来说也简单了一些。

这里对于函数,只有发送和接受函数和之前有点区别:

sendto()

函数结构

#include <sys/types.h>

#include <sys/socket.h>

ssize_t sendto ( socket s , const void * msg, int len, unsigned int flags, const

struct sockaddr * to , int tolen ) ;

描述

sendto() 用来将数据由指定的socket传给对方主机。

参数

- s

用于通信的通信描述符,对于服务器,就是指accept函数返回的通信描述符

- msg

指向一片应用缓存,用于存放要发送的数据,存放数据一般使用结构体变量。

- len

存放发送数据的缓存的大小。

- flags

一般设置为0,此时是阻塞发送的,阻塞发送是指发送数据不成功会一直阻塞,直到被某信号中断或发送成功为止,不过发送数据一般不阻塞。

- to

存放指定欲传送的网络地址,结构sockaddr请参考bind()。

- tolen

sockaddr的结构长度。

- 返回值

成功:返回发送的字节数,失败:返回-1

recvfrom()

函数结构

#include <sys/types.h>

#include <sys/socket.h>

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,

                 struct sockaddr *src_addr, socklen_t *addrlen);

描述

它是一个系统调用,用于从套接字接收数据。该函数通常与无连接的数据报服务(如 UDP)一起使用,但也可以与其他类型的套接字使用。与简单的 recv() 函数不同,recvfrom() 可以返回数据来源的地址信息。

参数

- sockfd

一个已打开的套接字的描述符

- buf

指明一个缓冲区,该缓冲区用来存放recvfrom函数接收到的数据

- len

指明buf的长度。

- flags

传0 表示使用默认协议。

- src_addr

一个指针,指向一个 sockaddr 结构,用于保存发送数据的源地址,结构sockaddr请参考bind()。

- addrlen

src_addr的结构长度。当 recvfrom() 返回时,该值会被修改为实际地址的长度(以字节为单位)。

- 返回值

成功:成功执行时,返回接收到的字节数。,失败:返回-1。

剩下的函数请参考TCP中的函数:linux网络编程——TCP编程-CSDN博客

现在分别实现server 程序和client 程序。

server程序

在这个函数中参照server图进行编程,将图中所有函数挨个实现即可。

图 4server

具体实现看代码:

#include <sys/types.h>          /* See NOTES */

#include <sys/socket.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <netinet/in.h>

#include <sys/wait.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <pthread.h>







/*

* 服务器端程序

* socket

* bind

* sendto/recvfrom

* close

*/

#define PORT 8888



struct Param {

    int sockfd;

    char* buff;

    struct sockaddr* src_addr;

};



// 接收数据在子线程中处理

void* Receive_data(void* Param1)

{



    struct Param Param2 = *(struct Param*)Param1;



    while (1)

    {

        // 接收数据

        int addr_len = sizeof(Param2.src_addr);

        int iRecvLen = recvfrom(Param2.sockfd, Param2.buff, sizeof(Param2.buff), 0, Param2.src_addr, &addr_len);

        if (iRecvLen > 0)

        {

            Param2.buff[iRecvLen] = '\0';

            // inet_ntoa(tSocketClientAddr.sin_addr)是将IP地址转换为字符串的函数

            printf("Get Msg From Client: %s: %s\n", inet_ntoa(((struct sockaddr_in*)Param2.src_addr)->sin_addr), Param2.buff);

        }

    }

   

}

int main(int argc, char** argv)

{

    int isocketfd;

    int Client_socketfd;

    int ret;

    struct sockaddr_in my_addr;

    struct sockaddr_in Client_addr;

    char send_buf[1024];

    char buff[1000];

    struct Param Param1;

    pthread_t ntid;

    // SOCK_DGRAM是UDP协议,AF_INET表示IPv4协议

    isocketfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (-1 == isocketfd)

    {

        printf("create socket failed!\n");

        return -1;

    }

    // 配置bind函数的地址信息

    my_addr.sin_family      = AF_INET;  //指定协议族为IPV4版本的TCP/IP协议族

    my_addr.sin_port        = htons(PORT);  //指定端口号(和客户端通信的端口号,两者必须一致)

    my_addr.sin_addr.s_addr = htonl(INADDR_ANY);  //指定IP地址,这里设置为INADDR_ANY,表示可以接收任何来源的连接请求

    ret = bind(isocketfd, (const struct sockaddr*)&my_addr,sizeof(struct sockaddr));

    if (-1 == ret)

    {

        printf("bind socket failed!\n");

        return -1;

    }



    Param1.sockfd = isocketfd;

    Param1.buff = buff;

    Param1.src_addr = (struct sockaddr*)&Client_addr;

    ret = pthread_create(&ntid, NULL, Receive_data, &Param1);

    if (ret)

    {

        printf("create pthread failed!\n");

        return -1;

    }

    while (1)

    {

        // 发送数据

        if (fgets(send_buf, sizeof(send_buf), stdin))

        {

            sendto(isocketfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&Client_addr, sizeof(Client_addr));

        }

       

       

    }

    close(isocketfd);

    return 0;

}

这里使用了多线程将发送和接收数据分开,实现发送和接收数据互不干涉,其中pthread_create()函数是创建一个线程,具体函数分析见pthread_create()章节,这里将接收数据放入了创建的子线程中,主函数中实现发送函数。

图 5服务器端测试结果

这里获得的数据,其中192.168.147.132的IP是客户端的数据。

client 程序

在客户端的程序中,基本思路还是和之前服务器的程序相同,都是使用多线程将接收数据放入了创建的子线程中,还是依照韦老师的图:

图 6client

依次实现如上函数即可,具体实现如下代码:

#include <sys/types.h>          /* See NOTES */

#include <sys/socket.h>

#include <stdio.h>

#include <stdlib.h>

#include <errno.h>

#include <string.h>

#include <netinet/in.h>

#include <sys/wait.h>

#include <unistd.h>

#include <arpa/inet.h>

#include <pthread.h>



/*

* UDP客户端程序

* socket

* send

* close

*/



#define PORT 8888



// 线程参数结构体

struct Param {

    int sockfd;

    char* buff;

    struct sockaddr* src_addr;

};



// 接收数据在子线程中处理

void* Receive_data(void* Param1)

{



    struct Param Param2 = *(struct Param*)Param1;



    while (1)

    {

        // 接收数据

        int addr_len = sizeof(Param2.src_addr);

        int iRecvLen = recvfrom(Param2.sockfd, Param2.buff, sizeof(Param2.buff), 0, Param2.src_addr, &addr_len);

        if (iRecvLen > 0)

        {

            Param2.buff[iRecvLen] = '\0';

            // inet_ntoa(tSocketClientAddr.sin_addr)是将IP地址转换为字符串的函数

            printf("Get Msg From Client: %s: %s\n", inet_ntoa(((struct sockaddr_in*)Param2.src_addr)->sin_addr), Param2.buff);

        }

        else if (iRecvLen == -1)

        {

            perror("recvfrom failed");

            break;

        }

    }



}





int main(int argc, char** argv)

{

    int isocketfd;

    struct sockaddr_in client_addr;

    char send_buf[1024];

    struct Param Param1;

    pthread_t ntid;

    char reve_buff[1024];

    memset(send_buf, 0, sizeof(send_buf));

    if (argc < 2)

    {

        printf("Usage: %s ip_address\n", argv[0]);

        return -1;

    }



    client_addr.sin_family = AF_INET;  //指定协议族为IPV4版本的TCP/IP协议族

    client_addr.sin_port = htons(PORT);  //指定端口号

    //指定IP地址,htons()函数是将一个本地字节序的short转为网络字节序的short

    client_addr.sin_addr.s_addr = inet_addr(argv[1]);

    isocketfd = socket(AF_INET, SOCK_DGRAM, 0);

    if (-1 == isocketfd)

    {

        printf("create socket failed!\n");

        return -1;

    }

    Param1.sockfd = isocketfd;

    Param1.buff = reve_buff;

    Param1.src_addr = (struct sockaddr*)&client_addr;

    int ret = pthread_create(&ntid, NULL, Receive_data, &Param1);

    if (ret)

    {

        printf("create pthread failed!\n");

        return -1;

    }

    while (1)

    {

        if (fgets(send_buf, sizeof(send_buf), stdin))

        {

            sendto(isocketfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&client_addr, sizeof(client_addr));

        }

    }

    return 0;

}

图 7客户端测试结果

连接成功后即可发送和接收数据。

pthread_create()

函数结构

#include <pthread.h>

int pthread_create(pthread_t* restrict tidp,const pthread_attr_t* restrict_attr,void* (*start_rtn)(void*),void *restrict arg);

描述

用来创建线程,并向线程函数传递参数。

参数

- tidp

事先创建好的pthread_t类型的参数。成功时tidp指向的内存单元被设置为新创建线程的线程ID。

- attr

用于定制各种不同的线程属性。通常直接设为NULL。

- start_rtn

新创建线程从此函数开始运行。无参数时arg设为NULL即可。

- arg

start_rtn函数的参数。无参数时设为NULL即可。有参数时输入参数的地址。当多于一个参数时应当使用结构体传入。

- 返回值

成功:返回0,失败:返回错误码。

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

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

相关文章

操作系统 ---- 处理机调度

一、处理机调度学习路线 二、调度要研究的问题&#xff1f; 当有一堆任务要处理&#xff0c;但由于资源有限&#xff0c;这些事情没法同时处理。这就需要确定某种规则来决定处理这些任务的顺序&#xff0c;这就是“调度”研究的问题。 三、调度的三个层次 3.1 高级调度&…

深入解读Docker核心原理:Namespace资源隔离机制详解

在容器技术中&#xff0c;资源隔离 是容器化能够实现轻量级虚拟化的关键技术之一。通过资源隔离&#xff0c;容器可以拥有自己的独立环境&#xff0c;确保容器之间互不干扰&#xff0c;从而实现应用的安全和稳定。Docker作为主流的容器平台&#xff0c;其核心的资源隔离机制依赖…

LabVIEW软件授权与分发要求

在LabVIEW开发中&#xff0c;将软件打包成安装程序并销售给其他公司&#xff08;例如对知识产权有严格要求的国外公司&#xff09;时&#xff0c;涉及授权和许可的多个关键环节。NI对LabVIEW的开发、分发、安装和使用都有明确的授权要求&#xff0c;以确保知识产权的合法性和软…

CentOS 7 最小化安装后如何安装图形化桌面

CentOS 7 最小化安装后如何安装图形化桌面 一、准备工作1. 登录系统2. 配置网络 二、安装图形化桌面1. 安装 X Window System2. 安装 GNOME 桌面 三、配置默认启动模式1. 查看当前启动模式2. 修改默认启动模式 四、重启系统并验证 &#x1f496;The Begin&#x1f496;点点关注…

基于微信小程序的高校实验室管理系统的设计与实现

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 基于微信小程序JavaSpringBootVueMySQL的高…

FreeRTOS学习笔记(十一)内存管理

文章目录 前言一、内存管理1.1 内存管理的引入1.2 内存碎片 二、内存分配的方法2.1 heap_12.1.1 实现原理2.1.2 源码解析 2.2 heap_2 内存分配方法2.2.1 实现原理2.2.2 源码解析 2.3 heap_3 内存分配方法2.4 heap_4 内存分配方法2.4.1 实现原理2.4.2 源码解析 2.5 heap_5 内存分…

【论文解读系列】DPD-BiReconstructor的神经网络架构

原标题&#xff1a;Semisupervised Neural Proto-Language Reconstruction 论文地址&#xff1a;https://arxiv.org/pdf/2406.05930 现有实现祖先语言&#xff08;原语言&#xff09;比较重建的工作通常需要完全监督。然而&#xff0c;如果历史重建模型只能用少量标记数据进行训…

二、栈和队列-算法总结

文章目录 二、栈和队列2.1 基本应用2.1.1 逆波兰表达式求值2.1.2 有效的括号 2.2 单调栈2.2.1 柱状图中最大的矩形 二、栈和队列 2.1 基本应用 2.1.1 逆波兰表达式求值 150. 逆波兰表达式求值 class Solution {/**思路分析&#xff1a;遇到数则压栈&#xff0c;遇到运算符…

每日一练12:杨辉三角(含链接)

1.链接 杨辉三角_牛客题霸_牛客网 2.题目 3.代码 #include <iostream> #include<vector> using namespace std; vector<int> arr(35); int main() {int n;cin>>n;for(int i1;i<n;i){if(i1) {printf("%5d",1);arr[1]1;cout<<end…

电商API接口安全:构建稳固的数字防线

电子商务的蓬勃发展带来了前所未有的便利&#xff0c;同时也带来了新的安全挑战。API接口作为电商系统的核心组件&#xff0c;其安全性直接关系到企业的数据安全和业务连续性。因此&#xff0c;评估和加固电商API接口的安全性变得尤为重要。 电商API接口安全的重要性 电商API接…

【Redis】Redis 典型应用 - 分布式锁原理与实现

目录 Redis 典型应⽤ - 分布式锁什么是分布式锁分布式锁的基础实现引⼊过期时间引⼊校验 id引⼊ lua引⼊ watch dog (看⻔狗)引⼊ Redlock 算法其他功能 Redis 典型应⽤ - 分布式锁 什么是分布式锁 在⼀个分布式的系统中&#xff0c; 也会涉及到多个节点访问同⼀个公共资源的…

YOLOv5改进:CA注意力机制【注意力系列篇】(附详细的修改步骤,以及代码)

如果实验环境尚未搭建成功&#xff0c;可以参考这篇文章 ->【YOLOv5超详细环境搭建以及模型训练&#xff08;GPU版本&#xff09;】 文章链接为&#xff1a;http://t.csdnimg.cn/Ke0bb ---------------------------------------------------------------------------​ 1…

09-排序1 排序(C)

这一节&#xff0c;测试各类排序算法的运行速度&#xff08;没有基数排序&#xff08;桶&#xff09; 其实在实际学习中&#xff0c;还是有意义的 给定 n 个&#xff08;长整型范围内的&#xff09;整数&#xff0c;要求输出从小到大排序后的结果。 本题旨在测试各种不同的排序…

Unity Addressables 使用说明(三)构建内容(Build Content)

Build Content 【概述】Build Content 内容构建会处理 Addressables 组&#xff0c;生成内容目录&#xff08;content catalog&#xff09;、运行时设置以及包含你的资源的 AssetBundles。Addressables 使用这些文件在运行时加载内容。 你可以配置 Addressables 系统将 Addr…

重磅!OpenAI正式发布博士水平的推理模型o1!附详细说明

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;所以创建了“AI信息Gap”这个公众号&#xff0c;专注于分享AI全维度知识…

【android10】【binder】【2.servicemanager启动——全源码分析】

系列文章目录 可跳转到下面链接查看下表所有内容https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501文章浏览阅读2次。系列文章大全https://blog.csdn.net/handsomethefirst/article/details/138226266?spm1001.2014.3001.5501 目录 …

登山第九梯:稀疏点云实例分割——又快又准

文章&#xff1a;Fast Range Image-Based Segmentation of Sparse 3D Laser Scans for Online Operation 代码&#xff1a;https://github.com/PRBonn/depth_clustering 1&#xff09;摘要 从 3D 距离数据中分割对象是移动机器人领域的一个重要主题。在动态环境中导航的机器人需…

C51单片机-单按键输入识别,键盘消抖

【实验目的】 独立按键的识别方法、键盘消抖等。 【实验现象】 每按一次独立键盘的S2键&#xff0c;与P1口相连的八个发光二极管中点亮的一个往下移动一位。 【实验说明】 关于按键去抖动的解释&#xff0c;我们在手动按键的时候&#xff0c;由于机械抖动或是其它一些非人为的因…

NR PDSCH/PUSCH支持的maxMIMO layers

这里不考虑UE支持的具体MIMO能力&#xff0c;仅仅讨论协议上定的maxMIMO layers。 PDSCH 根据上面38.331中的结构&#xff0c;PDSCH max MIMO layers 为8 layers&#xff0c;进行8 layers传输时 要enable two codewords&#xff0c;因为 one codeword只能支持4 layers传输&…

【信创】Linux系统如何配置USB存储禁用及例外 _ 统信 _ 麒麟 _ 方德

原文链接&#xff1a;【信创】Linux系统如何配置USB存储禁用及例外 | 统信 | 麒麟 | 方德 Hello&#xff0c;大家好啊&#xff01;今天给大家带来一篇关于如何在Linux系统中配置USB存储禁用及例外的文章。禁用USB存储可以有效防止未经授权的人员从系统中复制数据或注入恶意软件…