[网络篇] socket编程——UDP

一、初识UDP

1.UDP 协议

  1. UDP 是无连接的,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延
  2. UDP 使用尽最大努力交付,即不保证可靠交付,主机不需要维持复杂的连接状态表(如发短信,你无法确定对方是否收到)
  3. UDP 是面向报文的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界
  4. UDP 没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的
  5. UDP 支持一对一、一对多、多对一和多对多的交互通信
  6. UDP 的首部开销小,只有8个字节,比 TCP 的20个字节的首部要短

2.UDP头

源端口:在需要对方回信时1,不需要时可用全0

目标端口:这在终点交付报文时必须使用

长度:UDP 用户数据报的长度,其最小值是8(仅有首部)

校验和: 检测 UDP 用户数据报在传输中是否有错。有错就丢弃

3.UDP通信过程

 二、UDP通信——scoket编程

UDP网络通信(类似发送/接收短信):

类比

作用

功能

函数

有手机

有网络通信协议UDP

创建套接字文件

socket()

有手机卡(号码)

通信协议中需要有自己的网络信息

绑定(指定)本地当前进程的网络信息

bind()

填写对方手机号,发送短信

使用协议发送数据

协议中添加对方信息发送数据(ip端口)

sendto()

接收短信

使用协议接收数据

根据解析的信息接收数据

recvfrom()

关闭

不再进行通信

关闭通信

close()

1. 创建套接字

#include <sys/types.h>

#include <sys/socket.h>

//创建套接字文件,为进程添加一个对应的网络通信协议(文件),返回值就是创建号的文件描述符(socket描述符就代表一套协议---套接字)

int socket(int domain, int type, int protocol);

参数1:

int domain:地址族,选用那种网络层协议地址
AF_INET------IPV4
AF_INET6------IPV6

参数2:

int type:套接字类型

SOCK_STREAM--------TCP

SOCK_DGRAM---------UDP

SOCK_RAW:原始套接字(没有传输层协议)

参数3:

int protocol:套接字协议

           0:套接字默认协议

返回值:

int:整数---------文件描述符(套接字文件)
成功:返回套接字描述符 >= 0
失败:返回-1

2.绑定套接字

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

#include <sys/socket.h>

//绑定本地网络信息到套接字中

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

参数1:

int sockfd:绑定本地网络信息到哪个套接字上(绑定到哪一套协议上)

参数2:

const struct sockaddr *addr:结构体地址,这个结构体中存储的本地网络信息(要绑定的网络信息ip、port)

struct sockaddr {//通用结构体,表示一个网络信息内容

    sa_family_t sa_family;

    char sa_data[14];

}

//IPV4 网络信息结构体

struct sockaddr_in {

    sa_family_t sin_family;//地址族 AF_INET

    in_port_t sin_port;//端口

    struct in_addr sin_addr;//结构体变量--ip地址

};



/* Internet address. */

struct in_addr {

  uint32_t s_addr;//ipv4地址

};

参数3:

socklen_t addrlen:整数,结构体大小(确定信息结构体的大小)

返回值:

成功:返回0

失败:返回-1

3.发送数据

#include <sys/types.h>

#include <sys/socket.h>

//使用UDP协议发送数据

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

参数1:

int sockfd:套接字对象,使用哪个套接字发送数据

参数2:

const void *buf:要发送的数据的内存首地址

参数3:

size_t len:发送的数据的大小

参数4:

int flags:标志

0:阻塞发送

参数5:

const struct sockaddr *dest_addr:发送的目标网络信息

参数6:

socklen_t addrlen:结构体大小

返回值:

成功:返回发送的字节数

失败:返回-1

4.接收数据

#include <sys/types.h>

 #include <sys/socket.h>

//使用UDP协议接收数据

ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);

参数1:

int sockfd:套接字,指定使用哪个套接字来接收(ip,port来进行检测)

参数2:

void *buf:接收的数据的存放的地址

参数3:

size_t len:指定能够接收存储的最大大小

参数4:

int flags:标志

0:阻塞接收

参数5:

struct sockaddr *src_addr:在接收数据时,存储发送方的ip和port,如果不需要写NULL

参数6:

socklen_t *addrlen:存储信息结构体的大小,不需要写NULL

返回值:

成功:返回收到的大小
失败:返回-1

5.关闭套接字

int close(int fd)

三、实现代码:

//通过UDP协议,发送数据,接收数据
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{

	//1、创建套接字,选择对应的网络通信协议组
	int socketfd = socket(AF_INET,SOCK_DGRAM,0);//当前进程使用UDP IP 协议
	/*	if(socketfd < 0)
		{
		return -1;
		}
		*/

	//2、绑定套接字,对套接字添加自己当前进行需要到本地网络信息

	struct sockaddr_in addr;//有一个IPV4网络信息结构体
	addr.sin_family  = AF_INET;//地址族-----IPV4
	addr.sin_port = htons(10000);//为当前进程添加的端口号为10000-------主机10000端字节序转换为网络字节序
	addr.sin_addr.s_addr = inet_addr("192.168.124.63");

	bind(socketfd,(struct sockaddr *)&addr,sizeof(addr));

	char buf[20];
	memset(buf,0,20);//清空buf
	struct sockaddr_in dest_addr;//接收方网络信息结构体
	dest_addr.sin_family  = AF_INET;//地址族-----IPV4
	dest_addr.sin_port = htons(2000);
	dest_addr.sin_addr.s_addr = inet_addr("192.168.124.27");

	while(1)
	{	
		fgets(buf,20,stdin);
		sendto(socketfd,buf,20,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));//发送

		memset(buf,0,20);//清空buf
		int num=recvfrom(socketfd,buf,20,0,NULL,NULL);
		printf("recv size is %d\n",num);
		printf("data is %s\n",buf);

	}
	return 0;
}

通信结果如下图所示:

猜你喜欢

转载自blog.csdn.net/qq_53676406/article/details/129368533