61.Linux/Unix 系统编程手册(下) -- SOCKET: 高级主题

1.流式套接字上的部分读和部分写
	如果套接字上可用的数据比 read() 调用中请求的数据少,那就可能出现部分读的现象。
	如果没有足够的缓存空间来传输所有的请求,可能会出现部分写的现象。

2.shutdown(int sockfd, int how) 系统调用
	在套接字上调用 close() 会将双向通信管道的两端都关闭。
	系统调用 shutdown() 可以根据 how 的值选择关闭套接字的一端还是两端。

	shutdown() 同 close() 之间的一个重要区别是:无论该套接字上是否还有其他关联的文件描述符,shutdown() 
  都会关闭套接字通道。(换句话说,shutdown() 是根据打开的文件描述符来执行操作的,而同文件描述符无关)。
    fd2 = dup(sockfd);
    close(sockfd);  // 此时,我们仍然可以通过 fd2 在该连接上做 IO 操作

    fd2 = dup(sockfd);
    shutdown(sockfd, SHUT_RDWR); // 该连接的双向通道都会关闭,通过 fd2 也无法进行 IO 操作

3.专用于套接字的 IO 系统调用: recv() 和 send()
	recv(),sned() 系统调用可在已连接的套接字上执行 IO 操作。它们提供了专属套接字的功能,而这些功能在传统的 write(),read() 
  系统调用中是没有的。

4.sendfile(int out_fd, int in_fd, off_t *offset, size_t count) 系统调用
	像 web 服务器和文件服务器这样的应用程序通常需要将磁盘上的文件内容不做修改的通过(已连接)套接字传输出去,其中一种方法是:
		while( (n = read(diskfilefd, buf, size)) > 0)
			write(sockfd, buf, n);
    对于大多数应用程序来说,这是可以接受的。但是,如果我们使用套接字频繁的传输大文件的话,这种技术就显得非常不高效。为了传输文件,
  我们必须使用2个系统调用(可能需要在循环中多次调用):一个用来将文件内容从内核缓冲区cache 拷贝到用户空间,另外一个用来将用户空间缓冲
  拷贝回内核空间,以此才能够通过套接字进行传输。
    系统调用 sendfile() 被设计用来消除这种低效性。当应用程序调用 sendfile() 时,文件内容会直接传送到套接字上,而不会经过用户空间,
  这种技术被称为 零拷贝技术(zero-copy transfer)。

    系统调用 sendfile() 在代表输入文件的描述符 in_fd 和 代表输出文件的描述符 out_fd 之间传送文件内容。描述符 out_fd 必须指向一个
  套接字。参数 in_fd 指向的文件必须是可以进行 mmap() 操作的。我们可以使用 sendfile() 将数据从文件传递到套接字上,但反过来不行。另外,
  我们也不能通过 sendfile() 在两个套接字之间直接传递数据。

    TCP_CORK 套接字选项:
    	要进一步提高 tcp 应用使用 sendfile() 时的性能,Linux 采用专有套接字选项 TCP_CORK 常常会有帮助。例如, web 服务器传送页面给
      浏览器,作为对请求的响应。web 服务器的响应通常有2部分组成: HTTP 首部,也许会通过 write() 来输出;页面数据,可以通过 sendfile()
      来输出。在这种场景下,通常会传输2个 tcp 报文段: HTTP 首部在第一个(非常小)报文段中,而页面数据再第二个报文段中发送。这对网络带宽的利用率
      不够高效。可能还会在发送和接收 tcp 报文时做些不必要的工作,因为在许多情况下 HTTP 首部和页面数据都比较小,足以容纳在一个单独的 tcp 报文中。
      套接字选项 TCP_CORK 正是被设计用来解决这种低效性的。
        当 tcp 套接字上启用了 TCP_CORK 之后,之后所有的输出都会缓冲到一个单独的 tcp 报文段中,直到满足一下条件为止:
        	1.已达报文的大小上限
        	2.取消了 TCP_CORK 选项
        	3.套接字被关闭
        	4.或者当启用 TCP_CORK 后,从写入第一个字节开始,已经经历了 200毫秒
        我们通过 setsockopt() 系统调用来启用或取消 TCP_CORK 选项。


5.获取套接字地址
	getsockname(); // 返回本地套接字地址
	getpeername(); // 返回对端套接字地址

6.TIME_WAIT 状态
	存在的主要目的:	
		1.实现可靠的连接终止
		2.让老的重复的报文段在网络中消失

	这个超时时间是 2倍的 MSL,这里是 MSL(报文最大生存时间)是 tcp 报文在网络中最大的生存时间
	BSD 套接字的实现假设 MSL 为 30s, 而 Linux 遵守 BSD 规范。因此,Linux 上的 TIME_WAIT 状态持续 60s。但是,RFC 1122 建议是MSL 是2分钟,因此
  遵守了这个规则的是 4分钟.

7.监视套接字: netstat
	Active Internet connections (servers and established)
	Proto Recv-Q Send-Q Local Address           Foreign Address         State
	tcp        0      0 0.0.0.0:sunrpc          0.0.0.0:*               LISTEN
	tcp        0      0 localhost.locald:domain 0.0.0.0:*               LISTEN
	tcp        0      0 0.0.0.0:ssh             0.0.0.0:*               LISTEN

	Proto: 套接字所使用的协议
	Recv-Q: 表示套接字接收缓冲区还未被本地应用读取的字节数。对于 udp 套接字来说,该字段不只包含数据,还包含 udp 首部以及其他元数据所占的字节。
	Send-Q: 表示套接字发送缓冲区中排队等待的字节数。和 Recv-Q 字段一样,对 udp 套接字来说,该字段还包含了 udp 首部和其他元数据所占的字节。
	Local Address: 该字段表示套接字绑定到的地址,以主机ip:端口的形式表示。默认情况下,主机地址和端口都以名称形式表示,除非数值形式无法解析到对应
	 			   的主机和服务名称。地址中主机部分的星号(*)表示这是一个通配的 IP 地址。
	Foreign Address: 这是对端套接字所绑定的地址。字符串 *.* 表示没有对端地址。
	State: 表示当前套接字的状态

8.套接字选项
	getsockopt();
	setsockopt();

9.SO_REUSEADDR 套接字选项
	SO_REUSEADDR 选项可以作多种用途。常见的,避免当 tcp 服务器重启时,尝试将套接字绑定到当前已经同 tcp 节点相关联的端口上时出现的 EADDRINUSE(地址已使用),
  错误。这个问题会在如下2种情况中出现:
  	1.之前连接到客户端的服务器要么通过 close(),要么因为崩溃而执行了一个主动关闭。这就使得 tcp 节点处于 TIME_WAIT 状态,而直到2倍的 MSL 超时过去为止。
  	2.之前,服务器先创建一个子进程来处理客户端的连接。稍后,服务器终止,而子进程继续服务客户端,因而使得维护的 tcp 节点使用了服务器的知名端口。
  	以上2种情况,剩下的 tcp 节点无法接受新的连接。尽管如此,针对这2种情况,默认情况下大多数的 tcp 实现会阻止新的监听套接字绑定到服务器的知名端口上。

10.在 accept() 中继承标记和选项
	我们可以将套接字设定为多个选项。如果将这些标记和选项设定在监听套接字上,它们会通过由 accept() 返回的新套接字继承吗?
	在 Linux 上,如下的这些属性是不会被继被 accept() 返回的新的文件描述符所继承的:
	1.同打开的文件描述符相关的状态标记---即,可以通过 fcntl() 的 F_SETTL 操作所修改的标记。这写标记包括 O_NONBLOCK 和 O_ASYNC
	2.文件描述符标记---可以通过 fcntl() 的 F_SETTD 操作来修改的标记。唯一一个这个标记是执行中关闭(close-on-exec)标记。
	3.与信号驱动IO相关联的文件描述符属性。如 fcntl() 的 F_SETOWN(属主进程ID)以及 F_SETSIG(生成信号)操作。
	换句话说,由 accept() 返回的新的描述符继承了大部分套接字选项,这些选项可以通过 setsockopt() 来设定。
	为了满足可移植性,可能需要显示的在 accept() 返回的新套接字上重新设定这些选项。
	

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值