数据结构

今日头条试题:小明在抖音关注了n个主播,每个主播每天的开播时间是固定的,分别在时刻开始,ti时刻结束

作者:喵咪咪 链接:https://www.nowcoder.com/discuss/93459?type=0&order=0&pos=23&page=0 来源:牛客网 5. 小明在抖音关注了n个主播,每个主播每天的开播时间是固定的,分别在时刻开始,ti时刻结束。小明无法同时看两个直播。一天被分为m个时间单位。请问小明每天最多能完整观看多少个直播? 输入描述: 第一行一个整数,代表n 第二行一个整数,代表m 第三行空格分隔n*2个整数,代表s,t 输出描述: 一行一个整数,表示答案 输入: 3 10 0 3 3 7 7 0 输出 3 数据范围: 1 <= n <= 10^5 2 <= m <= 10^6 0 <= si,ti < m class Solution: def __init__(self): pass def conflict(self, state, next_tuple): if not state: return False if not next_tuple: return True for i in range(len(state)): if (next_tuple[0] <= state[i][0] and next_tuple[1] > state[i][0]) or (next_tuple[0] >= state[i][0] and next_tuple[0] < state[i][1]): return True return False def find_method(self, lst, array): if not lst: return array array.

Socket TCP协议 实时通信的粘包处理 Java与C++实现

原理: (经典)tcp粘包分析 场景: 此项目是处理实时监测数据,一旦tcp socket建立连接,会不间断实时发送数据,峰值输数据量在3M/秒,这样的数据量必然会造成数据粘包。 目的: TCP连接面向流,读取网络的一包数据不一定正好是协议里定义的完整的一包,有可能是多包,有可能是半包,也有可能是一包半,现在要将每次读取的数据进行分包,也就是粘包处理,提取出完整的一包数据供上层使用,上层需要将完整的一包数据里的数据根据协议定义的格式提取出来。 实现: 将收到的数据copy到缓存区,在缓存区里循环从起始位按照协议找出完整的一包数据提取出来。 关键点在于根据协议找出完整一包数据的长度。 从网络读取数据后拷贝到缓存区 判断:缓存区里数据占位,长度小于某个值n,return再次读取网络数据。这个值n长度的数据内要能解析出单个完整包的长度,以便后续处理 循环:如果缓存区长度大于解析出来的完整一包的长度 执行: 取出完整一包数据后,然后剔除这包,将缓存区剩余数据放置起始位 循环里再次判断: 长度小于某个值n,return再次读取网络数据。 这个值n长度的数据内要能解析出单个完整包的长度,以便后续处理 如果协议定义了帧头,可以在取包的长度之前校验帧头,确保数据正确。 这里说明定义缓冲区buffer的长度大小:必须要大于可能收到的最大数据包的长度加上read读取一次网络最大数据长度 原因是缓冲区里可能剩下不到一包数据,下一次读取网络数据后要将数据copy至缓冲区,如果超过缓冲区大小就无法进行处理。可在copy时加一层判断,如果超过缓存区,就直接返回,断开连接。代表这种数据包不能进行处理。如果缓存区设计合理,不会出现此种情况。read读取一次网络最大数据长度是在read到的buffer定义的长度。缓冲区的buffer不要设置过大,占用太多内存。 数据源说明:第一位固定#。第二位表示之后有几位代表了之后的数据的长度,比如第一条数据的第二位4,代表之后的四位3350是从0:开始共有3350个字节长度的数据。之后的数据跟业务相关。 主要代码: Java实现: 不可用于生产环境,理解思想后根据业务数据处理粘包 private static int MAXDATALEN = 500000; //处理数据缓冲池的长度 private static int RECEIVEDATALEN = 200000;//读取网络数据包最大长度 private int SiglePackageLen = 0;//提取出包的长度 private int SequenceLen = 0;//当前缓冲区内数据长度 private byte BuffSequencePackage[] = new byte[MAXDATALEN];//数据缓冲池 public void readData() { //读取网络数据长度 int RecvLen; //缓存区 byte ReceiveData[] = new byte[RECEIVEDATALEN]; try { while (AdapterManager.

网络编程之:TCP服务器的简单实现

说到TCP服务器,就不得不提socket编程,我们知道,在TCP/IP协议中,“IP地址+TCP或UDP端口号”唯一标识⽹络通讯中的唯一一个进程,“IP地址+端口号”就称为socket。 在TCP协议中,建立连接的两个进程各自有一个socket来标识,那么这两个socket组成 的socket pair就唯一标识一个连接。socket本身有“插座”的意思,因此⽤来描述网络连接的一 对⼀的关 系。 TCP/IP协议最早在BSD UNIX上实现,为TCP/IP协议设计的应用层编程接口称为socket API。 TCP/IP协议规定:网络数据流规定应采用大端字节序,即低地址存储高位数据,因此网络数据流的地址是由低到高的,此处应包括收取哈发送数据两个过程。 1.socket数据类型及其相关函数 socket API是一层抽象的⽹网络编程接口,适⽤用于各种底层⽹网络协议,如IPv4、IPv6,以及UNIX Domain Socket。然⽽,各种网络协议的地址格式并不相同,如下图所示: sockaddr数据结构: 可以看到,各种sockaddr的地址结构前16位都是一样的,都表示整个结构体的长度,IPv4、IPv6和UNIX Domain Socket的地 址类型分别定义为常数AF_INET、AF_INET6、AF_UNI,这样,只要取 得某种sockaddr结构体的 ⾸首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地 址类型字段确定结构体中的内容。因此,socket API可以接受各种类型的sockaddr结构体指针做参数,例如bind、accept、connect等函数,这些函数的参数应该设计成void *类型以便接受各 种类型的指 针,但是sock API的实现早于ANSI C标准化,那时还没有void *类型,因此这些函数的参数都用struct sockaddr *类型表示,在传递参数之前要强制类型转换⼀下。 举个例子:bind(listen_sock,(struct sockaddr*)&local,sizeof(local)) 下面是基于TCP协议服务器/客户端的一般流程: 服务器调用socket()—创建套接字、bind()—绑定、listen()—监听, 完成初始化后,调⽤accept()阻塞等待,处于监听端口的状态,客户端调用socket()初始化后,调用connect()发出SYN段并阻塞等待服务器应答,服务器应答一个SYN-ACK段,客户端收到后从connect()返回,同时应答一个ACK段,服务器收到后从accept()返回。 数据传输的过程: 建立连接后,TCP协议提供全双工的通信服务,但是一般的客户端/服务器程序的流程是由客户端主动发起请求,服务器被动处理请求,一问一答的⽅方式。因此,服务器accept()返回后立刻调用read(),读socket就像读管道一样,如果没有数据到达就阻塞等待,这时客户端调用write()发送请求给服务器,服务器收到后从read()返回,对客户端的请求进行处理,在此 期间客户端调用read()阻塞等待服务器的应答,服务器调用write()将处理结果发回给客户端,再次调⽤用read()阻塞 等待下一条请求,客户端收到后从read()返回,发送下一条请求,如此循环下去。 如果客户端没有更多的请求了,就调用close() 关闭连接,就像写端关闭的管道⼀样,服务器 的 read()返回0,这样服务器就知道客户端关闭了连接,也调⽤用close()关闭连接。注意,任何⼀方close()后,连接的两个传输⽅方向都关闭,不能再发送数据了。如果⼀方调用shutdown() 则连接处于半关闭状态,仍可接收对⽅方发来的数据。 下面就来看一下这个服务器和客户端是如何实现的: 首先来到目录下创建server.c和client.c两个文件,在编写一下Makefile文件,然后正式编写server.c: 以上就是server的编写,下面是client 的编写: 好了,现在服务器和客户端已将编写好了,我们来测试一下: 我们在另一个终端进入到目标目录里运行client,并输入文字: 然后来看看客户端是否可以收到client发过来的消息: server已经成功收到了消息,并且TCP服务器只能被动的接受处理client发起的请求,所以只能是server接受client发来的消息,server并不能给client发消息。 好啦,这就是我编写的简单的TCP服务器/客户端啦,希望各种小伙伴们指出问题,共同学习~