IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 网络编程:UDP的socket编程(Linux) -> 正文阅读

[网络协议]网络编程:UDP的socket编程(Linux)


前言

本篇文章介绍UDP的socket编程流程,使用的接口都是Linux操作系统中的接口。这些编程接口可能与Windows操作系统中有些不同。文章中如果发现有错误的地方,可以一起讨论!!!

一、UDP协议

1.简单了解UDP协议

无连接:UDP客户端给服务端发送数据的时候,不需要和服务端先建立连接,而是直接进行发送数据
不可靠:不保证数据是可靠有序到达对端的
面向数据报:UDP数据不管是应用层还是网络层传递,都是整条数据进行交付。

2.网络字节序

数据在内存中进行存储时,有两种存储顺序:大端字节序和小端字节序。
大端字节序:数据的低位存储在高地址
小端字节序:数据的地位存储在低地址
在网络中进行收发数据时,也是需要遵守一定的规则,按照一定的字节序进行数据的组织。
网络字节序:采用的是大端字节序
主机字节序:根据机器本身采用的字节序(小端机器为小端字节序,大端机器为大端字节序)
如果机器的主机字节序为小端字节序,在网络中发送数据时就需要将主机字节序转换为网络字节序,否则发送的数据与接收到的数据就会有差异。
有两个接口可以进行主机字节序与网络字节序之间的转换:
1.主机字节序转换成网络字节序
在这里插入图片描述
2.网络字节序转换成主机字节序
在这里插入图片描述

二、UDPsocket编程

1.编程流程

首先需要服务端与客户端创建套接字,然后进行绑定地址信息,之后就可以进行正常通信了。通信结束需要关闭套接字。
在这里插入图片描述

2.编程接口

①创建套接字(socket)

使用socket函数创建套接字,具体参数含义和返回值内容见下图:
在这里插入图片描述

②绑定地址信息(bind)

使用bind函数对地址信息进行绑定
在这里插入图片描述
struct sockaddr结构体内部信息:
在这里插入图片描述

③发送数据(sendto)

调用sendto函数进行发送数据
在这里插入图片描述

④接收数据(recvfrom)

调用recvfrom函数接收数据
在这里插入图片描述

3.服务端测试

根据编程流程,使用socket函数创建套接字并绑定地址信息

  1 #include<stdio.h>                                                                                                              
  2 #include<iostream>
  3 #include<unistd.h>
  4 //socket编程的头文件
  5 #include<sys/socket.h>
  6 #include<netinet/in.h>
  7 #include<arpa/inet.h>
  8 using namespace std;
  9 
 10 int main()
 11 {
 12     int sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建UDP套接字
 13     if(sock_fd < 0)
 14     {
 15         perror("socket");
 16         return 0;
 17     }
 18     cout << "套接字描述符:" << sock_fd  << endl;//打印套接字描述符
 19 
 20     struct sockaddr_in addr;//定义地址信息的结构体
 21     addr.sin_family = AF_INET;//使用ipv4
 22     addr.sin_port = htons(27089);//指定端口27089,需要将端口转换成大端字节序
 23     addr.sin_addr.s_addr = inet_addr("172.16.0.9");//IP地址
 24 
 25     int ret = bind(sock_fd,(struct sockaddr*)&addr, sizeof(addr));//绑定地址信息
 26     if(ret < 0)
 27     {
 28         perror("bind");
 29         return 0;
 30     }
 31     while(1)
 32     {
 33         sleep(1);
 34     }
 35     return 0;
 36 }          

程序运行结果
在这里插入图片描述
使用命令对服务端状态进行测试,下图状态标识服务端监听成功,可以进行收发数据了:
在这里插入图片描述

3.客户端代码

  1 #include<stdio.h>                                                                                                              
  2 #include<iostream>
  3 #include<unistd.h>
  4 #include<string.h>
  5 //socket编程的头文件
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 using namespace std;
 10 
 11 int main()
 12 {
 13     int sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建UDP套接字
 14     if(sock_fd < 0)
 15     {
 16         perror("socket");
 17         return 0;
 18     }
 19     cout << "套接字描述符:" << sock_fd  << endl;//打印套接字描述符
 20 
 21     struct sockaddr_in addr;//定义地址信息的结构体
 22     addr.sin_family = AF_INET;//使用ipv4
 23     addr.sin_port = htons(27089);//指定端口27089,需要将端口转换成大端字节序
 24     addr.sin_addr.s_addr = inet_addr("172.16.0.9");//IP地址
 25    
 26     while(1)
 27     {
 28         char buf[1024] = "i am client";
 29                                                                                                                                
 30         struct sockaddr_in dest_addr;//client的地址信息结构
 31         dest_addr.sin_family = AF_INET;
 32         dest_addr.sin_port = htons(27089);
 33         dest_addr.sin_addr.s_addr = inet_addr("1.14.151.67");
 34 
 35         sendto(sock_fd, buf, strlen(buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
 36 
 37         memset(buf, '\0', sizeof(buf));//清空缓冲区
 38 
 39         struct sockaddr_in peer_addr;
 40         socklen_t len = sizeof(peer_addr);
 41         ssize_t recv_size = recvfrom(sock_fd, buf, sizeof(buf) - 1, 0, (struct sockaddr*)&peer_addr, &len);
 42         if(recv_size < 0)
 43         {
 44             continue;
 45         }
 46 
 47         printf("收到消息: \"%s\" 来自:%s:%d\n", buf, inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
 48         sleep(1);
 49     }
 50		close(sock_fd);//关闭套接字
 51     return 0;
 52 }      

4.服务端代码

  1 #include<stdio.h>                                                                                                              
  2 #include<iostream>
  3 #include<unistd.h>
  4 #include<string.h>
  5 //socket编程的头文件
  6 #include<sys/socket.h>
  7 #include<netinet/in.h>
  8 #include<arpa/inet.h>
  9 using namespace std;
 10 
 11 int main()
 12 {
 13     int sock_fd = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);//创建UDP套接字
 14     if(sock_fd < 0)
 15     {
 16         perror("socket");
 17         return 0;
 18     }
 19     cout << "套接字描述符:" << sock_fd  << endl;//打印套接字描述符
 20 
 21     struct sockaddr_in addr;//定义地址信息的结构体
 22     addr.sin_family = AF_INET;//使用ipv4
 23     addr.sin_port = htons(27089);//指定端口27089,需要将端口转换成大端字节序
 24     addr.sin_addr.s_addr = inet_addr("172.16.0.9");//IP地址
 25
 26     int ret = bind(sock_fd,(struct sockaddr*)&addr, sizeof(addr));//绑定地址信息
 27     if(ret < 0)
 28     {
 29         perror("bind");
 30         return 0;
 31     }
 32     
 33     while(1)//循环接收数据
 34     {
 35         char buf[1024] = {0};//缓冲区
 36         struct sockaddr_in peer_addr;//定义地址信息结构
 37         socklen_t len = sizeof(peer_addr);
 38         ssize_t recv_size = recvfrom(sock_fd, buf, sizeof(buf) - 1, 0, (struct sockaddr*)&peer_addr, &len);
 39         if(recv_size < 0)
 40         {
 41             continue;//继续接收
 42         }
 43         printf("收到消息: \"%s\" ,来自 %s:%d\n" , buf, inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));
 44         memset(buf, '\0', sizeof(buf));//清空缓冲区buf                                                                         
 45         sprintf(buf, "welcome client %s:%d", inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));//将字符串写入到buf当中
 46         sendto(sock_fd, buf, strlen(buf), 0, (struct sockaddr*)&peer_addr, sizeof(peer_addr));
 47     }
 48                                                                                                                               
 49     close(sock_fd);
 50     return 0;      
 51 }   

5.连接测试

测试结果如下,服务端和客户端能够正常进行通信
在这里插入图片描述

6.缓冲区的概念

UDP在进行发送数据时,是先将数据放入UDP的发送缓冲区当中,然后经过网络协议栈对数据进行层层封装,然后到达服务端的接收缓冲区,服务端再从接收缓冲区中读数据。
同理服务端向客户端发送数据时也是需要经过缓冲区这样一个过程,如下图:
在这里插入图片描述

  网络协议 最新文章
使用Easyswoole 搭建简单的Websoket服务
常见的数据通信方式有哪些?
Openssl 1024bit RSA算法---公私钥获取和处
HTTPS协议的密钥交换流程
《小白WEB安全入门》03. 漏洞篇
HttpRunner4.x 安装与使用
2021-07-04
手写RPC学习笔记
K8S高可用版本部署
mySQL计算IP地址范围
上一篇文章      下一篇文章      查看所有文章
加:2021-08-27 12:13:42  更:2021-08-27 12:14:09 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:14:55-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码