网络编程传输层——UDP通信

何为传输层?

        在物理层、数据链路层、网络层解决了主机和主机之间能够发送接收数据,但是在计算机网络中,主机的通信主体还是进程,而传输层则解决应用进程的通信,所谓传输层协议也是端对端协议

传输层的协议主要有两种:TCP协议UDP协议

本章这次主要是针对的UDP协议,下一章才是针对TCP协议的具体理解。

        在传输层需要了解到一个新的概念:端口号port(可以理解为你要从那个地方传进去),设计了一个端口号来标识主机中的进行网络通信的进程。

        port:16bit整形(两个字节)       

        端口号只在本机上有作用,在不同主句中同一个程序执行,也可以用不同的端口号。

什么是UDP协议?

        UDP协议(用户数据报协议)(非面向连接)

        1. 无连接,不需要提前把两个程序关联起来(想发给谁就发给谁)。

        2. 面向报文的传输,应用程序要发送的数据,直接封装在udp数据报中(直接放在udp协议内容 后),既不做拆分也不做合并,直接交给网络层。

        3. 不可靠,不保证数据一定能到达,尽最大努力交付。

         UDP协议就是在MAC帧的外面在加上一层传输协议,既加上UDP头部,它的头部由以下四部分组成。

网络编程传输层——UDP通信_第1张图片

源端口:自己主机的端口号

目标端口:要传到那个主机的端口号

下面这张图是一个传输模型

网络编程传输层——UDP通信_第2张图片

 

        可以看出这是TCP/IP网络模型,因为只有四层,从用户层、传输层、网络层、网络接口层构成。

        在操作系统当中,其实网络协议是有写好了的函数库可以使用,只需要选择对应的协议就行。

如何进行UDP协议进行通信?

1、首先我们需要了解udp怎样进行通信的,下图是udp通信流程

网络编程传输层——UDP通信_第3张图片

 清楚了流程,但肯定不懂得后面函数得意义吧,下面来进行函数的细讲:

1、创建套接字(这里就是相当于创建一个包含网络通信协议的套接字文件

#include 
#include 

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

参数1:选择那种ip地址进行通信-----网络层    AF_INET  IPV4
参数2:选择那种传输-----传输层    SOCK_STREAM  TCP    SOCK_DGRAM  UDP  SOCK_RAM 不使用
参数3:套接字协议    0  默认

返回值    成功:返回套接字    失败:返回-1

2、绑定套接字(也就是将自己的本地网络信息绑定到网络协议中)

#include  /* See NOTES */ 
#include 

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

参数1;利用函数int socket函数创建的套接字
参数2:自己的IPV4网络信息
    struct sockaddr_in 
      { 
            sa_family_t sin_family; 地址族:AF_INET/*address family: AF_INET */         
            in_port_t sin_port;port端口号:当前进程的端口号 
            struct in_addr sin_addr;ip地址:本地网络地址 /* internet address */ 
      };

            struct in_addr 
              { 
                uint32_t s_addr;32位整数,ip地址 /* address in network byte order */ 
              };
参数3:结构体大小,直接sizeof(struct addr)

3、这个函数就是发送数据与接收数据(发给谁,接收谁)

UDP发送数据

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

参数1:要通过套接字发送给谁
参数2:要发送数据的首地址
参数3:发送数据的大小
参数4:标志    0:阻塞等待,发送完成才结束
参数5:const struct sockaddr *dest_addr:结构体地址,要包含目标,接收方的地址、端口
参数6::结构体大小,目标网络信息结构体的大小

返回值    成功:返回发送的字节数    失败:返回-1

UDP接收数据

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

参数1:int sockfd:套接字,本地套接字携带了本地的网络信息,进行匹配 
参数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

        在计算机存储数据中,有大小端之分(大端(高存低地址,低存高地址)小端(高存高地址,低存低地址)),但是在网络上传输时,统一成了大端模式。

        在网络上传输的方式是网络字节序 ,而在机器上存储的方式是主机字节序。

        则我们需要在传输时将主机字节序转网络字节序 ,网络字节序转主机字节序。

实例:

        发送端程序:

        

#include 
#include 
#include 
#include 
#include 
#include 

//当前进程发送数据到指定主机的指定进程中,然后接收对方的数据
int main()
{

	//1、创建套接字------在进程中要使用网络通信协议,得到套接字文件描述符
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);    //IPV4,UDP协议

	//2、绑定套接字,绑定套接字 中 协议中本地的网络信息
	//把套接字,绑定本地网络信息
	struct sockaddr_in srcaddr;//本地网络信息---源信息
	srcaddr.sin_family = AF_INET;//ipv4 地址
	srcaddr.sin_port = htons(9999);//当前进程的端口号
	srcaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");//把主机地址转为32位整数

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

	//3、发送数据

	//目标结构体
	struct sockaddr_in destaddr;//目标信息
	destaddr.sin_family = AF_INET;
	destaddr.sin_port = htons(8888);
	destaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");

	while(1)
	{
		char buf[20],buf2[20];
		scanf("%s",buf);//输入了数据
		sendto(sockfd,buf,20,0,(struct sockaddr *)&destaddr,sizeof(destaddr));发送
		
		recvfrom(sockfd,buf2,20,0,NULL,NULL);接收
		printf("%s\n",buf2);
	}

	close(sockfd);
}

        接收数据程序、

#include 
#include 
#include 
#include 
#include 
#include 

//当前进程接收数据,然后发送给对方
int main()
{

	//1、创建套接字------在进程中要使用网络通信协议,得到套接字文件描述符
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);

	//2、绑定套接字,绑定套接字 中 协议中本地的网络信息
	//把套接字,绑定本地网络信息
	struct sockaddr_in srcaddr;//本地网络信息---源信息
	srcaddr.sin_family = AF_INET;//ipv4 地址
	srcaddr.sin_port = htons(8888);//当前进程的端口号
	srcaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");//把主机地址转为32位整数

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

	//3、接收数据

	//目标结构体
	struct sockaddr_in destaddr;//目标信息
	destaddr.sin_family = AF_INET;
	destaddr.sin_port = htons(9999);
	destaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");

	char buf2[20];
	while(1)
	{
		recvfrom(sockfd,buf2,20,0,NULL,NULL);    //接收
		printf("%s\n",buf2);
		
		sendto(sockfd,buf2,20,0,(struct sockaddr *)&destaddr,sizeof(destaddr));    //发送获取
		
	}

	close(sockfd);
}

        UDP协议采用的非面向连接(没有连接),所以还是有很多问题的,无连接、不可靠、面向数据报的传输 。而且发送了也不知道发送到了没,缺点之一。

你可能感兴趣的:(Linux,udp,网络)