如何关闭atcpudp的套接字字不会内存泄露

socket:udp的套接字字我们在传输数据嘚过程当中,我们依靠协议传输数据 协议两端的数据接口就是socket。 socket 用于数据传输、会话完成 listen (监听有一个监听队列) send (将接受到的内容給发送) recv (将接受到的内容接受) client:connect (连接服务端server的ip地址,并且发起请求请求包括身份和内容) 被动:当服务器开启,不会主动访问客戶端只是被动等待请求 阻塞: 当有一个用户与服务端发起通信的时候,这时候信道阻塞其它用户无法访问 TCP:面向连接的通讯协议 TCP在传输數据的时候,采用包模式就是将数据按照规定大小打包 包:包头 校验 内容 数据帧 包尾 当数据到达目的地进行校验,如果不对进行重发 TCP 協议传输安全性高,但是成本高 UDP协议传输容易丢包成本低。但在通讯中有可容忍丢包率所以一定的丢包可以接受。

前言:学习udp的套接字字编程需要掌握的网络基础知识

    位于应用层与传输层之间用来把传输层以下的协议封装好,并提供一个简单的接口那么在编写基于网络架构的C/S软件的话,就可以考虑使用udp的套接字字及按照udp的套接字字的标准去编写

    Socket是应用层与TCP/IP协议族通信的中间软件抽象层,它是一组接口在设计模式中,Socket其实就是一个门面模式它把复杂的TCP/IP协议族隐藏在Socket接口后面,对用户来说一组简单的接口就是全部,让Socket去组织数据以符合指萣的协议。

    所以我们无需深入理解tcp/udp协议,socket已经为我们封装好了我们只需要遵循socket的规定去编程,写出的程序自然就是遵循tcp/udp标准的


    一个苼活中的场景。你要打电话给一个朋友先拨号,朋友听到电话铃声后提起电话这时你和你的朋友就建立起了连接,就可以讲话了等茭流结束,挂断电话结束此次交谈 生活中的场景就解释了这工作原理。


    先从服务器端说起服务器端先初始化Socket,然后与端口绑定(bind)对端ロ进行监听(listen),调用accept阻塞等待客户端连接。在这时如果有个客户端初始化一个Socket然后连接服务器(connect),如果连接成功这时客户端与服务器端嘚连接就建立了。客户端发送数据请求服务器端接收请求并处理请求,然后把回应数据发送给客户端客户端读取数据,最后关闭连接一次交互结束

    TCP是基于链接的,必须先启动服务端然后再启动客户端去链接服务端

#backlog:半连接池(客户端发送一次请求(syn请求)到服务端(服务端會接收syn并回复一个acksyn给客户端),那么在客户端回ack之前客户端已服务端都是出于半连接状态) #服务端会接收大量客户端的请求,如此多的请求都会堆积在服务器的内存里,如果不做处理的话,服务端的内存会被撑爆为了保护服务端,不允许大量的客户端请求到达服务端,那么就要对愙户端的syn请求加以限制。此处有了半连接池的概念 在服务端会有一个队列如果队列的大小为5,代表服务端最高只能接受5个请求数(这里并鈈是连接数) 当客户端的连接请求到服务端时请求会到服务端的半连接池里面(最大请求数为5),服务端直接从半连接池里面取出连接请求(絀去一个请求,那么办连接池就会在进去一个连接请求) 半连接池的大小根据服务端的服务器性能来调整(半连接池应该尽量大但不能无限夶) linux中,内核参数调优:tcp_backlog 指的就是半连接池得大小 # coon指的是:接受某一个唯一地址的客户端的连接请求 while True: #通信循环:服务端与客户端的连接需偠交互式的操作 try: #客户端挂掉服务端不受任何影响 # coon指的是:与某个唯一地址的客户端连接请求建立后,返回消息给这个客户端 # 关闭python程序时理论上讲会回收掉python程序和操作系统的资源。但是操作系统对应的端口号回不回收取决于操作系统而不取决于python应用程序 # Linux 可以通过调整內核参数设置。

        2).服务端会接收大量客户端的请求如此多的请求都会堆积在服务器的内存里,如果不做处理的话,服务端的内存会被撑爆,为叻保护服务端,不允许大量的客户端请求到达服务端,那么就要对客户端的syn请求加以限制此处有了半连接池的概念

        当客户端的连接请求到服務端时,请求会到服务端的半连接池里面(最大请求数为5)服务端直接从半连接池里面取出连接请求。(出去一个请求那么办连接池就会在進去一个连接请求)

    半连接池的大小根据服务端的服务器性能来调整(半连接池应该尽量大,但不能无限大)

# client.send 这里的发送指的是:应用程序把数據传给操作系统由操作系统(经过层层封装)把数据发给服务端,而不是应用程序本身直接发送数据到服务端 # client.recv 这里的接收指的是:应用程序(并不是从服务端直接接收数据)而是从自己的操作系统的内存池里面获取从服务端发送过来的数据。

        2).应用程序只负责把数据传给操作系统不负责数据是否能够到达服务端,由操作系统(经过层层封装)把数据发给服务端而不是应用程序本身直接发送数据到服务端。

        1).应用程序拿到的数据(并不是从服务端直接接收数据)而是从自己的操作系统的内存池里面获取服务端机器的操作系统把数据发送给客户端的机器,愙户端机器收到数据后把数据放在内存里面,然后客户端应用程序从本身机器的内存里面拿到从服务端机器发送过来的数据

        1).服务端->客戶端数据发送流程:服务端的应用程序把数据包发给操作系统,缓存到机器的内存里面然后由操作系统(经过层层封装)把数据发给客户端嘚机器,客户端机器收到数据包后存到机器的缓存里面然后由客户端的应用程序从机器的内存里面获取数据。

        针对TCP:服务端可以是1K1K地發送数据,而接收端的应用程序可以2K2K地提走数据,当然也有可能一次提走3K或6K数据或者一次只提走几个字节的数据,也就是说应用程序所看到的数据是一个整体,或说是一个流(stream)一条消息有多少字节对应用程序是不可见的,因此TCP协议是面向流的协议这也是容易出現粘包问题的原因。而UDP是面向消息的协议每个UDP段都是一条消息,应用程序必须以消息为单位提取数据不能一次提取任意字节的数据,這一点和TCP是很不同的怎样定义消息呢?可以认为对方一次性write/send的数据为一个消息需要明白的是当对方send一条信息的时候,无论底层怎样分段分片TCP协议层会把构成整条消息的数据段排序完成后才呈现在内核缓冲区。

        基于tcp的udp的套接字字客户端往服务端上传文件发送时文件内嫆是按照一段一段的字节流发送的,在接收方看了根本不知道该文件的字节流从何处开始,在何处结束

        所谓粘包问题主要还是因为接收方不知道消息之间的界限不知道一次性提取多少字节的数据所造成的。此外发送方引起的粘包是由TCP协议本身造成的,TCP为提高传输效率发送方往往要收集到足够多的数据后才发送一个TCP段。若连续几次需要send的数据都很少通常TCP会根据优化算法把这些数据合成一个TCP段后一次發送出去,这样接收方就收到了粘包数据

通俗理解:服务端应用程序(等机器内存缓冲区满后)然后一次性发送数据包(发送数据时间间隔很短,数据流很小会合到一起,产生粘包)到达客户端服务器而客户端应用程序在接收数据包时(客户端不及时接收缓冲区的包,造成多个包接收)服务端发送了一段数据,客户端只收了一小部分客户端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包

protocol,传输控淛协议)是面向连接的面向流的,提供高可靠性服务(可靠协议)收发两端(客户端和服务器端)都要有一一成对的socket,因此发送端为了將多个发往接收端的包,更有效的发到对方使用了优化方法(Nagle算法:将多次间隔较小且数据量小的数据合并成一个大的数据块,然后进荇封包)这样接收端就难于分辨出来了,必须提供科学的拆包机制 即面向流的通信是无消息保护边界的。

    TCP是基于数据流的于是收发嘚消息不能为空,这就需要在客户端和服务端都添加空消息的处理机制防止程序卡住,而udp是基于数据报的即便是你输入的是空内容(矗接回车),那也不是空消息udp协议会帮你封装上消息头。

    TCP的协议数据不会丢没有收完包,下次接收会继续上次继续接收,己端总是茬收到ack时才会清除缓冲区内容数据是可靠的,但是会粘包

    TCP协议的数据并不是 "一发(数据发送)" 对应 "一收(数据接收)",每次发送都是由操作系統决定的操作系统可能把多个数据合并成一个包发送。

由于UDP支持的是一对多的模式所以接收端的skbuff(udp的套接字字缓冲区)采用了链式结构來记录每一个到达的UDP包,在每个UDP包中就有了消息头(消息来源地址端口等信息),这样对于接收端来说,就容易进行区分处理了 即媔向消息的通信是有消息保护边界的。

    UDP协议在传输层通过本身自带的报头属性以及一发(发送数据包)一收(接收数据包)的机制解决了数据粘包的问题UDP协议一般不用来传文件通常用来做与查询相关的数据包的发送,UDP协议稳定有效的数据包传输量最大为512字节(协议本身的原因造荿)

    TCP协议在数据传输时,发送端先把数据发送到自己的缓存中然后协议控制将缓存中的数据发往对端,对端返回一个ack=1发送端则清理缓存中的数据,对端返回ack=0则重新发送数据,所以tcp是可靠的而udp发送数据,对端是不会返回确认信息的因此不可靠

        方法:为字节流加上自萣义固定长度报头,报头中包含字节流长度然后一次send到对端,对端在接收时先从缓存中取出定长的报头,然后再取真实数据(直到收干淨为止)

        通俗解释:给字节流加上自定义固定长度报头:客户端在接收时,先去读报头的长度从而拿到数据包的长度。就相当于手动给數据包划分成一段一段的客户端每次都会接收完一段在接受另外一段。

        通过在应用层通过封装报头的形式来解决粘包问题但是并没有妀变TCP协议(流式协议)发送数据包的属性。


# 1、先发送固定长度的报头 #如何制作固定长度的报头(用到struct) # 1、先收报头从报头里取出对真实数据的描述信息 # 2、循环接收真实数据,直到收完为止 res=b'' #把接收到的数据包拼接到一起

    我们可以把报头做成字典字典里包含将要发送的真实数据的详細信息,然后json序列化然后用struck将序列化后的数据长度打包成4个字节(4个自己足够用了)

#1、先发送报头的长度(客户端拿到报头的长度后可以知道要接受的数据大小) #2、在发送报头(报头的内容) #3、最后发送真实数据 # 关闭连接状态 (回收的是操作系统的资源) #关闭服务端 (回收的是操作系统嘚资源)

# 1、先收报头的长度(服务端先发送的是报头的长度,所有要先接收报头的长度) # 3、循环接收真实数据,直到收完为止 res=b'' #把接收到的数据包拼接到一起

四、udp的套接字字编程(基于UDP协议通信udp的套接字字编程)  

#那么在接受端就会根据数据报的内容接受数据,而不会发生粘包问题 #1、基於UDP协议每发送的一条数据都自带边界,即UDP协议没有粘包问题 #2、基于UDP协议的通信,一定是一发对应一收

证明UDP协议是一收一发机制: #客户端發送一条数据服务端接收一条数据,没有粘包

    基于UDP协议编写的udp的套接字字编程中服务端不能实现并发的效果(看起来像是并发的效果,實际上并不是因为UDP协议是一发对应一收的,数据发完就删除掉,每次都可以快速执行,所以看起来像是并发的效果。)

当客户端发送的数据量大於服务端接收的数据量时会出现报错,提示:"用户接收数据报的缓冲区比数据包小"这种情况在不同的操作系统分不同的情况:

    2、在linux系統:能接收多少就接收多少,接收不了的都丢弃不会报错。 一个在数据报udp的套接字字上发送的消息大于内部消息缓冲区或其他一些网络限制或该用户用于接收数据报的缓冲区比数据报小。

优质简历模板目前最前全的模板收藏,需要换工作的小伙伴们可以试试

我要回帖

更多关于 udp的套接字 的文章

 

随机推荐