一,UDP简介
UDP是传输层协议,和TCP协议处于一个分层中,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议。
UDP协议是英文UserDatagramProtocol的缩写,即用户数据报协议,主要用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的C/S模式的网络应用都需要使用UDP协议。UDP协议直接位于IP(网际协议)协议的顶层。
特点:
1)无连接,发送数据之前不需要建立连接。开销和发送之前的时间延迟较短。
2)尽最大努力交付。(可以采取一定策略实现可靠传输)
3)面向报文,UDP对应用程序交付的报文,添加UDP首部后直接交给IP层。不合并,不拆分。
4)没有拥塞控制,网络拥塞不会使源主机发送率降低。
5)UDP支持一对一,一对多,多对一的交互通信
6)UDP首部开销较小,8字节(TCP为20字节、IP为20字节)
二,UDP首部格式
源端口:2字节 = 16bit =0 ~ 65535
目的端口:2字节
长度:2字节 用户数据包的长度(最短为8字节,仅有头部)
检验和:2字节
三,常见问题
1,如果接受方UDP发现收到报文中目的端口不正确(不存在对应端口的应用程序)怎么办?
丢弃该报文,由ICMP发送“端口不可达”差错报文给发送发。
traceroute 工作原理,一种利用ICMP的TTL,另一种利用UDP的端口
四,程序实例
Windows C++ 源码 (开发环境:VS2005 ,Win7)
1)发送端
#include <winsock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") using namespace std; int main() { SOCKET sock; //socket char szMsg[] = "this is a UDP test package";//被发送的字段 /*typedef unsigned short WORD*/ WORD wVersionRequested;//1.启动SOCKET库,版本为2.0 WSADATA wsaData;//这个结构被用来存储 被WSAStartup函数调用后返回的 Windows Sockets数据 int err; wVersionRequested = MAKEWORD( 2, 0 );//创建一个被指定变量连接而成的WORD变量。返回一个WORD变量 err = WSAStartup(wVersionRequested, &wsaData );//Winsock服务的初始化 if ( err != 0 ) { cout<<"Socket2.0初始化失败,Exit!"; } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) //判断是否是 2.0版本的socket { WSACleanup( ); } //2.创建socket sock = socket( AF_INET, //代表TCP/IP协议族: UDP, TCP, etc SOCK_DGRAM, //SOCK_DGRAM说明是UDP类型,SOCK_STREAM是TCP类型 0 //protocol ); if (sock == INVALID_SOCKET ) { cout<<"Socket 创建失败,Exit!"; } //3.设置发往的地址 sockaddr_in addrto; //发往的地址 memset(&addrto,0,sizeof(addrto)); addrto.sin_family=AF_INET; //以127开头的ip,并且客户和服务器在同一个局域网,服务方都可以接收(相当于广播); //指定服务方ip的可以接收 addrto.sin_addr.s_addr=inet_addr("127.0.0.1"); addrto.sin_port=htons(7861);//端口号必须和服务器绑定的端口号一致 int nlen=sizeof(addrto); unsigned int uIndex = 1; while(true) { Sleep(1000); //从广播地址发送消息 if( sendto(sock,szMsg,strlen(szMsg),0,(sockaddr*)&addrto,nlen)== SOCKET_ERROR ) cout<<WSAGetLastError()<<endl; else cout<<uIndex++<<":an UDP package is sended."<<endl; } if (!closesocket(sock)) { WSAGetLastError(); } if (!WSACleanup()) { WSAGetLastError(); } }
#include <winsock2.h> #include <iostream> #pragma comment(lib, "ws2_32.lib") using namespace std; void main(void) { SOCKET sock; //1.启动SOCKET库,版本为2.0 WORD wVersionRequested; WSADATA wsaData; int err; wVersionRequested = MAKEWORD( 2, 0 ); err = WSAStartup( wVersionRequested, &wsaData ); if ( err != 0 ) { cout<<"Socket2.0初始化失败,Exit!"; return; } if ( LOBYTE( wsaData.wVersion ) != 2 || HIBYTE( wsaData.wVersion ) != 0 ) { WSACleanup(); return; } //2.创建套接字 sock = socket(AF_INET,SOCK_DGRAM,0); if (sock == INVALID_SOCKET ) { cout<<"Socket 创建失败,Exit!"; return; } //3.绑定 sockaddr_in myaddr; //sockaddr_in相当于sockaddr结构 memset(&myaddr,0,sizeof(myaddr)); myaddr.sin_family=AF_INET; //如果绑定地址不是本机地址或者ADDR_ANY,则recvfrom函数不会正确接收,而是立刻返回 myaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //端口号必须和客户发往的端口号一致 myaddr.sin_port=htons(7861); bind(sock,(sockaddr*)&myaddr,sizeof(myaddr)); int fromlength = sizeof(SOCKADDR); char buf[256]=""; long number=0; while(1) { if(recv(sock,buf,sizeof(buf),0)) { cout<<number<<":"<<buf<<endl; number++; } memset(buf,0,sizeof(buf)); } if (!closesocket(sock)) { WSAGetLastError(); return; } if (!WSACleanup()) { WSAGetLastError(); return; } }