Linux C中的Socket,shutdown函数和close函数有什么不同

Linux C中的Socket,shutdown函数和close函数有什么不同,第1张

假设server和client 已经建立了连接,server调用了close, 发送FIN 段给client(其实不一定会发送FIN段,后面再说),此时server不能再通过

socket发送和接收数据,此时client调用read,如果接收到FIN 段会返回0,但client此时还是可以write 给server的,write调用只负责把数据交给TCP

发送缓冲区就可以成功返回了,所以不会出错,而server收到数据后应答一个RST段,表示服务器已经不能接收数据,连接重置,client收到RST段后无

法立刻通知应用层,只把这个状态保存在TCP协议层。如果client再次调用write发数据给server,由于TCP协议层已经处于RST状态了,因此不会将数据

发出,而是发一个SIGPIPE信号给应用层,SIGPIPE信号的缺省处理动作是终止程序。

有时候代码中需要连续多次调用write,可能还来不及调用read得知对方已关闭了连接就被SIGPIPE信号终止掉了,这就需要在初始化时调用sigaction处

理SIGPIPE信号,对于这个信号的处理我们通常忽略即可,signal(SIGPIPE, SIG_IGN)如果SIGPIPE信号没有导致进程异常退出,write返回-1并且

errno为EPIPE。

#include <unistd.h>

intclose(int fd)

close 关闭了自身数据传输的两个方向。

#include <sys/socket.h>

intshutdown(int sockfd, int how)

shutdown 可以选择关闭某个方向或者同时关闭两个方向,shutdownhow = 1 or how = 2 (SHUT_WR or SHUT_RDWR),可以保证对等方接收到一个EOF字符(即发送了一个FIN段),而不管其他进程是否已经打开了这个套接字。而close不能保证,只有当某个sockfd的引用计数为0,close 才会发送FIN段,否则只是将引用计数减1而已。也就是说只有当所有进程(可能fork多个子进程都打开了这个套接字)都关闭了这个套接字,close 才会发送FIN段。

所以说,如果是调用shutdown how = 1 ,则意味着往一个已经接收FIN的套接字中写是允许的,接收到FIN段仅代表对方不再发送数据,但对方还是可以读取数据的,可以让对方可以继续读取缓冲区剩余的数据。

下面使用shutdown 修改客户端程序,在前面讲过的使用select函数修改后的客户端程序基础上,修改很小一部分:

C++ Code

if (FD_ISSET(fd_stdin, &rset))

{

if (fgets(sendbuf, sizeof(sendbuf), stdin)== NULL)

{

stdineof = 1//表示已经输入完毕

/* 关闭sock的写端,还能够接收数据,在sock的缓冲区末尾添加一个FIN段 */

shutdown(sock, SHUT_WR)

}

else

{

writen(sock, sendbuf, strlen(sendbuf))

memset(sendbuf, 0, sizeof(sendbuf))

}

}

为了测试我们想要的效果,需要在select函数修改后的服务器端程序的 134 行代码之后,即writen 之前 sleep(4)目的是接收到客户端数据后不马

上回射回去,睡眠4s 后在客户端已经关闭连接的情况下再发送数据。

先运行服务器端程序,再运行客户端程序,在客户端标准输入,迅速敲入两行:AAAAA\n BBBBB\n 然后按下ctrl+d 即fgets 会返回NULL,然后调用

shutdown关闭写端,虽然服务器端延时才发送数据,此时客户端写端已经关闭,但还是可以读取到回射回来的数据,服务器端最后得到一个FIN段,read

返回0,打印输出 client close ,并且close(conn)而客户端在读取服务端回射回来的两次数据后,再次read 也返回0,故打印 server connect

close,break退出循环,进程顺利退出。从下面的输出还可以看出,因为延时的关系,所以不像以前那样发射一行就回射一行。

simba@ubuntu:~/Documents/code/linux_programming/UNP/socket$./echoser_select

recv connect ip=127.0.0.1 port=54010

fdsgfgd

gfedg

client close

...........................

simba@ubuntu:~/Documents/code/linux_programming/UNP/socket$./echocli_select_shutdown

local ip=127.0.0.1 port=54010

fdsgfgd

gfedg

fdsgfgd

gfedg

1

gfedg

server connect close

如果我们将客户端程序中的shutdown 改成了 close,那么当延时后服务器端发送数据给客户端时,客户端的读端和写端都已经关闭,第一次发AAAAA会

返回一个RST段,根据本文前面所说,再次发BBBBB直接产生SIGPIPE信号,默认会终止进程,但因为我们已经设置了忽略SIGPIPE信号,所以服务器端进

程不会被终止,但客户端也会出错,因为回到while循环开头,select阻塞等待时发现套接字的读端已经关闭,所以不能再关心可读事件了,select会返

回-1,错误码是 EBADF: Bad File Descriptor。

PHP手册:die()Equivalent to exit()。

说明:die()和exit()都是中止脚本执行函数;其实exit和die这两个名字指向的是同一个函数,die()是exit()函数的别名。该函数只接受一个参数,可以是一个程序返回的数值或是一个字符串,也可以不输入参数,结果没有返回值。

参考:虽然两者相同,但通常使用中也有细微的选择性。例如:

当传递给exit和die函数的值为0时,意味着提前终止脚本的执行,通常用exit()这个名字。

echo "1111"

exit(0)

当程序出错时,可以给它传递一个字符串,它会原样输出在系统终端上,通常使用die()这个名字。

$fp=fopen("./readme.txt","r") or die("不能打开该文件")


欢迎分享,转载请注明来源:夏雨云

原文地址:https://www.xiayuyun.com/zonghe/691370.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-08-01
下一篇2023-08-01

发表评论

登录后才能评论

评论列表(0条)

    保存