一、UDP协议
UDP协议的特点:用户数据包协议
1、UDP协议是无连接的。也就说在数据发送之前并不需要建立连接(当然,在发送数据结束的时候也就不存在链接的释放),因此减少了开销和数据发送之前的时延。
2、UDP使用尽最大努力的交付,但是不保证可靠性的交付,因此主机不需要维持复杂的链接状态表。(网上的的可靠性建立在应答的基础上,不提供可靠×××付,即不需要应答,因此不需要维护状态表)
3、UDP是面向报文。发送方的UDP对于应用程序进程交下来的报文,即不合并,也不拆分,而是保留这些报文的边界。这也就是说,应用层交付给UDP多长的报文,UDP就照样发送,即一次发送一个报文。同时,在接收方,对于IP层交上来的UDP用户数据报,在去除首部后就原封不动的交付给应用层的应用进程了。也就说,UDP一次交付一个完整的报文。因此报文的大小必须合适,负责会降低数据的传输效率。如果报文太长,在IP层需要对报文分片,就会降低IP层的效率。反之,若报文太短,UDP把它交给IP层后,会使得IP数据报的首部相对过长,同样会降低IP层的效率。
4、UDP没有拥塞控制
二、基于UDP的socket编程的一般流程
1.server端
a.获取有效的IP地址与端口号(port)(服务器端需要约定好的端口号与IP,方便客户直接与该IP下的该端口建立连接)
b.将IP与port转为网络通用格式
c.声明监听文件描述符 (int listen_sock),将该文件描述符”注册“为
套接字文件(listen_sock=socket(AF_INET,SOCK_DGRAM,0))
参数:
AF_INET:IPv4套接字类型(说明地址类型格式)
SOCK_DGRAM:UDP协议类型(提供无连接的尽力交付)
0:表示该套接字只支持一种协议
d.给listen_sock绑定相应的信息( IP,port),因为socket套接字是由内核接管处理的,因此我们无法直接操作,写入信息需要以下操作:
1>声明struct sockaddr_in 结构体,将对因信息赋值给结构体对应单元
local.sin_family=AF_INET;
local.sin_port=htons(port);
local.sin_addr.s_addr=ip;
2>调用bind(int sockfd,struct sockaddr* addr,socklen_t addrlen)函数,将ip,port信息写入(即绑定)套接字的
f.使用recvfrom()接收数据。
server端代码实例:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
void usage(char* arg)
{
printf("Missing Parameters: %s [remote ip :] [remote port :]",arg);
}
int main(int argc,char* argv[])
{
if(argc!=3){
usage(argv[0]);
exit(1);
}
in_addr_t _ip=inet_addr(argv[1]);
int _port=atoi(argv[2]);
int sock=socket(AF_INET,SOCK_DGRAM,0);
struct sockaddr_in server;
socklen_t len=sizeof(server);
server.sin_family=AF_INET;
server.sin_port=_port;
server.sin_addr.s_addr=_ip;
if(bind(sock,(struct sockaddr*)&server,len)<0){
perror("bind");
exit(2);
}
char buf[1024];
while(1){
ssize_t size=recvfrom( sock,buf, 1023,0,\
(struct sockaddr *)&server, &len);
if(size<0){
perror("read");
break;
}else if(size==0){
printf("server %d close: ip: %s !\n",sock,inet_ntoa(server.sin_addr));
}
else{
printf("get a connect %d... ip:%s,port:%d\n",sock\
,inet_ntoa(server.sin_addr),ntohs(server.sin_port));
buf[size]=0;
printf("server# %s\n",buf);
}
}
return 0;
}
a.获取有效的IP地址与端口号(port)(此处为需要发送的目标服务器的ip,与广知的port)
b.将IP与port转为网络通用格式
c.声明文件描述符 (int _sock),将该文件描述符”注册“为
套接字文件(_sock=socket(AF_INET,SOCK_DGRAM,0))
d.声明struct sockaddr_in _server结构体,connect()将目标服务器ip与port写入使用,并与_sock绑定,同时与目标服务器建立连接。
e.使用sendto()向目标发送UDP报文。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <errno.h>
#include <string.h>
#include <arpa/inet.h>
void usage(char* arg)
{
printf("Missing Parameters: %s [remote ip :] [remote port :]",arg);
}
int main(int argc,char* argv[])
{
if(argc!=3){
usage(argv[0]);
exit(1);
}
in_addr_t _ip=inet_addr(argv[1]);
int _port=atoi(argv[2]);
int sock=socket(AF_INET,SOCK_DGRAM,0);
if(sock<-1){
perror("socket");
exit(2);
}
struct sockaddr_in server;
socklen_t len=sizeof(server);
server.sin_family=AF_INET;
server.sin_port=_port;
server.sin_addr.s_addr=_ip;
if( connect( sock, (struct sockaddr *)&server, len)<0){
perror("connect");
exit(3);
}
char buf[1024];
while(1){
printf("please Enter:");
gets(buf);
if(strcmp(buf,"quit")==0){
sendto(sock, buf,0,0 ,(struct sockaddr *)&server, len);
break;
}
sendto(sock, buf,strlen(buf),0 ,(struct sockaddr *)&server, len);
}
close(sock);
return 0;
}
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。