18 | 防人之心不可无:检查数据的有效性
18 | 防人之心不可无:检查数据的有效性
讲述:冯永吉
时长10:14大小9.38M
对端的异常状况
缓冲区处理
第一个例子
第二个例子
第三个例子
总结
思考题
赞 7
提建议
精选留言(25)
- LDxy2019-09-121,最终缓冲区的大小应该比预计接收的数据大小大一些,预防缓冲区溢出。2,完全可以动态分配,但是要记得在return前释放缓冲区
作者回复: 👍
29 - 郑祖煌2020-07-02(1).第一道,我们在读数据的时候,一般都需要给应用程序最终缓冲区分配大小,这个大小有什么讲究吗? 有讲究的。如果分配的太小,那就会频繁的从用户太切换到内核态,这样其实非常损耗CPU的时间。同时如果设置的太大的话,那就会长期阻塞在read或者recv函数上,造成可以先服务或者先完成的内容没完成。再次,也得比实际的数据稍微大一些以免缓冲区溢出,边界的问题要想办法做好的调整。。 (2). 第二道,你能分析一下,我们文章中的例子所分配的缓冲是否可以换成动态分配吗?比如调用 malloc 函数来分配缓冲区?是可以动态分配,就是new的话要记得及时的去delete,以免造成内存泄露。展开
作者回复: 回答的这么赞,我还能说啥呢 :)
20 - 超大红细胞2020-01-11一开始不理解为什么设置了 timeout 的 recv 会返回 EAGAIN 错误,在我的知识体系中 EAGAIN 一般出现在非阻塞的 socket 中,后来 man 了一下 SO_RCVTIMEO,发现确实如此,给后面的同学提个醒: Specify the receiving or sending timeouts until reporting an error. The argument is a struct timeval. If an input or output function blocks for this period of time, and data has been sent or received, the return value of that function will be the amount of data transferred; if no data has been transferred and the timeout has been reached then -1 is returned with errno set to EAGAIN or EWOULDBLOCK, or EINPROGRESS (for connect(2)) just as if the socket was specified to be nonblocking. 总之一句话,SO_RCVTIMEO 会导致 recv 返回 EAGAIN展开
作者回复: 👍
16 - 传说中的成大大2019-09-15第一问: 不能太小也不能太大 太小了频繁的用户态和内核态切换,太大了读不够容易阻塞,就算不阻塞也容易浪费 第二问: 如果用malloc频繁的申请和释放也不太好 容易造成碎片共 2 条评论4
- yusuf2019-09-111、大小一般为2的多少次方 2、不能换成动态分配。在read中需要sizeof指明接受数据的最大长度,malloc返回的是一个指针,求指针的sizeof时返回的是指针所占内存大小(32位为4,64位为8),跟实际数据的大小不一致共 3 条评论3
- 郭晓朋2021-01-28你好,对于最后一个例子我感觉好像有问题,--length这种写法会读不到012345678\n这个字符串的,最终导致读到的字符串没有结束符\0。length--导致越界的原因是*buffer++ = c;。不应该先执行buffer++,应该放到if语句之后。
作者回复: 你是说样例的readline程序有问题么?
2 - J.M.Liu2019-09-12老师,第二个例子中,及时加上了msg_length和缓冲区length的大小比较,如果msg_length写得很大(但小于length)而实际数据没有那么大时,服务器也会阻塞在read上吧?所以说判断msg_length<=length并不能接read阻塞的问题呀,只能解内存溢出的问题。
作者回复: 是的,如果是这样,只能说我们双方的通信协议没有得到严格的遵守。
2 - 黄毅2021-04-10关于思考题的第二个问题,有个疑问,如果通过动态分配read_buffer,假设recv能读取512个字节,进一步假设第200个字符是\n,那么在read_line退出前能delete吗?如果delete的话,会不会第201到512字节的数据丢失?
作者回复: 这要看你的程序是怎么设计的,如果是预先读取了512字节,那确实200后的数据,你得想办法重新"缓冲"起来,以便和后面的数据拼凑成完整意义的字节流;如果你是一个一个字节读的,知道读到\n,那么则不必了。 一般情况下,我们是用缓冲来做这件事情,你可以跳到后面的Buffer设计部分,通过指针来指向当前消费的位置,和数据读取的位置做一个比较,就可以不用每次重新生成动态分配的buffer。
1 - lupguo2020-01-12课后题,我的理解是应用程序缓冲区大小设置,如果是预分配buffer情况,应该根据程序场景来的。这个buffer是通过recv系统调用从内核空间将数据拷贝到用户空间,如果buffer过小,会导致需要多次系统调用的开销,过大又会导致用户空间浪费,因此需要选择合适大小;第二个是可以选择动态malloc,只是需要注意释放,否则会有内存泄露的风险;当然也可以基于gc机制来统一回收!1
- 钱2019-11-24😅读完好像明白了,其实应该没明白,因为,课后思考题,答不上来! 在网络编程中,是否做好了对各种异常边界的检测,将决定我们的程序在恶劣情况下的稳定性,所以,我们一定要时刻提醒自己做好应对各种复杂情况的准备,这里的异常情况包括缓冲区溢出、指针错误、连接超时检测等。1
- Khan2023-02-06 来自湖南看到好多人说缓冲区太大会阻塞,不是很理解,读取数据的时候又不是一定要读满整个buffer,而是读取消息头中指定的数据大小而已,所以应该不存在阻塞吧?
- 无名氏2022-05-22临时缓存区,那个“微小瑕疵”,前后两段程序程序没有区别啊😄?
作者回复: 你细品: int nBytes = recv(connfd, buffer, sizeof(buffer), 0); int nBytes = recv(connfd, buffer, sizeof(buffer)-1, 0);
- 纪神籽2022-03-31第三个例子有点疑问,如果第一次调用readline,读取512字节,查到第100字节是换行符,然后就返回结果,这样子剩下的412字节不就会丢失了。是不是应该先把上次readline的数据处理完在进行新的recv。
作者回复: 你说的没错,是需要把剩下的412字节保存下来的。这个例子只是对readline该注意的事项进行了模拟分析。
- 苏志辉2021-10-29第三个例子修改后的版本,如果length为10发送的也是012345678\n一共10个,由于--length,所以一次最多读9个,要读完完整的消息,需要读两次吧
作者回复: 读取的时候,是一次性尝试读取最多 512 字节。 最外面的length循环实际上控制的是拷贝临时缓冲区字符的工作。 所以,还是读取一次。
- 吃猫的鱼2021-08-06第三个例子中,如果recv读取出的数据格式如下 “xxx\n yyy\n”,然后length=4,此时在不就只读出 “xxx\n”,但是下一次调用recv,“yyy\n”没被应用就被丢弃了。。。
作者回复: 这个例子的假设就是\n为报文的分界符。
- null2021-04-05原文: 这个函数一次性读取最多 512 字节到临时缓冲区,之后将临时缓冲区的字符一个一个拷贝到应用程序最终的缓冲区中。 在程序的 26-28 行,判断是否读到换行符,如果读到则将应用程序最终缓冲区截断,返回最终读取的字符个数。 问题: 假设 client 在一个连接中,发了2次请求: 第一次发了1000个字符(包含换行符); 第二次发了24个字符(包含换行符)。 对端 server 在 socket 缓冲区,每次都读取 512 个字符。读到换行就截断。那第二次请求的24个字符不就被截断丢弃了,应用程序再也读不到这24字符了。 请问老师,会出现这种情况么?谢谢展开
作者回复: 不会啊,因为readline这个函数是被反复调用的,所以会读到第二行(也就是第二个换行符)。
- NEVER SETTLE2020-07-20“第二个版本,这个函数一次性读取最多 512 字节到临时缓冲区,之后将临时缓冲区的字符一个一个拷贝到应用程序最终的缓冲区中“ 老师,针对第二个版本,我有个问题,如果“\n”之后还会有内容,当调用recv函数后,假如返回512个字符,但是程序只取了“\n”之前的字符串,那“\n”之后的内容是不是就是丢弃了。
作者回复: 原来问题在这啊。 不会啊,可以继续调用recv函数来读下一个512字节。在网络字节流处理中,循环读取是一个常见的技巧。
共 3 条评论 - NEVER SETTLE2020-07-20“第二个版本,这个函数一次性读取最多 512 字节到临时缓冲区,之后将临时缓冲区的字符一个一个拷贝到应用程序最终的缓冲区中。“
作者回复: 没看懂问题.....
- YC2020-07-20//输入字符为: 012345678\n char buf[10] readline(fd, buf, 10) 为什么会溢出呢?不应该刚刚好填满buffer嘛。 0123456789\n才会溢出吧展开
作者回复: 注意是增加一个\0哦,原来的换行符还是会读取的,所以会溢出的。
- 满怀2019-12-22老师能帮我看一下代码吗 我把这段时间学习到的 整合在一起 现在执行的时候出了一点问题 分析不出错误原因
作者回复: 抱歉,这段时间一直忙,贴下你的代码链接
共 2 条评论