Linux下UDP编程

news2024/12/24 8:12:32

一.概念介绍

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.coloradmin.cn/o/2082518.html

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

相关文章

Cobalt Strike 4.8 用户指南-第四节-监听器和基础设施管理

4.1、概述 任何行动的第一步都是建立基础设施。在 Cobalt Strike 中&#xff0c;基础设施由一台或多台团队服务器、重定向器以及指向团队服务器和重定向器的 DNS 记录组成。一旦团队服务器启动并运行&#xff0c;你将需要连接到它&#xff0c;并将其配置为接收来自受感染系统的…

呼叫中心系统数据分析报表统计

呼叫中心系统在客服职场中具有非常重要的作用&#xff0c;可以说如果呼叫中心系统瘫痪整个客服职场都无法工作。呼叫中心的数据统计分析功能对于企业来说也是非常重要的&#xff0c;能够快速帮助企业生成各种数据报表。 呼叫中心系统数据分析统计功能包括&#xff1a;工作量统计…

解锁AI力量:Gemini模型在Android中的技术应用

说在前面的话 大型语言模型&#xff08;LLM&#xff09;是近年来人工智能领域最令人瞩目的突破之一。它们拥有强大的语言理解和生成能力&#xff0c;能够完成各种任务&#xff0c;为我们打开了一个全新的世界。 以下是一些常见的使用场景&#xff1a; 1. 内容创作&#xff1…

如何为你的jar包上保险,防止别人反编译获取代码。Jar混淆全网最详细教学

写在前面:众所周知,Java程序不管使用maven或者Gradle进行构建,都可以获得一个可运行的jar包,比如现在我写了一个IDEA插件可以实现在IDEA中输入中文的名称之后自动变成是规范的英文类,那么在进行友好的分享时候,如何防止自己的jar依赖被别人翻版,就是本次给大家提供的教学…

Android 12系统源码_输入系统(二)InputManagerService服务

前言 上一篇我们简单介绍了Android系统输入事件的常见类型和事件的传递流程&#xff0c;输入事件的传递流程主要分三个部分&#xff0c;输入系统处理部分、WMS处理部分、View处理部分。 其中输入系统处理部分细分为输入子系统处理部分和InputManagerService处理部分&#xff…

嵌入式学习----IO多路复用

1.概念&#xff1a;多个IO复用一个进程 2.IO多路复用的一般实现&#xff1a; &#xff08;1&#xff09;创建文件描述符集合 &#xff08;2&#xff09;添加文件描述符到集合中 &#xff08;3&#xff09;通知内核开始监测 &#xff08;4&#xff09;根据返回的结果做对应…

TESSY创建单元测试或集成测试工程

我们以tessy5.1 IDE为例&#xff0c;给大家展示工程的创建过程。 1、打开TESSY5.1软件后&#xff0c;会弹出&#xff1a; 2、点击NEW Project后&#xff0c;会弹出&#xff1a; 3、接下来&#xff0c;就可以打开刚创建的工程&#xff1a; 4、进入到TESSY的主界面后&#xff0c…

清凉行动启航!汕头电信爱心翼站夏送清凉,每一份汗水都值得被温柔以待

8月中旬汕头电信濠江营业厅开展了“与你一起&#xff0c;清凉一夏”爱心翼站•夏送清凉活动。 在温馨的活动氛围中&#xff0c;爱心翼站的爱心大使与志愿者们&#xff0c;以生动有趣的小课堂&#xff0c;为小朋友们揭开了中暑这一话题的神秘面纱&#xff0c;细致阐述了其定义及…

在团队里对着干的人

在团队里对着干的人&#xff0c;踢走&#xff1b; 在团队里跟着干的人&#xff0c;培养&#xff1b; 在团队里帮着干的人&#xff0c;分钱&#xff1b; 在团队里领着干的人&#xff0c;分红。 这是规律也是规矩&#xff0c;一个真正的强者&#xff0c;是看他帮助了多少人&#…

CLIP微调方法总结

文章目录 前言1️⃣ Tip-Adapter论文和源码原理介绍 2️⃣Cross-modal Adaptation&#xff08;跨模态适应&#xff09;论文和源码原理介绍 3️⃣ FD-Align&#xff08;Feature Discrimination Alignment&#xff0c;特征判别对齐&#xff09;论文和源码原理介绍 总结 前言 本文…

教您用军团要塞2服务器开服联机教程

1、购买后登录服务器 进入控制面板后会出现正在安装的界面 2、下载连接工具 打开Steam库中搜索Source SDK Base 2013 Multiplayer并安装 3、下载游戏 以下三个链接均为同一个游戏 百度 通过百度网盘分享的文件&#xff1a;tf2classic.zip 链接&#xff1a;百度网盘 请输入提…

(最新)华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—(共12套)(每套四十题)

&#xff08;最新&#xff09;华为 2024 届秋招-硬件技术工程师-单板硬件开发—机试题—&#xff08;共12套&#xff09;&#xff08;每套四十题&#xff09; 岗位——硬件技术工程师 岗位意向——单板硬件开发 真题题目分享&#xff0c;完整版带答案(有答案和解析&#xff0…

浅析WebRTC技术在智慧园区视频管理场景中的应用

随着科技的飞速发展&#xff0c;智慧园区作为城市智慧化的重要组成部分&#xff0c;正逐步成为现代化管理的重要方向。智慧园区的建设不仅涉及硬件设施的智能化升级&#xff0c;还离不开高效的视频管理和实时通信技术。在这一背景下&#xff0c;WebRTC&#xff08;Web Real-Tim…

BackdoorLLM:一个针对生成性LLMs后门攻击的全面基准测试

大型语言模型&#xff08;LLMs&#xff09;在从自然语言理解到机器翻译等一系列任务上取得了显著的突破性进展。例如&#xff0c;GPT-4模型展示了在生成类人文本和解决复杂问题方面的前所未有的能力。然而&#xff0c;近期的研究表明&#xff0c;LLMs存在一个关键的脆弱性&…

sqli-labs靶场通关攻略(41-45关)

第41关 这关我们使用工具sqlmap练习一下&#xff08;这里如果用本机的回环地址访问靶场的话只能在你的本机访问&#xff0c;因为我们是在虚拟机上进行扫描&#xff0c;所以不能使用127.0.0.1访问&#xff09; 进入虚拟机kali&#xff0c;打开终端 查库 sqlmap -u 网址 -- curr…

uniapp生活记账小程序

Springboot vue uniapp生活记账小程序&#xff0c;前端采用vue uni-app设计开发&#xff0c;后端采用 Springboot 开发前端对应的数据接口&#xff0c;首页显示生活账单信息&#xff0c;我的野蛮统计记账信息和微信登录状况。记账页面可以&#xff0c;根据不同类别的日常消费记…

MySQL集群技术4——MySQL路由

mysql-route MySQL 路由&#xff08;Routing&#xff09;通常指的是在 MySQL 架构中如何处理客户端请求和数据流向的问题。在 MySQL 中&#xff0c;路由可以涉及多种不同的场景和技术&#xff0c;包括但不限于反向代理、负载均衡、读写分离等。下面我将详细介绍这些场景和技术…

如何反射获取类的全部信息?(java代码)

什么是反射&#xff1f; 反射是 Java 提供的一种机制&#xff0c;允许在运行时动态地获取类的信息&#xff08;如类的名称、方法、字段等&#xff09;&#xff0c;以及创建对象和调用方法。反射利用了 java.lang.reflect 包中的类&#xff0c;如 Class、Method、Field 和 Cons…

仿BOSS招聘系统开发:构建高效、智能的在线招聘平台

在数字化时代&#xff0c;招聘行业正经历着前所未有的变革。BOSS直聘作为国内领先的招聘平台&#xff0c;以其高效的匹配机制、丰富的职位信息和便捷的用户体验&#xff0c;赢得了广泛的市场认可。本文将探讨如何开发一个仿照BOSS招聘系统的在线招聘平台&#xff0c;旨在为企业…

8月28复盘日记

8月28复盘日记 前言今日感恩今日知识今日反思今日名言 前言 今天早上是六点半起床嘻嘻&#xff0c;这两天因为生理期,皮质醇似乎有些高,入睡会有些困难。但是因为今天是开学第一天&#xff0c;意味着&#xff0c;健身房恢复晨练了&#xff01;我可太喜欢晨练时间安安静静的健身…