linux下网络通信(udp通信协议详解)

一、udp通信简介

udp是User Datagram Protocol的简称, 中文名是用户数据报协议。udp协议位于osi模型中的传输层,它是一种面向无连接的协议。udp协议并不保证数据一定能够到达对端,也不能保证数据能够按照顺序到达对端,udp数据的可靠性需要引用层来保证。

udp提供的虽然是不可靠的数据传输,但是udp在数据传输过程中延迟小、数据传输效率高,适合对可靠性要求不高的应用程序。

二、udp通信建立步骤

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FYg2OXQL-1604480407906)(A10329AC3225414C80EBF1B9DD5CE01D)]

2.1、服务器端

1)socket建立套接字,需要指定ip类型和协议类型
socket(AF_INET,SOCK_DGRAM,0);
2)bind绑定服务器ip和端口
bind(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
3)recvfrom接收来自客户端的数据
4)sento发送数据到客户端

2.2、客户端

1)socket建立套接字,需要指定ip类型和协议类型
2)recvfrom接收来自客户端的数据
3)sento发送数据到客户端

三、udp和tcp的区别

协议UDPTCP
是否面向连接
传输可靠性不可靠可靠
传输速度
应用场合数据量少,对可靠性要求不高数据量大,对可靠性要求较高

3.1、面向连接和面向无连接

当我们需要拨打电话给某个人的时候,需要知道对方的电话号码,并且只有在对方接通电话之后才能进行正常通话,tcp面向连接就类似于拨打电话,客户端需要知道服务器的ip地址和端口并且建立连接之后才能进行正常通讯。

udp通信方式类似于对讲机,只要对方的对讲机打开,我们就可以进行语音通信,并不需要对方进行接听动作,这就是无连接。通常一个人对着对讲机说话,使用同一频段的对讲机都可以听到这个人的声音,这点也和udp广播和组播类似。

在tcp中,服务器必须开启之后,客户端才能连接上服务器,并在建立连接之后进行数据通信;而对于udp,不管服务器是否开启,udp客户端都可以正常创建并发送数据,只不过可能没有服务器接收你的数据而已。

3.2、可靠性

tcp协议提供非常可靠的数据传输方式,tcp在进行数据通信前会进行三次握手,保证通信双方能够接收对方的消息并且正确解析;在传输过程中tcp提供了重传功能,能够保证消息完整有序的到达接收端;在连接断开的时候,tcp能够通过四次握手保证最后一帧数据的完整性;

udp通信既没有三次握手和四次挥手,也没有重传机制,它只保证数据正确的发送出去,并不关心对端能不能收到,也不关心对端的数据是否接收完整或者是否按照顺序到达。

3.3、tcp和udp的优缺点和应用

tcp由于其高可靠性,多应用于数据量大并且对可靠性要求高的场合,比如http协议;udp虽然不可靠,但是传输速度很快,效率很高,而且客户端和服务器端并不相互依赖,比较适用于对及时性要求高的场合,比如早期的qq就是使用的udp协议。

四、udp协议的格式及wireshark数据包

在这里插入图片描述

我们通过客户端发送Test udp message!字符串到8099端口,使用wireshark抓取数据包如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DuuJq06r-1604480407909)(9523397E33684838B8A1837AD9F9F23E)]

可以看出udp协议的格式非常简单,它只有8个字节的首部,后面的全是数据。

五、linux下udp实例

目标:在linux下建立一个客户端和一个服务器,通过客户端发送字符串“Test udp message!”,服务器收到之后回复“Got it!”。

服务器端代码:

#include <unistd.h>
#include <pthread.h>
#include  <netdb.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>

#define UDP_PORT 8099
int main()
{
	int ret;
	int read_len = 0;
	int thread_fd;
	int sockfd;
	int server_fd;
	struct sockaddr_in server_addr;
	struct sockaddr client_addr;
	socklen_t len;
	char buffer[1024];
	
	server_addr.sin_family = AF_INET; //使用IPV4
	server_addr.sin_port = htons(UDP_PORT);//服务器端口号
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);//主机可能有多个网卡,INADDR_ANY表示绑定所有网卡
	
	sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建TCP,指定ip类型为IPV4
	if(sockfd < 0)
	{
		printf("socket create fail!\r\n");
		return -1;
	}
	ret = bind(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));//将socket和服务器地址绑定
	if(ret < 0)
	{
		printf("socket bind fail!\r\n");
	}
	while(1)
	{
		memset(buffer,0,sizeof(buffer));
		read_len = recvfrom(sockfd,buffer,sizeof(buffer),0,&client_addr,&len);
		printf("recv(%d):%s\r\n",read_len,buffer);//最后面如果不带\r\n可能会导致在shell中不显示数据
		if(read_len > 0)
		{
			sendto(sockfd,"Got it!",strlen("Got it!"),0,&client_addr,sizeof(client_addr));
		}
	}
	close(sockfd);
	return 0;
}

客户端代码:

#include <unistd.h>
#include <pthread.h>
#include  <netdb.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/select.h>

#define DEST_ADDR "192.168.3.15"
#define UDP_PORT 8099
int main()
{
	int ret;
	int read_len = 0;
	int sockfd;
	int server_fd;
	struct sockaddr_in dest_addr;
	struct sockaddr src_addr;
	socklen_t len;
	
	dest_addr.sin_family = AF_INET; //使用IPV4
	dest_addr.sin_port = htons(UDP_PORT);//服务器端口号
	dest_addr.sin_addr.s_addr = htonl(INADDR_ANY);//主机可能有多个网卡,INADDR_ANY表示绑定所有网卡,适用于本地通信
	//dest_addr.sin_addr.s_addr = inet_addr(DEST_ADDR);//适用于局域网通信
	
	sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建TCP,指定ip类型为IPV4
	if(sockfd < 0)
	{
		printf("socket create fail!\r\n");
		return -1;
	}
	while(1)
	{
		char buffer[1024] = "Test udp message!";
		ret = sendto(sockfd,buffer,strlen(buffer),0,&dest_addr,sizeof(dest_addr));
		if(ret < 0)
		{
			printf("sendto error\r\n");
			continue;
		}
		memset(buffer,0,sizeof(buffer));
		read_len = recvfrom(sockfd,buffer,sizeof(buffer),0,&src_addr,&len);
		printf("recv:%s\r\n",buffer);
		sleep(1);
	}
	close(sockfd);
	return 0;
}
  • 5
    点赞
  • 55
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值