关于文件和socket读写的系统调用和库函数的一些小问题

stdio中fopen二进制打开和文本打开的区别

因为都是读取的byte by byte,区别在哪里?唯一的区别就是windows VC,文本rw模式对于/r/n的处理。
而unix-like上和二进制没有区别。
所以为了简单还是二进制读取比较好,然后针对场景分别处理。

open在syscall层面有多少种mode

在syscall open中,mode是指rwx,另有oflag:O_APPEND,O_CREATE,O_EXCL,O_TRUNC。搭配O_RDONLY,O_WRONLY,O_RDWR。因为不同的flag决定内核不同的处理逻辑。

file read结束是哪一层判定的

kernel的fs还是,lib层
ssize_t read(int fd, void *buf, size_t count);是syscall,当返回0表示到达文件结尾,当返回-1
表示发生错误。

是syscall就能判定的。

那么kernel是如何判断read的syscall到达了end而立即返回还是等待下一个byte?

因为文件系统的每一个文件都记录了文件的长度,可以根据文件描述符的当前offset判断是否读取完结,并不是根据什么特殊字符。

fgetc是stdio的函数,也就是c语言的标准库中的函数。这是比较上层的函数,而不是原生的系统调用,或c语言对系统调用的对应封装。使用fgetc的时候已经假设返回的一定是一个ascii范围的int,所以很容易定义一个负值作为EOF。标志文件结束的特殊值。

内核对文件读写的完整性控制

因为file的metadata是会记录文件长度的,所以内核很容易知道文件是否读取完成。当文件描述符的当前指针指向结尾处,就可以把系统调用read返回了。

在写文件的时候如果突然掉电或者进程崩溃,如何确保文件的长度和内容保持一致的?

  • 如果是突然掉电,这个很可能无法保证file的完整性,至于什么策略,看不同文件系统的特性。TODO
  • 如果是进程crash,或者进程主动exit。那么os kernel应该可以从容处理进程打开的文件描述符。

那socket的文件描述符如何判断结束

既然file可以通过file长度的元数据判断。socket是如何判定的呢?

tcp socket是通过挥手报文表示结束,当一端收到对方发送的挥手报文,用户空间不能感知到tcp报文,所以当接收到对方的挥手报文后,recv即可return 0,

syscall send何时返回

是tcp pkg已经收到ack后返回还是发送了缓冲区立即返回?
不管是否阻塞模式,当data copied to kernel之后就return。
flag参数MSG_DONTWAIT ,表示当需要阻塞的时候返回错误码,仅在本次send调用中生效。

   MSG_DONTWAIT (since Linux 2.2)
          Enables nonblocking operation; if the operation would block,
          EAGAIN or EWOULDBLOCK is returned.  This provides similar
          behavior to setting the O_NONBLOCK flag (via the fcntl(2)
          F_SETFL operation), but differs in that MSG_DONTWAIT is a per-
          call option, whereas O_NONBLOCK is a setting on the open file
          description (see open(2)), which will affect all threads in
          the calling process and as well as other processes that hold
          file descriptors referring to the same open file description.

所以如果仅有一次tcp socket的send,并不能保证对方确实已经收到消息,因为send只是复制data到kernel就返回了,后续不能感知。

TCP什么时候判断意外断开?

这个应该是内核协议栈的逻辑。考虑有keepalive的设定,那么猜测,如果不设置keepalive应该不能很快检测的。即使断开,如果不通过调用socket的一些方法,是无法知道socket的状态的,那么最后断开之前调用的send是否真的成功无法保证。

多进程append file安全吗

不要求append的顺序,只考察是否覆盖。按照https://stackoverflow.com/questions/7552451/can-multiple-processes-append-to-a-file-using-fopen-without-any-concurrency-prob
syscall的a模式可以保证,但是库一级未必有保证。

TCP如果last send没有收到ack会如何

由于前述send函数在data copied to kernel之后立即返回,那么如果最后一次send失败了,没有收到ack,那么应用程序如何知道呢?
是不是通过close正确返回?

TCP提供的抽象就是一个stream,所以如果持续不断地使用这个stream,如果真的网络断开,那么stream就一定是可以感知到断开,应用程序可以很明确地处理。

但是如果在流的末尾可能还有隐患,就是最后一个send并没有得到对方确认ack,send方法就返回了。

keepalive的问题也是类似,当三次握手之后,如果Client掉电,那么server还是认为处于连接状态,recv还在阻塞,而当client重启后,如果收到server keepalive的syn消息,会返回reset消息给server,server的recv就能够返回。这种情况应该算是errorno ret。

https://stackoverflow.com/questions/38753903/tcp-socket-recv-indicating-unexpected-disconnect-after-successful-send
表明基于socket之后的应用协议仍然需要设计req和resp,和幂等性,因为send并不是收到ack之后返回用户代码。

文件系统如何保证写磁盘原子化

https://unix.stackexchange.com/questions/279708/how-filesystem-atomically-writes-a-block-to-disk
硬盘保证一个扇区的原子写,文件的修改是先尝试修改数据,后原子修改metadata。

原文地址:https://www.cnblogs.com/linlei2099/p/10472498.html