TCP/IP网络编程笔记-ch6.基于UDP的服务器端/客户端

函数

UDP的发送数据

#include<sys/socket.h>

@param sock:用于传输数据的UDP套接字文件描述符
@param buff:保存在待传输数据的缓冲地址符
@param nbytes:待传输的数据长度,字节为单位
@param flags:可选项参数,没有则传递0
@param to:存有目标地址信息的sockaddr结构体变量的地址值
@param addrlen:传递给参数to的地址值结构体变量长度
ssize_t sendto(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *to,socklen_t addrlen);
//成功时返回传输字节数,失败返回-1

UDP的接收数据

#include<sys/socket.h>

@param sock:用于接收数据的UDP套接字文件描述符
@param buff:保存接收数据的缓冲地址符
@param nbytes:可接受的最大字节数,故无法超过参数buff所指的缓冲代销
@param flags:可选项参数,没有则传递0
@param from:存有发送端地址信息的sockaddr结构体变量的地址值
@param addrlen:保存参数from的结构体变量长度的变量地址值
ssize_t recvfrom(int sock,void *buff,size_t nbytes,int flags,struct sockaddr *from,socklen_t *addrlen)
//成功时返回接收的字符串,失败返回-1

UDP特点

UDP提供的是不可靠的数据传输服务。

IP的作用是让离开主机的UDP数据包准确传递到目的主机
将UDP包最终交给目的主机的目的UDP套接字的过程则是由UDP完成的。

UDP与TCP

UDP结构比TCP简洁,它不会发送类似ACK的应答消息,不会像SEQ那样给数据报分配序号。因此UDP性能有时比TCP高出很多,编程中实现UDP也比TCP简单。

为了提供可靠的数据传输服务,TCP在不可靠的IP层进行流控制,UDP则缺少这种流控制机制。(TCP是区分UDP和TCP的最重要的标志)(TCP的生命在于流控制)。

每次交换数据量越大,TCP的传输速率越接近UDP的传输速率。

UDP也具有一定可靠性。
当传递压缩文件时则必须使用TCP,因为压缩文件一旦丢失一部分就很难解压,所以必须使用TCP。
而要求实时性的比如视频和音频传输时,因为需要提供实时服务,速度很重要,因此更优先考虑UDP

UDP并非每次都快于TCP,TCP慢于UDP的原因通常有两点:

收发数据前后进行的连接设置及清除过程
收发数据过程中为保证可靠性而添加的流控制

如果收发数据小但需要频繁连接时,UDP比TCP更高效。

与TCP不同,UDP中的服务器端和客户端没有连接(不必调用TCP连接过程中调用的listen和accept),也因此某种意义上无法区分服务器端和客户端,只是因为其提供服务而称为服务器端。
UDP服务器端和客户端均只需要一个套接字。(TCP中套接字间一对一,10个客户端提供服务,除了守门的服务套接字外,还需要10个服务器套接字)

UDP客户端套接字的地址分配

TCP客户端调用connect函数自动完成IP和端口的分配,而UDP中担任相同功能的函数调用语句都没有。那UDP是怎么完成地址分配的呢:
UDP中,调用sendto函数传输数据前应调用bind函数来完成套接字的地址分配工作。(bind函数不区分TCP与UDP)。
如果在调用sendto函数时尚未分配地址信息,则首次调用sendto函数时会给相应套接字自动分配IP和端口,且此时分配地址保存到程序结束
(由此:UDP调用sendto时自动分配IP和端口号,所以UDP客户端中通常不需要额外的地址分配过程)

UDP的数据传输特性

TCP数据传输不存在边界,与之相对,UDP是具有数据边界的协议,即必须输入函数的调用次数和输出函数的调用次数完全一致,才能保证接收全部已发送数据。
所以UDP编程中常常使用while循环来接收数据。

UDP中存在数据边界,一个数据包即可称为一个完整数据,因此称为数据报。

UDP调用connect函数

UDP套接字中需注册待传输数据的目标IP和端口号,UDP中则不需要注册。由此通sendto函数传递数据的过程大致分为以下三部分:

1.向套接字注册目标IP和端口号
2.传输数据
3.删除UDP套接字中注册的目标地址信息

每次调用sendto函数时重复上过程,这就是能利用一个UDP套接字与多个不同目的UDP套接字进行通信的原因。
这种未注册目标信息的套接字称为未连接套接字。与此相对的就是注册了目标地址的连接connect套接字
要与同一目的主机进行长时间通信时,将UDP套接字变为已连接套接字会提高效率。
实例:

sock=socket(PF_INET,SOCK_DGRAM,0);//第二个参数为SOCK_DGRAM,创建UDP套接字
memset(&adr,0,sizeof(adr));
adr.sin_family=AF_INET;
adr.sin_addr.s_addr=.....
adr.sin_port=....
connet(sock,(struct sockaddr *)&adr,sizeof(adr));

调用connect函数不意味着与对方UDP套接字连接,只是向UDP套接字注册目标IP和端口信息。
之后就和TCP套接字一样,每次调用sendto只需要传输数据,因为已经指定收发对象,不仅可以使用sendto、recvfrom,还能使用write、read函数进行通信。

实例

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HKr10T2D-1641994222597)(https://note.youdao.com/yws/res/2/WEBRESOURCE8196621a333d3197e9682591243a15d2)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aLtAXEUN-1641994222598)(https://note.youdao.com/yws/res/8/WEBRESOURCE114e86f8a52fe91b1be709131d62bdf8)]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值