套接字实现Udp服务器

上一篇博客讲述了怎么使用套接字来实现一个Tcp服务器,来实现客户端-服务器之间的双向通信。今天我们来看看怎么使用套接字socket实现Udp服务器吧!

1、使用socket套接字实现Udp服务器

1.1、简单介绍实现方法

Udp服务器的实现与Tcp之间是很有差别的,下面我们来说要注意的几点:

①、首先、需要调用socket创建套接字 ,socket函数的参数与Tcp调用时有点不一样,Udp是数据包传输,所以传输的类型是要改为SOCK_DGRAM,也就是socket函数的第二个参数需要更改;

②、调用bind来绑定服务器,所以我们需要 知道的服务器的ip与端口号;

③、Udp服务器不需要进行三次握手来建立链接,所以不需要设置监听状态;

④、绑定之后可以直接进行读写;(Udp通信的读写方式不是使用read、write);

1.2、Udp通信之间的读写方式 

【recvfrom】数据接收——读数据

SYNOPSIS
       #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);
参数socket表示的是当前的socket

参数buf表示的是接受到数据指针;

参数flags默认缺省 0;

参数addr为输入输出型参数,输出的是发送方的协议地址。

参数addrlen为输入输出型参数,填写的是addr的大小。

【sendto】数据发送——写数据

       #include <sys/types.h>
       #include <sys/socket.h>

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

参数socket表示的是当前的socket

参数buf表示的是到数据指针;

参数flags默认缺省 0;

参数addr为输入输出型参数,填写的发送方的协议地址。

参数addrlen为输入输出型参数,填写的是addr的大小。

2、代码实现Udp服务器——客户端

服务器代码:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
//实现Udp服务器

static void usage(const char * proc )
{
	printf("%s [ip_addr] [port]\n",proc);
}
int main(int argc ,char * argv[])
{
	if(argc !=3)
	{
		usage(argv[0]);
		return 1;
	}
	//创建套接字 套接字参数 数据传输类型为数据报传输 SOCK_DGRM
	int sockfd  =socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0)
	{
		perror("socket");
		return 2;
	}
	//当然作为服务器本身就是一对多的,所以需要绑定ip与端口
	struct  sockaddr_in local;
	local.sin_family = AF_INET;
	local.sin_port = htons(atoi(argv[2]));
	local.sin_addr.s_addr = inet_addr(argv[1]);
	//绑定端口 与ip
	if(bind(sockfd,(struct sockaddr*)&local,sizeof(local)) < 0 )
	{
		perror("bind");
		return 3;
	}	
	//绑定成功之后不需要设置为监听状态,因为Udp是不可靠传输的,所以不需要建立链接也就不需要保存链接
	char  buf[1024];
	while(1)
	{
		//udp客户端-服务器之间的通信采用的是  专门的函数通信
		struct sockaddr_in client;
		socklen_t  len = sizeof(client);
		//recvfrom从客户端接收数据
		ssize_t  s = recvfrom(sockfd,buf,sizeof(buf)-1,0,(struct  sockaddr*)&client,&len);
		if(s<0 )
		{
			perror("read");
			return  4;
		}
		else if(s == 0)
		{}
		else
		{
			buf[s] = 0 ;
			printf("%s ,%d #:%s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
			//调用sendto发送数据到 客户端
			sendto(sockfd,buf,strlen(buf),0,(struct  sockaddr*)&client,len);
		}
	}
	close(sockfd);
	return  0;
}
客户端实现代码:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>


static void usage(const char * proc )
{
	printf("%s [ip_addr] [port]\n",proc);
}
int main(int argc ,char * argv[])
{
	if(argc !=3)
	{
		usage(argv[0]);
		return 1;
	}
	//创建Udp套接字 ,传输类型为SOCK_DGRAM
	int sockfd  =socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0)
	{
		perror("socket");
		return 2;
	}		
	//创建成功
	char  buf[1024];
	printf("Please Enter\n");
	while(1)
	{
		printf("client#: ");
		fflush(stdout);
		//从标准输入中读到数据
		ssize_t  s = read(0,buf,sizeof(buf)-1);
		if(s <0 )
		{
			perror("read");
			return 3;
		}
		buf[s-1] = 0;
		//给定接受方的协议地址
		struct sockaddr_in peer;
		peer.sin_family = AF_INET;
		peer.sin_port  = htons(atoi(argv[2]));
		peer.sin_addr.s_addr = inet_addr(argv[1]);
		//想服务器发送数据
		if(sendto(sockfd,buf,strlen(buf),0,(struct  sockaddr*)&peer,sizeof(peer)) < 0)
		{
			perror("sendto");
			return  4;
		}
		struct sockaddr_in server;
		socklen_t  len = sizeof(server);
		//接受服务器的数据
		s = recvfrom(sockfd,buf,sizeof(buf)-1,0,(struct sockaddr*)&server,&len);
		//接受失败
		if(s<0 )
		{
			perror("recvfrom");
			return  5;
		}
		//接受到文件结尾 表示 服务器关闭
		else if(s == 0)
		{
			printf("server  quit\n");
			break;
		}
		//将受到的数据放到显示器上
		else
		{
			buf[s] = 0 ;
			printf("%s ,%d #:%s\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port),buf);
		}
	}
	close(sockfd);
	return  0;
}

3、怎么在用户空间用Udp实现可靠性

UDP它不属于连接型协议,因而具有资源消耗小,处理速度快的优点,所以通常音频、视频和普通数据在传送时使用UDP较多,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
传输层无法保证数据的可靠传输,只能通过应用层来实现了。实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。
实现确认机制、重传机制、窗口确认机制。
如果你不利用Linux协议栈以及上层socket机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:
发送:包的分片、包确认、包的重发
接收:包的调序、包的序号确认
目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。
【RUDP】
RUDP 提供一组数据服务质量增强机制,如拥塞控制的改进、重发机制及淡化服务器算法等,从而在包丢失和网络拥塞的情况下, RTP 客户机(实时位置)面前呈现的就是一个高质量的 RTP 流。在不干扰协议的实时特性的同时,可靠 UDP 的拥塞控制机制允许 TCP 方式下的流控制行为。
【RTP】
实时传输协议(RTP)为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。应用程序通常在 UDP 上运行 RTP 以便使用其多路结点和校验服务;这两种协议都提供了传输层协议的功能。但是 RTP 可以与其它适合的底层网络或传输协议一起使用。如果底层网络提供组播方式,那么 RTP 可以使用该组播表传输数据到多个目的地。
RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于底层服务去实现这一过程。 RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。
【UDT】
基于UDP的数据传输协议(UDP-basedData Transfer Protocol,简称UDT)是一种互联网数据传输协议。UDT的主要目的是支持高速广域网上的海量数据传输,而互联网上的标准数据传输协议TCP在高带宽长距离网络上性能很差。顾名思义,UDT建于UDP之上,并引入新的拥塞控制和数据可靠性控制机制。UDT是面向连接的双向的应用层协议。它同时支持可靠的数据流传输和部分可靠的数据报传输。由于UDT完全在UDP上实现,它也可以应用在除了高速数据传输之外的其它应用领域,例如点到点技术(P2P),防火墙穿透,多媒体数据传输等等。
因项目中的需要,现在详细分析一下UDT是如何通过udp实现数据的可靠传输。通过阅读源码的方式。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值