Linux close
{
//https://www.cnblogs.com/blankqdb/archive/2012/08/30/2663859.html
1. send解析
sockfd:指定发送端套接字描述符。
buff: 存放要发送数据的缓冲区
nbytes: 实际要改善的数据的字节数
flags: 一般设置为0
1) send先比较发送数据的长度nbytes和套接字sockfd的发送缓冲区的长度,如果nbytes > 套接字sockfd的发送缓冲区的长度, 该函数返回SOCKET_ERROR;
2) 如果nbtyes <= 套接字sockfd的发送缓冲区的长度,那么send先检查协议是否正在发送sockfd的发送缓冲区中的数据,如果是就等待协议把数据发送完,如果协议还没有开始发送sockfd的发送缓冲区中的数据或者sockfd的发送缓冲区中没有数据,那么send就比较sockfd的发送缓冲区的剩余空间和nbytes
3) 如果 nbytes > 套接字sockfd的发送缓冲区剩余空间的长度,send就一起等待协议把套接字sockfd的发送缓冲区中的数据发送完
4) 如果 nbytes < 套接字sockfd的发送缓冲区剩余空间大小,send就仅仅把buf中的数据copy到剩余空间里(注意并不是send把套接字sockfd的发送缓冲区中的数据传到连接的另一端的,而是协议传送的,send仅仅是把buf中的数据copy到套接字sockfd的发送缓冲区的剩余空间里)。
5) 如果send函数copy成功,就返回实际copy的字节数,如果send在copy数据时出现错误,那么send就返回SOCKET_ERROR; 如果在等待协议传送数据时网络断开,send函数也返回SOCKET_ERROR。
6) send函数把buff中的数据成功copy到sockfd的改善缓冲区的剩余空间后它就返回了,但是此时这些数据并不一定马上被传到连接的另一端。如果协议在后续的传送过程中出现网络错误的话,那么下一个socket函数就会返回SOCKET_ERROR。(每一个除send的socket函数在执行的最开始总要先等待套接字的发送缓冲区中的数据被协议传递完毕才能继续,如果在等待时出现网络错误那么该socket函数就返回SOCKET_ERROR)
7) 在unix系统下,如果send在等待协议传送数据时网络断开,调用send的进程会接收到一个SIGPIPE信号,进程对该信号的处理是进程终止。
2.recv函数
sockfd: 接收端套接字描述符
buff: 用来存放recv函数接收到的数据的缓冲区
nbytes: 指明buff的长度
flags: 一般置为0
1) recv先等待s的发送缓冲区的数据被协议传送完毕,如果协议在传送sock的发送缓冲区中的数据时出现网络错误,那么recv函数返回SOCKET_ERROR
2) 如果套接字sockfd的发送缓冲区中没有数据或者数据被协议成功发送完毕后,recv先检查套接字sockfd的接收缓冲区,如果sockfd的接收缓冲区中没有数据或者协议正在接收数据,那么recv就一起等待,直到把数据接收完毕。当协议把数据接收完毕,recv函数就把s的接收缓冲区中的数据copy到buff中(注意协议接收到的数据可能大于buff的长度,所以在这种情况下要调用几次recv函数才能把sockfd的接收缓冲区中的数据copy完。recv函数仅仅是copy数据,真正的接收数据是协议来完成的)
3) recv函数返回其实际copy的字节数,如果recv在copy时出错,那么它返回SOCKET_ERROR。如果recv函数在等待协议接收数据时网络中断了,那么它返回0。
4) 在unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用 recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
close系统调用的功能很直接,就是关闭一个已经打开的文件。函数原型:
int close(int fd);
1
fd就是之前用open()获得的一个文件描述符。
在内核中,打开的文件会被维护一个引用计数,每次close()会把文件的引用计数减一,引用计数减少到0的文件才会从内核中释放资源。
close()成功执行后会返回0,否则返回-1,同时失败原因会被记录在errno中。常见的错误原因有:
EBADF:fd不是有效的文件描述符
EINTR:close()被某个信号处理程序中断
EIO:关闭文件时发生了IO错误
调用close()而不检查返回值的代码非常常见,但是严格的说,这其实是个严重的编程错误,因为之前的write()操作也可能会导致close()的失败,如果就这样忽略close()的操作结果可能会导致数据的丢失,在NFS或者有限额的磁盘上尤其常见。
一次成功的close()并不会总是保证所有的数据都会被刷新到磁盘上去,因为内核会延迟写。如果要在close()时需要保证所有的数据都已经保存到磁盘,要使用fsync()系统调用。
另外,需要注意的是,close()的操作对象是文件描述符,它是一个能被重用的整数,所以,如果需要在多线程中操作一个文件,那在多线程中用这个文件描述符来应用该文件不是个好主意,如果一个线程中关闭了文件,然后重新打开的另一个文件重用了同一个整数文件描述符,那么在另外一个线程中就会操作到错误的文件。
另外,如果要使用close()操作套接字,需要确保当前没有其他线程阻塞在该套接字的recv()上,因为该套接字关闭之后另外一个线程会永远收不到任何消息,从而永远阻塞在那里。这种情况下,应该先用shutdown()系统调用来结束所有的连接。
}
//https://www.cnblogs.com/CodingUniversal/p/7593210.html
注意:在Unix系统下,如果recv函数在等待协议接收数据时网络断开了,那么调用recv的进程会接收到一个SIGPIPE信号,进程对该信号的默认处理是进程终止。
/////////////////////////进程对该信号的默认处理是进程终止。/////////////////////////进程对该信号的默认处理是进程终止。/////////////////////////进程对该信号的默认处理是进程终止。