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 小米 华为 单反 装机 图拉丁
 
   -> 网络协议 -> 【网络编程】3.UDP网络编程 -> 正文阅读

[网络协议]【网络编程】3.UDP网络编程

一、UDP概述

udp协议,即用户数据报协议,是面向无连接的协议,在传输数据之前不需要先建立连接,目的主机的运输层收到UDP报文后,不需要给出任何确认。

特点:

  • 传输速度快
  • 简单的请求/应答应用程序可以使用UDP
  • 对于海量数据传输不应使用UDP
  • 广播和多播应用必须使用UDP

应用:DNS域名解析、NFS网络文件系统、RTP流媒体等,一般音视频都是通过UDP来传输的

二、网络编程接口socket(套接字)

网络通信要解决的是不同主机进程间的通信,首要解决的是网络间进程标识问题,以及多重协议的识别问题。socket是实现tcp/udp的网络编程接口,用以提供不同主机上进程的通信。

1.socket的特点

  • 是一种文件描述符,代表了一个通信管道的一个端点
  • 类似对文件的操作一样,可以使用read、write、close等函数对socket套接字进行网络数据的收取和发送等操作
  • 得到socket套接字的方法是调用socket()

2.socket分类

  • SOCK_STREAM,流式套接字,用于TCP
  • SOCK_DGRAM,数据报套接字,用于UDP
  • SOCK_RAW,原始套接字,对于其他层次的协议操作是需要使用这个类型

3.UDP编程流程

?服务端:

  1. 创建套接字socket()
  2. 将socket与服务器的ip地址、端口号进行绑定
  3. 接收数据recvfrom()
  4. 发送数据sendto()

客户端

  1. 创建套接字
  2. 发送数据sendto()
  3. 接收数据recvfrom()
  4. 关闭客户端close()

?三、UDP编程

1.创建socket套接字

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
int socket(int domain, int type, int protocol);

功能:创建一个用于网络通信的socket套接字

参数:

? ? ? ? family:协议族(AF_UNIX本地通信,AF_INET ipv4按网络协议,AF_INET6 ipv6网络协议,PF_PCAKET底层接口等)

? ? ? ? type:套接字类(SOCK_STRAEAM 流式套接字,SOCK_DGRAM 数据报套接字,SOCK_RAW原始套接字)

? ? ? ? protocol:协议类别(0,,IPPROTO_TCP,IPPROTO_UDP)

返回值:成功返回套接字(文件描述符),失败返回-1

特点:

????????创建套接字时,系统不会分配端口

? ? ? ? 创建的套接字默认属性是主动的,即主动发起服务的请求,当作为服务器是,往往需要修改为被动

2.ipv4套接字地址结构体

网络编程中常用的结构体

#include <netinet/in.h>
struct in_addr{
    in_addr_t s_addr;//4字节
};
struct sockaddr_in{
    sa_family_t sin_family;//2字节
    in_port_t sin_port;//2字节
    struct in_addr sin_addr;//4字节
    char sin_zero[8]//8字节,填充,不起什么作用
};

为了使不同格式地址能被传入套接字函数,地址必须要强制转换成通用套接字,原因是不同场合使用的结构体不一样,但是调用的函数却是同一个,所以定义一个通用结构体,挡在指定场合使用时,再根据要求传入指定的结构体即可。

通用结构体

#include <netinet/in.h>
struct sockaddr{
    sa_family sa_family;//2字节
    char sa_data[14];//14字节
}

在定义源地址和目的地址结构的时候选用struct sockaddr_in,然后在调用编程接口函数的时候,使用参数传入地址结构是就需要使用struct sockaddr进行强制转换。

例如:

struct sockaddr_in myaddr;
bind(sockfd,(struct sockaddr*)&myaddr,sizeof(myaddr));

3.发送数据 sendto函数

ssize_t sendto(int sockfd,const void *buf,
                size_t nbytes,int flags,
                const struct sockaddr *to,
                socklen_t addrlen);

功能:向to结构体指针中指定的ip发送UDP数据

参数:sockfd:套接字

? ? ? ? ? ? ? ? buf:发送数据缓冲区

? ? ? ? ? ? ? ? nbytes:发送数据缓冲区的大小

? ? ? ? ? ? ? ? flags:一般为0

? ? ? ? ? ? ? ? to:指向目的主机地址结构体的指针

? ? ? ? ? ? ? ? addrlen:to所指向内容的长度

注意:通过to和addrlen确定目的地址,可以发送0长度的UDP数据报

返回值:成功:发送数据的字符数,失败:-1

实例:

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

//UDP socket netpro
int main(){
/**创建套接字**/
	int sockfd;
	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){
		perror("fail to socket()");
		exit(1);
	}
/**确定发送地址和端口 结构体**/
	struct sockaddr_in myaddr; 	
	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = inet_addr("192.168.137.1");
	myaddr.sin_port = htons(6666);
/**发送数据**/
	char buf[128];
	while(1){
		fgets(buf,128,stdin);
		buf[strlen(buf)-1] = '\0';
		if(sendto(sockfd,buf,128,0,(struct sockaddr*)&myaddr,sizeof(myaddr))==-1){
			perror("fail to sendto");
			exit(1);
		}
	}
	close(sockfd);
	return 0;
}

4.绑定 bind函数

UDP网络程序想要接收数据,需要确定ip地址以及port端口号

发送端(客户端)在sendto函数中指定接收端的ip和port就可以发送数据了,客户端不进行绑定ip地址以及端口号的话,端口号会系统自动分配。

在接收端(服务器)可以使用bind函数,来完成地址结构和socket套接字的绑定,这样ip和port就固定了,这解释绑定函数bind 的使用场合

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

int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

功能:将本地协议地址与sockfd绑定

?参数:sockfd:socket套接字

? ? ? ? ? ? ? ? addr:指向特定协议的地址结构指针

? ? ? ? ? ? ? ? addrlen:该地址结构的长度

返回值:成返回0失败返回其他

#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

//UDP socket netpro
/**使用参数传递ip地址和端口号,加上错误判断**/
int main(int argc,const char* argv[]){
	if(argc < 3){
		printf("arg:%s ip port\n",argv[0]);
		exit(1);
	}

/**创建套接字**/
	int sockfd;
	if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){
		perror("fail to socket()");
		exit(1);
	}
	
/**设置地址信息**/
	struct sockaddr_in myaddr;
	myaddr.sin_family = AF_INET;
	myaddr.sin_addr.s_addr = inet_addr(argv[1]);
	myaddr.sin_port = htons(atoi(argv[2]));
	
/*套接字绑定地址信息***/
	if(bind(sockfd,(struct sockaddr*)&myaddr,sizeof(myaddr))!=0)
	{
		perror("fail to bind\n");
		exit(1);
	}
	close(sockfd);
	return 0;
}

5.接收数据 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);

功能:接收数据,并将源地址信息保存在src_addr指向的结构中

参数:sockfd:套接字

? ? ? ? ? ? ? ? buf:接收数据缓冲区

? ? ? ? ? ? ? ? len:接收数据缓冲区大小

? ? ? ? ? ? ? ? flags:套接字标志(通常为0)

? ? ? ? ? ? ? ? src_addr:源地址结构体指针,用来保存数据来源 可以为空

? ? ? ? ? ? ? ? addrlen:src_addr所指内容的长度 可以为空,注意这里的长度是一个指针,所以不能直接使用sizeof来计算长度,需要先定义一个aocklen_t的变量,对他进行sizeof赋值,然后传入这个参数的地址即可。

返回值:成功返回接收到的字节数,失败返回-1

四、UDP广播

每个网段中主机id为255的ip为广播地址,有一台主机向该主机所在子网内的所有主机发送数据的方式称之为广播

广播只能由UDP或原始IP实现,不能用TCP

特点:

? ? ? ? 处于同一子网内的所有主机都必须处理数据‘

? ? ? ? UDP数据包会沿协议栈向上一直到UDP层

? ? ? ? 局限于局域网使用

? ? ? ? 运行音视频等较高速率公错的应用,会带来较大的负荷

单播:

广播:

?

?广播消息只有在传输层才有可能被丢弃,在数据链路层识别到消息的mac地址是FF.FF.FF.FF会直接通过,网络层也同理,识别ip地址后直接通过

广播流程:

发送者:

? ? ? ? 创建套接字socket()

? ? ? ? 设置为允许发送广播权限setsockopt()

? ? ? ? ?向广播地址发送数据sendto()

接收者:

? ? ? ? 创建套接字socket()

? ? ? ? 将套接字与广播的信息结构体进行绑定bind()

? ? ? ? 接收数据recvfrom()

int setsockopt(int sockfd,int level,int option_name,const void *option_value,
                            socklen_t option_len);

功能:设置一个套接字的属性

参数:

? ? ? ? sockfd:文件描述符

? ? ? ? level:协议层次

? ? ? ? ? ? ? ? ? ? ? ? SOL_SOCKET?????????套接字层次

? ? ? ? ? ? ? ? ? ? ? ? IPPROTO_TCP? ? ? ? TCP层次

? ? ? ? ? ? ? ? ? ? ? ? IPPROTO_IP? ? ? ? ?IP层次

????????option_name:选项的名称、

? ? ? ? ? ? ? ? SO_BROADCAST? ? ? ? 允许发送广播数据????????SOL_SOCKET层次的

? ? ? ? option_value:设置的选项的值

? ? ? ? ????????????????????????int类型的值,存储的是bool的数据(1/0)?

? ? ? ? ? ? ????????????????? ? 0:不允许

? ? ? ? ? ? ? ? ????????????????1:允许? ? ?

? ? ? ? option_len:option_value的长度

返回值:成功0失败-1

五、UDP多播

多播是一种数据的收发旨在同一分组中进行的发送方式,多播也称之为组播

特点如下:多播的值标识一组接口

? ? ? ? ? ? ? ? 多播可以用于广域网使用

? ? ? ? ? ? ? ? 在ipv4中,多播是可选的

ipv4的D类地址是多播地址,从244.0.0.1到239.255.255.254

比起广播,多播具有可控性,只有加入了多播组的接收者才可以接收到数据,否则接收不到

工作过程:

多播流程:

发送者:

? ? ? ? 创建套接字socket()

? ? ? ? 向多播地址发送数据snedto()

接收者:

? ? ? ? 创建套接字socket()

? ? ? ? 设置为加入多播组setsockopt()

? ? ? ? 将套接字与多播信息结构体绑定bind()

? ? ? ? 接收数据recvfrom()

多播地址结构体 在iPv4网络中,多播地址结构体用ip_mreq表示

int setsockopt(int sockfd,int level,int option_name,const void *option_value,
                            socklen_t option_len);

功能:设置一个套接字的属性

参数:

? ? ? ? sockfd:文件描述符

? ? ? ? level:协议层次

? ? ? ? ? ? ? ? ? ? ? ? IPPROTO_IP? ? ? ? ?IP层次

????????option_name:选项的名称

? ? ? ? ? ? ? ? IP_ADD_MEMBERSHIP? ? ? ?加入多播组

? ? ? ? option_value:设置的选项的值

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 传入上述多播结构体的地址,该结构体的第二个成员可以用一个宏INADDR_ANY来自动获取你的主机地址

? ? ? ? option_len:option_value的长度

返回值:成功0失败-1

接入多播组实例:

?

  网络协议 最新文章
使用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:41 
 
开发: 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:36:41-

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