socket编程---UDP

embedded/2025/4/2 6:38:28/

目录

一、socket

二、socket接口

1.流程原理

2.代码


前言

提示:这里可以添加本文要记录的大概内容:

        socket编程又称套接字编程,指进行网络通信程序的编写


提示:以下是本篇文章正文内容,下面案例可供参考

一、socket

网络通信就是将原始数据进行tcp/ip四层封装,通过网卡发送实现通信

网络通信分为:客户端、服务端。

        客户端:在客户这一端的进程,是主动发送请求的一端。客户端必须提前知道服务端的

                       地址与端口才能给服务端发送请求。

        服务端:提供服务的一端进程,是被动接收请求从而进行处理的一端。

二、socket接口

1.UDP通信流程原理

        sockaddr 是一个通用的套接字地址结构体,包含了一个地址族和地址数据,主要用来存储和传递套接字地址信息的。

        struct sockaddr { unsigned short sa_family; // 地址族 char sa_data[14]; // 地址信息 };

字节序转换接口---将主机字节序转化为网络字节序,字节序是存储多字节数据的

        uint16_t htons(uint16_val);        uint16_t ntons(uint16_val);     —   返回uint16_t数据

        uint32_t htonl(uint32_t val)        uint32_t ntonl(uint32_t val)     —   返回uint32_t数据

           所以2字节只能使用s进行转换,4字节只能属于l,这是指定的不能使用其他的

        

        in_addr_t inet_addr(const char* ip)    //将字符串IP地址转换为网络字节序整形IP地址

        const char* inet_ntoa(struct in_addr_t inet_addr;)         //将网络字节序整形IP地址转换

                                                                                                 为字符串IP地址

socket接口:

        int socket(int domain, int type, int protocol);     //创建socket,返回一个socket描述符

                domain:指定了套接字使用的协议        AF_INET:用IPv4网络协议

                       AF_INET6:用IPv6网络协议        AF_UNIX或AF_LOCAL:本地进程间通信

                type:指定套接字的类型

                        SOCK_STREAM:字节流传输通常用于TCP

                        SOCK_DGRAM:数据报传输通常用于UDP

                protocol:协议类型:通常设置为0

                        IPPROTO_TCP:TCP协议

                        IPPROTO_UDP:UDP协议

                返回值:失败返回-1

绑定地址接口

        int bind(int sockfd, struct sockaddr *addr, socklen_t addrlen) //为创建的套接字绑定一个

                                                                                                          地址

                sockfd:创建套接字返回的描述符

                addr:指向sockaddr结构体指针,包含要绑定的地址信息

                addrlen:地址长度,取决于IP协议类型

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

发送数据接口:

        ssize_t sendto(

                                int sockfd,        //返回的套接字描述符                                                                                                                                                                                                          

                                void *buf,       //要发送数据的缓冲区指针

                                size_t len,,        //要发送的数据的长度--字节

                                int flags,            //通常设置为0-阻塞发送, MSG_DONTWAIT--非阻塞

                                struct sockaddr *_addr,        //一个指向sockaddr结构体指针,实际

                                                                                     使用中通常会使用 sockaddr_in(对于

                                                                                     IPv4)或 sockaddr_in6(对于IPv6)-

                                                                                     目的端地址信息

                                socklen_t addrlen        地址长度

                                )

                返回值:成功返回实际发送的数据长度,失败返回-1

接收数据接口

        ssize_t recvfrom(

                                int sockfd,

                                void *buf        //存放接收数据的缓冲区指针--空间地址

                                size_t len        //要接收数据的长度

                                int flags,        //

                                struct sockaddr *dest_addr,        //对端地址信息

                                socklen_t addrlen         //用于设定想要获取的地址长度

                                   )

                返回值:成功返回实际接收到的数据长度,失败返回-1

关闭套接字

        int close(int sockfd);

UDP协议:

        无连接、不可靠、面向数据报

        无连接:只要知道对方的地址就可以给对方发送数据

        不可靠:数据没有丢包检测,丢了就没了,且不保证有序

        面向数据包:传输以快为单位,有最大数据传输限制

其传输性能较高,多用于视频、音频等资源传输 

 

2.代码

服务端

// udp服务端程序
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <arpa/inet.h>//htons字节序转换接口
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>int main(int argc, char *argv[]){//argc表示命令行参数个数。如果你在命令行中运行程序 ./myprogram arg1 arg2,那么 argc 的值将为3("./myprogram", arg1, arg2)//  ./udp_ 192.168.x.x 9000if(argc != 3){perror("./udp_ 172.23.62.176 9000");}char *ip_ = argv[1];        //argv[0]是程序的名称,argv[1]是第一个参数ip地址uint16_t port_ = atoi(argv[2]);     //将字符串转化整数
//创建套接字int socketfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(socketfd < 0){perror("socket error");return -1;}
//绑定地址struct sockaddr_in addr;    //IPv4的结构体//配置结构体addr.sin_family = AF_INET;//地址族addr.sin_port  = htons(port_);      //导入ip地址addr.sin_addr.s_addr = inet_addr(ip_);socklen_t addrlen = sizeof(struct sockaddr_in); //计算接收的地址长度int bind_ = bind(socketfd, (struct sockaddr*) &addr, addrlen);if(bind_ < 0){perror("bind error");return -1;}while(1){
//接收数据char buf[1024] = {0};struct sockaddr_in cliaddr;socklen_t addrlen = sizeof(struct sockaddr_in);ssize_t recv = recvfrom(socketfd, buf, 1023, 0, (struct sockaddr*)&cliaddr, &addrlen);if(recv < 0){perror("recvfrom error");return -1;}uint16_t cliport = ntohs(cliaddr.sin_port);const char *cliip = inet_ntoa(cliaddr.sin_addr);printf("client[%s:%d] say: %s\n",cliip, cliport, buf);//发送数据printf("server say:");fflush(stdout);fgets(buf, 1023, stdin);//从键盘获取数据int send = sendto(socketfd, buf, strlen(buf), 0, (struct sockaddr*)&cliaddr, addrlen);if(send < 0){perror("sendto error");return -1;}}
//关闭套接字close(socketfd);return 0;
}

客户端

#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <error.h>#define CHECK_RET(r) if((r) == false){return -1;}class UdpSocket {private:int _socketfd;  //定义一个套接字public:UdpSocket() :_socketfd(-1) {}~UdpSocket() { Close(); }bool Socket() {//创建套接字_socketfd =  socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);if(_socketfd < 0){perror("Socket error");return false;}return true;}bool Bind(const std::string &ip, uint16_t port){        //绑定地址信息struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr(ip.c_str());socklen_t addrlen = sizeof(struct sockaddr_in);int bend_ = bind(_socketfd, (struct sockaddr*)&addr, addrlen);if(bend_ < 0){perror("Bind error");return false;}return true;}bool Send(const std::string &body, const std::string& ip, uint16_t port){       //发送数据struct sockaddr_in addr;addr.sin_family = AF_INET;addr.sin_port = htons(port);addr.sin_addr.s_addr = inet_addr(ip.c_str());socklen_t addrlen = sizeof(struct sockaddr_in);ssize_t send = sendto(_socketfd, body.c_str(), body.size(), 0, (struct sockaddr*)&addr, addrlen);if(send < 0){perror("Send error");return false;}return true;}bool Recv(std::string* body, std::string *ip = NULL, uint16_t *port = NULL){    //接收数据struct sockaddr_in addr;socklen_t addrlen = sizeof(struct sockaddr_in);char tmp[4096] = {0};ssize_t recv = recvfrom(_socketfd, tmp, 4096, 0, (struct sockaddr*)&addr, &addrlen);if(recv < 0){perror("Recv error");return false;}if(ip != NULL) *ip = inet_ntoa(addr.sin_addr);if(port != NULL) *port = ntohs(addr.sin_port);body->assign(tmp, recv);return true;}bool Close(){   //关闭套接字if(_socketfd < 0){return true;}close(_socketfd);_socketfd = -1;return true;}
};int main(int argc, char* argv[])
{if(argc != 3){std::cout <<"./udp 172.23.62.176 9000\n";return -1;}UdpSocket us;   //实例化对象
//创建套接字CHECK_RET(us.Socket());while(1){std::string buf;std::cout <<"client say:";fflush(stdout); //刷新输出缓冲区std::cin >> buf;//向缓冲区写入数据
//发送数据CHECK_RET(us.Send(buf, argv[1], std::stoi(argv[2])));
//接收数据buf.clear();    //清空缓冲区CHECK_RET(us.Recv(&buf));std::cout << "server say:" << buf << std::endl;}
//关闭套接字us.Close();return 0;
}


http://www.ppmy.cn/embedded/134583.html

相关文章

UDP组播测试

支持组播的接口&#xff1a; ip a | grep MULTICAST 环回接口虽然显示不支持组播&#xff0c;实际也可以用于本地测试。 添加路由&#xff08;非必须&#xff1f;&#xff09;&#xff1a; ip route add 239.0.0.0/24 via 10.10.10.206 dev eth0 开放防火墙&#xff1a; 查…

将机器人六轴坐标转为4*4矩阵(Opencv/C++)

已知机器人六轴坐标x,y,z,rx,ry,rz&#xff0c;其中xyz表示空间位置坐标&#xff0c;rx,ry,rz是欧拉角&#xff1b; 需要将这六个值转为4*4的矩阵以便后续其它处理运算。 代码如下&#xff1a; #include <opencv2/core.hpp> #include <iostream> #include <cm…

解决Redis缓存穿透(缓存空对象、布隆过滤器)

文章目录 背景代码实现前置实体类常量类工具类结果返回类控制层 缓存空对象布隆过滤器结合两种方法 背景 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在&#xff0c;这样缓存永远不会生效&#xff0c;这些请求都会打到数据库 常见的解决方案有两种&#xff0c;分别…

江协科技STM32学习- P30 FlyMCU串口下载STLink Utility

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

【缓存与加速技术实践】NoSQL之Redis部署安装与基础命令

文章目录 关系型数据库与非关系型数据库关系型数据库SQL定义SQL语句主流产品 非关系型数据库NoSQL定义主流产品 区别数据存储方式不同扩展方式不同对事务性的支持不同应用场景结构对比 补充 RedisRedis 的特点与优势Redis 的使用场景哪些数据适合放入缓存中&#xff1f;Redis 为…

构建安全的用户登录API:从请求验证到JWT令牌生成

构建安全的用户登录API&#xff1a;从请求验证到JWT令牌生成 为了实现这个后端POST /api/users/login端点&#xff0c;我们可以使用Node.js和Express框架&#xff0c;并结合一些常用的库如jsonwebtoken、bcrypt和express-validator来处理验证和密码校验。下面是一个完整的示例…

20.04Ubuntu配置opencv并使用头文件

跟着我的步骤一步步来 第一步&#xff1a;你可以使用以下命令安装OpenCV&#xff1a; sudo apt-get update sudo apt-get install libopencv-dev第二步&#xff1a;检查是否安装成功&#xff0c;成功的话会返回版本 pkg-config --modversion opencv由于我安装的4开头的版本&…

spring 学习路线梳理(二)注解

1.通过注解的方式创建bean 1.1 定义dao层的接口和实现 public interface ILoginDao {public String login(); }Slf4j Repository public class LoginDaoImpl implements ILoginDao {public LoginDaoImpl(){System.out.println("spring create bean call");}Override…