Linux的TCPIP 网络工具

Linux的TCPIP 网络工具,第1张

如今很多系统管理员依然通过组合使用诸如ifconfig、route、arp和netstat等命令行工具(统称为net-tools)来配置网络功能,解决网络故障。net-tools起源于BSD的TCP/IP工具箱,后来成为老版本Linux内核中配置网络功能的工具。 但自2001年起,Linux社区已经对其停止维护。 同时,一些Linux发行版比如Arch Linux和CentOS/RHEL 7则已经完全抛弃了net-tools,只支持iproute2。

作为网络配置工具的一份子,iproute2的出现旨在从功能上取代net-tools。net-tools通过procfs(/proc)和ioctl系统调用去访问和改变内核网络配置,而iproute2则通过netlink套接字接口与内核通讯。抛开性能而言,iproute2的用户接口比net-tools显得更加直观。比如,各种网络资源(如link、IP地址、路由和隧道等)均使用合适的对象抽象去定义,使得用户可使用一致的语法去管理不同的对象。更重要的是,到目前为止,iproute2仍处在 持续开发 中。

如果你仍在使用net-tools,而且尤其需要跟上新版Linux内核中的最新最重要的网络特性的话,那么是时候转到iproute2的阵营了。原因就在于使用iproute2可以做很多net-tools无法做到的事情。

当然这两个工具在大部分Linux系统中自带的,下面通过iproute2的 ip addr show 指令看看返回了哪些内容。

以前一直使用的网络通讯的函数都是工作在阻塞模式。在看connect实现源码时,突然想到tcp/ip的

三次握手在内核如何实现的,尤其是在非阻塞模式下式,涉及到等待对端回送ack包,而本端又要立即返

回,想来这种实现肯定是遵循某种规则或是将所有的相关函数组合起来。

查看一些网络通信书籍,可知果然如此。应用编程如果设置为非阻塞模式,则连接时,connect发送

SYN包后立即返回-EINPROGRESS,表示 *** 作正在处理中;随后应用可以在connect返回后做一些其它的处理,

最后在select函数中来捕获socket的连接、读写、异常事件以触发相关 *** 作,下面我们看看内核中的相关

实现:

一、tcp/ip连接的三次握手过程:

clientSYN包---> server

client<---ACK包 server

clientACK包---> server

二、客户端支持

client发送2个包,一个SYN包,一个对服务器的响应ACK包。

client函数调用链:connect-->sys_connect->inet_stream_connect->tcp_connect...

看inet_stream_connect中实现的部分代码段:

...

switch (sock->state) {

...

/*此处调用tcp_connect函数发送SYN包*/

err = sk->prot->connect(sk, uaddr, addr_len)

if (err <0) //出错则退出

goto out

sock->state = SS_CONNECTING

/* 此处仅设置socket的状态为SS_CONNECTING表示连接状态正在处理

* 不同之处在于非阻塞情况下,返回值设置为-EINPROGRESS表示 *** 作正在处理

* 而阻塞式情况则在获得ACK包后将返回值置为-EALREADY.

*/

err = -EINPROGRESS

break

}

timeo = sock_sndtimeo(sk, flags&O_NONBLOCK)//注意,如果此时设置了非阻塞选项,则timeo返回0

//如果socket对应的sock状态是SYN包已发送或收到SYN包并发送了ACK包,并等待对端发送第三此的ACK包

if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) {

/* 错误返回码err前面已经设置 */

if (!timeo || !inet_wait_for_connect(sk, timeo))

/*注意上面所判断的2中情况,1、如果是非阻塞模式,则!timeo为1,则直接跳到out返回-EINPROGRESS结束connect函数

2、若为阻塞模式,则在inet_wait_for_connect函数中通过schedule_timeout函数放弃cpu控制权睡眠,等待服务器端

发送ACK响应包后被唤醒继续处理。如果没有异常出现,则置socket状态为SS_CONNECTED,表示连接成功,正确返回

*/

goto out

err = sock_intr_errno(timeo)

if (signal_pending(current)) /*处理未决信号*/

goto out

}

...

sock->state = SS_CONNECTED

err = 0

out:

release_sock(sk)

return err

...

上面的描述有一个问题:对服务器的响应ACK包是什么时候发送的?对于非阻塞模式,应该是应用处理过程中

的某个异步时间;对于阻塞模式,则是在inet_wait_for_connect函数中睡眠时处理。

即网卡在收到对方的ack包后,上传给对应的socket时发送服务器的响应ACK包

函数调用链为:netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->

tcp_rcv_state_process-->tcp_rcv_synsent_state_process-->tcp_send_synack-->tcp_transmit_skb...

发送SYN包后,socket对应的sock的状态变成TCPF_SYN_SENT,网卡收到服务器的ack传到tcp层时,根据TCPF_SYN_SENT

状态,做相关判断后再发送用于第三次握手的ack包。至此,将socket的状态改为连接建立,即TCP_ESTABLISHED。

具体的代码大家可以根据我提供的函数调用链查看。

注意,以TCPF_前缀开头的状态都表示是中间状态,而已TCP_为前缀的状态才是socket的一个相对稳定的状态。

这里有一个疑问,,根据接收处理源码,先前的SYN包应该发送给服务器的监听socket,而第三次握手似乎应该发送给

连接(未真正连接,因为三次握手还没完成呢)的socket,这个问题有待进一步确认

三、服务器端支持

服务器端此时必须是监听状态,则其函数调用链为:

netif_rx-->net_rx_action-->...(IP层处理)-->tcp_v4_rcv-->tcp_v4_do_rcv-->

tcp_rcv_state_process-->tcp_v4_conn_request-->tcp_v4_send_synack...

在tcp_v4_conn_request,中部分代码如下:

...

case TCP_LISTEN:

if(th->ack) /*监听时收到的ack包都丢弃?*/

return 1

if(th->syn) {/*如果是SYN包,则调用tcp_v4_conn_request*/

if(tp->af_specific->conn_request(sk, skb) <0)

return 1


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/7191960.html

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

发表评论

登录后才能评论

评论列表(0条)

保存