当前位置: 首页 > news >正文

C语言-网络编程-UDP通信创建流程

UDP 通信创建流程

UDP 是⼀个传输层的⽆连接的协议,我们编写代码⼀般是分为两个端。⼀个我们称之为发送端,另⼀
个我们称之为接收端。正常⼀般是接收端先运⾏,然后等待结束发送端发送过来的数据。

在这里插入图片描述

创建套接字

首先,我们需要创建套接字,套接字是通信的基础。我们可以通过 socket() 函数来创建套接字。

int socket(int domain, int type, int protocol);
参数:@domain地址族AF_UNIX, AF_LOCAL  本地通信,数据不仅过网卡AF_INET         IPV4 ineter⽹通信  AF_INET6        IPV6 ineter⽹通信AF_PACKET       网卡上的数据包通信....@ type使⽤协议类型SOCK_STREAM 流式套接字(TCP)SOCK_DGRAM 报⽂套接字(UDP)SOCK_RAW原始套接字: (IP,ICMP)......@protocol协议编号0 : 让系统⾃动识别IPPROTO_TCP : TCP协议IPPROTO_UDP : UDP协议返回值:成功返回得到的⽂件描述符。当前可使用的最小描述符失败返回 -1

发送消息 sendto()

发送端通过 sendto() 函数来发送消息。

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);参数:@sockfd 套接字文件描述符@buf  发送内容 数据存放的⾸地址@len  期望发送的数据的长度⼤⼩@flags 操作⽅式    0 表示默认操作@dest_addr 向指定的地址发送数据@addrlen  发送的地址的⼤⼩返回值:成功返回实际发送的字节数,失败返回-1struct sockaddr {unsigned short sa_family; // 地址族 对应socket()中的domainchar sa_data[14]; // 地址数据 ip地址端口信息
};struct sockaddr_in { short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr
};struct in_addr {uint32_t       s_addr; // IP地址
};

示例用法:

//填充信息
struct sockaddr_in peer_addr;
peer_addr.sin_family = AF_INET;
peer_addr.sin_port = htons(8080);
peer_addr.sin_addr.s_addr = inet_addr("192.168.0.88");
//发送信息
n = sendto(sockfd,buf,n,0,(struct sockaddr *)&peer_addr,sizeof(struct sockaddr_in));

示例 发送数据

// todo UDP发送端
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>//?发送数据
//?@param fd 套接字描述符
//?@param addr 目标地址
//?@param addrlen 地址长度
void send_data(int fd, struct sockaddr_in * addr , socklen_t addrlen);//命令行参数 ip port
int main(int argc, char *argv[] ){
//    if(argc!= 3){
//        printf("Usage: %s ip port\n", argv[0]);
//        exit(EXIT_FAILURE);
//    }//!通过socket函数创建套接字//!@param domain 协议族,AF_INET表示IPv4协议族//!@param type 套接字类型,SOCK_DGRAM表示UDP套接字//!@param protocol 协议,一般为0 让系统⾃动识别//!@return 成功返回套接字描述符,失败返回-1int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){    //创建套接字失败perror("socket err");exit(EXIT_FAILURE);}//准备接收消息的地址/*      struct sockaddr_in {short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr};*/struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(8080);//htons函数将主机字节序转换为网络字节序//addr.sin_addr.s_addr=inet_addr("192.168.74.1");//inet_addr()将点分十进制IP地址转换为网络字节序IP地址//inet_aton()将点分十进制IP地址转换为网络字节序IP地址//@param ip 字符串形式的IP地址//@param in_addr 结构体变量,用于存储IP地址int ret=inet_aton("172.17.128.1", &addr.sin_addr); // 成功返回⾮0,失败返回0if(ret == 0){perror("inet_aton err");exit(EXIT_FAILURE);}printf("ip == %d\n",addr.sin_addr.s_addr);//inet_ntoa()将网络字节序IP地址转换为点分十进制IP地址//char *ip=inet_ntoa(addr.sin_addr); // 成功返回⾮0,失败返回0//printf("ip == %s\n",ip);send_data(fd, &addr, sizeof(addr));return 0;
}//!发送数据
//!@param fd 套接字描述符
//!@param addr 目标地址
//!@param addrlen 地址长度
void send_data(int fd, struct sockaddr_in * addr , socklen_t addrlen){while (1){int n = 0;//返回发送的字节数char buf[1024] = {0};printf("请输入要发送的消息:");fgets(buf, 1024, stdin);//!发送数据//!@param fd 套接字描述符//!@param buf 发送缓冲区//!@param len 发送缓冲区长度//!@param flags 发送标志  0 表示默认操作//!@param addr 目标地址//!@param addrlen 地址长度//!@return 成功返回发送的字节数,失败返回-1n= sendto(fd, buf, strlen(buf), 0, (struct sockaddr *)addr, addrlen);if(n == -1){perror("sendto err");exit(EXIT_FAILURE);}if(strncmp(buf, "exit",4) == 0){break;}}
}

bind() 绑定地址

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
功能:绑定套接字到地址。参数:@sockfd 套接字文件描述符@addr  绑定的地址结构体@addrlen 地址结构体的长度返回值:成功返回0,失败返回-1

recvfrom() 接收消息

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
功能:从套接字接收数据。参数:@sockfd 套接字文件描述符@buf  接收缓冲区@len  接收缓冲区的长度@flags 接收标志  0 表示默认操作@src_addr 发送端地址结构体 ,如果不为NULL,会获取发送方的地址放入该结构体@addrlen  发送端地址结构体的长度 值结果参数,必须进⾏初始化, 表示表示对⽅实际地址的⼤⼩。返回值:成功返回实际接收的字节数,失败返回-1

示例 服务端

// todo UDP服务器端程序
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>//接收数据
void recv_data(int sockfd);int main(int argc, char *argv[]){//!通过socket函数创建套接字//!@param domain 协议族,AF_INET表示IPv4协议族//!@param type 套接字类型,SOCK_DGRAM表示UDP套接字//!@param protocol 协议,一般为0 让系统⾃动识别//!@return 成功返回套接字描述符,失败返回-1int fd = socket(AF_INET, SOCK_DGRAM, 0);if(fd == -1){    //创建套接字失败perror("socket err");exit(EXIT_FAILURE);}//准备服务器地址/*      struct sockaddr_in {short int sin_family; // 地址族 AF_INETunsigned short int sin_port; // 端口号struct in_addr sin_addr;// IP地址unsigned char sin_zero[8]; // 填充字节 为了对齐sockaddr};*/struct sockaddr_in addr;memset(&addr, 0, sizeof(addr));addr.sin_family=AF_INET;addr.sin_port=htons(8081);//htons函数将主机字节序转换为网络字节序//inet_aton()将点分十进制IP地址转换为网络字节序IP地址//*@param ip 字符串形式的IP地址//*@param in_addr 结构体变量,用于存储IP地址int ret=inet_aton("172.17.140.183", &addr.sin_addr); // 成功返回⾮0,失败返回0if(ret == 0){perror("inet_aton err");exit(EXIT_FAILURE);}//!绑定套接字到服务器地址//!@param sockfd 套接字描述符//!@param addr 服务器地址//!@param addrlen 服务器地址长度//!@return 成功返回0,失败返回-1int ret2 = bind(fd, (struct sockaddr*)&addr, sizeof(addr));if(ret2 == -1){perror("bind err");exit(EXIT_FAILURE);}//接收数据recv_data(fd);//关闭套接字close(fd);return 0;
}//接收数据
void recv_data(int sockfd) {struct sockaddr_in client_addr;//客户端的地址int client_addr_len = sizeof(client_addr);while(1) {char recv_buf[1024]={0};//接收数据//*@param sockfd 套接字描述符//*@param buf 接收缓冲区//*@param len 接收缓冲区长度//*@param flags 接收标志//*@param src_addr 发送方地址//*@param addrlen 发送方地址长度//*@return 成功返回接收到的字节数,失败返回-1int ret = recvfrom(sockfd, recv_buf, sizeof(recv_buf), 0, (struct sockaddr *) &client_addr, &client_addr_len);if (ret == -1) {perror("recvfrom err");exit(EXIT_FAILURE);}//打印接收到的信息char *ip_str = inet_ntoa(client_addr.sin_addr);//将网络字节序IP地址转换为点分十进制IP地址int port = ntohs(client_addr.sin_port); //将网络字节序端口号转换为主机字节序端口号printf("接收到来自%s:%d的数据:%s\n", ip_str, port, recv_buf);}
}
1) {perror("recvfrom err");exit(EXIT_FAILURE);}//打印接收到的信息char *ip_str = inet_ntoa(client_addr.sin_addr);//将网络字节序IP地址转换为点分十进制IP地址int port = ntohs(client_addr.sin_port); //将网络字节序端口号转换为主机字节序端口号printf("接收到来自%s:%d的数据:%s\n", ip_str, port, recv_buf);}
}

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 大数据之数据抽取架构演变过程
  • 数据结构 —— B树
  • 【BUG】已解决:WslRegisterDistribution failed with error: 0x800701bc
  • Qt Style Sheets-使用样式表自定义 Qt 部件
  • Freedom of Choice
  • R语言模型评估网格搜索
  • Linux网络——套接字与UdpServer
  • Haproxy服务
  • 第四周:机器学习笔记
  • 接口测试JMeter-1.接口测试初识
  • 电磁兼容专栏说明
  • 深入浅出WebRTC—ALR
  • git-各种场景-撤销指令
  • 文件IO(Ubuntu)
  • TypeScript与面向对象编程
  • ES6指北【2】—— 箭头函数
  • 【407天】跃迁之路——程序员高效学习方法论探索系列(实验阶段164-2018.03.19)...
  • 【跃迁之路】【669天】程序员高效学习方法论探索系列(实验阶段426-2018.12.13)...
  • ComponentOne 2017 V2版本正式发布
  • IP路由与转发
  • java8-模拟hadoop
  • Java面向对象及其三大特征
  • java中的hashCode
  • quasar-framework cnodejs社区
  • React中的“虫洞”——Context
  • swift基础之_对象 实例方法 对象方法。
  • ⭐ Unity 开发bug —— 打包后shader失效或者bug (我这里用Shader做两张图片的合并发现了问题)
  • Vue实战(四)登录/注册页的实现
  • 从 Android Sample ApiDemos 中学习 android.animation API 的用法
  • 给第三方使用接口的 URL 签名实现
  • 关于字符编码你应该知道的事情
  • 基于Mobx的多页面小程序的全局共享状态管理实践
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 强力优化Rancher k8s中国区的使用体验
  • 一文看透浏览器架构
  • 在Docker Swarm上部署Apache Storm:第1部分
  • 正则表达式小结
  • #HarmonyOS:基础语法
  • (1综述)从零开始的嵌入式图像图像处理(PI+QT+OpenCV)实战演练
  • (2024,Flag-DiT,文本引导的多模态生成,SR,统一的标记化,RoPE、RMSNorm 和流匹配)Lumina-T2X
  • (C++20) consteval立即函数
  • (八)Docker网络跨主机通讯vxlan和vlan
  • (超简单)使用vuepress搭建自己的博客并部署到github pages上
  • (二)JAVA使用POI操作excel
  • (黑马点评)二、短信登录功能实现
  • (转)Windows2003安全设置/维护
  • .htaccess配置常用技巧
  • .Mobi域名介绍
  • .NET HttpWebRequest、WebClient、HttpClient
  • .Net OpenCVSharp生成灰度图和二值图
  • .Net 执行Linux下多行shell命令方法
  • .Net6 Api Swagger配置
  • .net6使用Sejil可视化日志
  • .netcore 如何获取系统中所有session_ASP.NET Core如何解决分布式Session一致性问题