【网络】UDP服务器的实现

UDP服务器实现的基本步骤

(1)利用socket函数创建套接字

(2)服务器用bind进行IP和端口号的绑定

(3)不需要设置监听状态

(4)绑定后直接读写

相关函数

recvfrom

作用

用来数据的接收

头文件

#include

#include

函数原型

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

参数

sockfd表示当前的套接字

buf表示要接收的数据指针

len表示接收的长度

flags参数设置为0

src_addr表示发送方的协议地址

addrlen表示src_addr的大小

返回值

成功返回0

错误返回-1

sendto

作用

用来进行数据的发送

头文件

#include

#include

函数原型

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

参数

sockfd表示当前的套接字

buf表示要发送的数据指针

len表示要发送的数据长度

flags设置为0

src_addr为发送方的协议地址

addrlen为src_addr的大小

返回值

成功返回0

错误返回-1

代码实现

server.c

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

static void Usage()
{
	printf("Usage: [ipaddr] [port]\n");
	exit(1);
}

int main(int argc, char* argv[])
{
	if(argc != 3)
	{
		Usage();
	}

	//创建socket
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);

	if(sockfd < 0)
	{
		perror("socket");
		exit(4);
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port = htons(atoi(argv[2]));
	addr.sin_addr.s_addr = inet_addr(argv[1]);

	//进行绑定
	if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) < 0)
	{
		perror("bind");
		exit(2);
	}

	char buf[1024];

	//收发数据
	while(1)
	{
		struct sockaddr_in client;
		socklen_t clientLen = sizeof(client);
		ssize_t s = recvfrom(sockfd, buf ,sizeof(buf)-1,0,(struct sockaddr*)&client,&clientLen);

		if(s < 0)
		{
			perror("recvfrom");
			exit(3);
		}
		else if(s == 0)
		{
			continue;
		}
		else 
		{
			buf[s] = 0;
			printf("IP: %s , Port : %d  : %s\n",inet_ntoa(client.sin_addr),ntohs(client.sin_port),buf);
			sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,clientLen);
		}

	}
	close(sockfd);
	return 0;
}

client.c

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

static Usage()
{
	printf("Usage: [ipaddr] [port]\n");
	exit(1);
}

int main(int argc,char* argv[])
{
	if(argc != 3)
	{
		Usage();
	}

	//创建socket
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd < 0)
	{
		perror("sockfd");
		exit(2);
	}

	printf("请输入...\n");
	char buf[1024];
	//进行写和读
	while(1)
	{
		printf("#client : ");
		fflush(stdout);
		ssize_t s = read(0,buf,sizeof(buf)-1);
		if(s < 0)
		{
			perror("read");
			exit(3);
		}
		buf[s-1] = '\0';

		//进行发送
		struct sockaddr_in client;
		client.sin_family = AF_INET;
		client.sin_port = htons(atoi(argv[2]));
		client.sin_addr.s_addr = inet_addr(argv[1]);
	
		s = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&client,sizeof(client));

		if(s < 0)
		{
			perror("sendto");
			exit(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");
			exit(5);
		}
		
		//正常收到
		buf[s] = 0;
		printf("IP : %s , Port : %d  : %s\n",inet_ntoa(server.sin_addr),ntohs(server.sin_port),buf);

	}
	
	close(sockfd);
	return 0;
}

运行结果

客户端发送消息

【网络】UDP服务器的实现_第1张图片

服务器接受消息

【网络】UDP服务器的实现_第2张图片

如何保证UDP的可靠性

传输层无法保证数据的可靠传输,只能通过应用层来实现了。

实现的方式可以参照tcp可靠性传输的方式,只是实现不在传输层,实现转移到了应用层。

实现确认机制、重传机制、窗口确认机制。

除了利用Linux协议栈以及上层socket机制之外,自己可以通过抓包和发包的方式去实现可靠性传输

需要实现如下功能:

发送:包的分片、包确认、包的重发

接收:包的调序、包的序号确认

目前有如下开源程序利用udp实现了可靠的数据传输

分别为RUDP、RTP、UDT。

方法1:RUDP

RUDP 提供一组数据服务质量增强机制,如拥塞控制的改进、重发机制及淡化服务器算法等,从而在包丢失和网络拥塞的情况下, RTP 客户机(实时位置)面前呈现的就是一个高质量的 RTP 流。

在不干扰协议的实时特性的同时,可靠 UDP 的拥塞控制机制允许 TCP 方式下的流控制行为。

方法2:RTP

实时传输协议(RTP)为数据提供了具有实时特征的端对端传送服务,如在组播或单播网络服务下的交互式视频音频或模拟数据。

应用程序通常在 UDP 上运行 RTP 以便使用其多路结点和校验服务;

这两种协议都提供了传输层协议的功能。但是 RTP 可以与其它适合的底层网络或传输协议一起使用

如果底层网络提供组播方式,那么 RTP 可以使用该组播表传输数据到多个目的地。

RTP 本身并没有提供按时发送机制或其它服务质量(QoS)保证,它依赖于底层服务去实现这一过程。 

RTP 并不保证传送或防止无序传送,也不确定底层网络的可靠性。

 RTP 实行有序传送, RTP 中的序列号允许接收方重组发送方的包序列,同时序列号也能用于决定适当的包位置,例如:在视频解码中,就不需要顺序解码。

方法3:UDT

基于UDP的数据传输协议(UDP-basedData Transfer Protocol,简称UDT)是一种互联网数据传输协议。

UDT的主要目的是支持高速广域网上的海量数据传输,而互联网上的标准数据传输协议TCP在高带宽长距离网络上性能很差。

顾名思义,UDT建于UDP之上,并引入新的拥塞控制和数据可靠性控制机制。

UDT是面向连接的双向的应用层协议。它同时支持可靠的数据流传输和部分可靠的数据报传输。

由于UDT完全在UDP上实现,它也可以应用在除了高速数据传输之外的其它应用领域,例如点到点技术(P2P),防火墙穿透,多媒体数据传输等等。

你可能感兴趣的:(linux,C/C++,Linux操作系统)