1.UDP首部
2.UDP网络编程步骤
-
服务端:socket -> bind -> recvfrom/sendto -> close
-
客户端:socket -> sendto/recvfrom -> close
//UDP服务器 #include <sys/types.h> #include <sys/socket.h> /*包含socket()/bind()*/ #include <netinet/in.h> /*包含struct sockaddr_in*/ #include <string.h> /*包含memset()*/ #define PORT_SERV 8888/*服务器端口*/ #define BUFF_LEN 256 /*缓冲区大小*/ void static udpserv_echo(int s, struct sockaddr* client) { int n; /*接收数据长度*/ char buff[BUFF_LEN]; /*接收发送缓冲区 */ socklen_t len; /*地址长度*/ while(1) /*循环等待*/ { len = sizeof(*client); n = recvfrom(s, buff, BUFF_LEN, 0, client, &len); /*接收数据放到buff中,并获得客户端地址*/ sendto(s, buff, n, 0, client, len);/*将接收到的n个字节发送回客户 端*/ } } int main(int argc, char*argv[]) { int s; /*套接字文件描述符*/ struct sockaddr_in addr_serv,addr_clie; /*地址结构*/ s = socket(AF_INET, SOCK_DGRAM, 0); /*建立数据报套接字*/ memset(&addr_serv, 0, sizeof(addr_serv)); /*清空地址结构*/ addr_serv.sin_family = AF_INET; /*地址类型为AF_INET*/ addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址0.0.0.0*/ addr_serv.sin_port = htons(PORT_SERV); /*服务器端口*/ bind(s, (struct sockaddr*)&addr_serv, sizeof(addr_serv)); /*绑定地址*/ udpserv_echo(s, (struct sockaddr*)&addr_clie); /*回显处理程序*/ return 0; }
//UDP客户端 #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <sys/socket.h> /*包含socket()/bind()*/ #include <netinet/in.h> /*包含struct sockaddr_in*/ #include <string.h> /*包含memset()*/ #define PORT_SERV 8888 /*服务器端口*/ #define BUFF_LEN 256 /*缓冲区大小*/ static void udpclie_echo(int s, struct sockaddr*to) { char buff[BUFF_LEN] = "UDP TEST"; /*发送给服务器的测试数据 */ struct sockaddr_in from; /*服务器地址*/ socklen_t len = sizeof(*to); /*地址长度*/ sendto(s, buff, BUFF_LEN, 0, to, len); /*发送给服务器*/ recvfrom(s, buff, BUFF_LEN, 0, (struct sockaddr*)&from, &len); /*从服务器接收数据*/ printf("recved:%s ",buff); /*打印数据*/ } int main(int argc, char*argv[]) { int s; /*套接字文件描述符*/ struct sockaddr_in addr_serv; /*地址结构*/ s = socket(AF_INET, SOCK_DGRAM, 0); /*建立数据报套接字*/ memset(&addr_serv, 0, sizeof(addr_serv)); /*清空地址结构*/ addr_serv.sin_family = AF_INET; /*地址类型为AF_INET*/ addr_serv.sin_addr.s_addr = htonl(INADDR_ANY); /*本地地址0.0.0.0*/ addr_serv.sin_port = htons(PORT_SERV); /*服务器端口*/ udpclie_echo(s, (struct sockaddr*)&addr_serv); /*客户端回显程序*/ close(s); return 0; }
运行结果:
3.send()/recv()和sendto()/recvfrom()的区别
int send(SOCKET s, const char FAR *buf, int len, int flags); int recv(SOCKET s, char FAR *buf, int len, int flags); int sendto(int sockfd, const void *msg,int len unsigned int flags, const struct sockaddr *to, int tolen); int recvfrom(int sockfd,void *buf,int len,unsigned int flags,struct sockaddr *from,int *fromlen);
1)sendto()比send()多了两个参数,to表示目的主机IP地址和端口号信息,tolen常常被赋值为sizeof (struct sockaddr)
2)from是一个struct sockaddr类型的变量,该变量保存源主机的IP地址及端口号,fromlen常置为sizeof (struct sockaddr),当recvfrom()返回时,fromlen包含实际存入from中的数据字节数
3)一般情况下,send()/recv()用于TCP,但send()/recv()也可以用于UDP,用于UDP时应当注意的是,要对数据报socket调用connect() ,但socket仍然是数据报socket,并且利用传输层的UDP服务
4)一般情况下,sendto()/recvfrom()用于UDP,但sendto()/recvfrom()也可以用于TCP,用于TCP时最后两个参数没用
4.TCP和UDP的区别
1)TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2)TCP面向字节流,把应用层交下来的数据看成一连串无结构的字节序列,TCP有一个缓冲,当应用层的数据块太长,TCP就可以把它划分短一些再传送,如果太短,TCP也可以等待积累有足够多的字节后再构成TCP报文发送出去;UTP面向报文,UDP对应用层交下来的报文,即不合并,也不拆分,而是保留这些报文的边界,直接添加UDP首部后就向下交付给网络层
4)TCP保证可靠交付,通过TCP传输的数据,无差错,不丢失,不重复,且按序到达;而UDP尽最大努力交付,不保证可靠交付,收到有差错的数据段直接丢弃
- 若通信数据完整性需让位与通信实时性,则应该选用 TCP 协议(如文件传输、重要状态的更新等);反之,则使用 UDP 协议(如视频传输、实时通信等),语音单包数据一般比较小,要求传输的实时性高,你可以想象,在你打电话的时候,你可以接受偶尔一个丢音或者串音,但你绝不能接受因为要进行差错控制或信息重传而导致你的通话中断N秒,然后再继续,对吧?
- 现代网络中,越来越多使用UDP而不是TCP,网络质量的提升给UDP的稳定性提供可靠网络保障,丢包率很低,如果在应用层加上序列号和重传机制,也能够确保传输的可靠性,目前有利用udp实现了可靠传输的协议:RUDP、RTP、UDT
5)网页上的视频是基于HTTP/HTTPS,传输层是TCP,因为网页上看视频可以忍受缓冲,所以用TCP问题不大;视频聊天时绝不能容忍缓存一会才听到对方的回话,强调实时性,所以用UDP更合适;使用TCP还是UDP是在网络条件有限的情况下对“实时性”和“数据完整性”之间的权衡
6)TCP占用系统资源大,UDP占用系统资源小
7)套接字编程步骤不同
8)TCP支持的应用协议主要 有:Telnet、FTP、SMTP等;UDP支持的应用层协议主要有:DNS、NFS(网络文件系统)、SNMP(简单网络管理协议)、TFTP(通用文件传输协议)等.
9)TCP首部至少20字节(20~60),UDP首部为固定的8字节
10)TCP有确认和重传机制、流量控制、拥塞控制;UDP没有