Linux Socket

Socket创建


内核参照2.6.34 (部分2.6.21)

函数调用

sys_socketall() => sys_socket() =>sock_create() => __sock_create()


概要流程


1.      分配socket结构空间

2.      记录socket类型

3.      检查、取得协议族操作表

 

注:

Kernel 通过initcall将inet_family注册到net_families,如下:

fs_initcall(inet_init); => (void)sock_register(&inet_family_ops);

 

 

 

在inet中,会在inet_init()注册不同的sockettype: SOCK_STREAM, SOCK_DGRAM, SOCK_RAW. (这里注册的是不同类型的socket对应的操作所需要的处理函数.也就是各中socket的bind(), listen(), accept()等操作的处理函数.)

 

 

 



 

 


 

4.      执行协议族的创建函数

5.      利用协议族的函数表初始化socket


监听连接listen

调用协议族相应的处理函数,inet则调用inet_listen();


接收连接accept


调用协议族相应的处理函数,inet则调用inet_accept();


准备连接请求connect

1.        内核的连接

sys_socketcall() => sys_connect() =>inet_stream_connect() => tcp_v4_connect()

1)        端口检查与复用

2)        MTU,MSS的设置

3)        滑动窗口的初始化

4)        …

 

Tcp_connect() 发送第一次握手的SYN数据包

2.        分配数据包结构和数据空间

tcp_v4_connect() => tcp_connect() => alloc_skb_fclone() =>__alloc_skb()

 

3.        构建、发送TCP数据包

Tcp_connect() => tcp_transmit_skb()

4.        进化成IP数据包

Tcp_connect() => tcp_transmit_skb() => ip_queue_xmit()

Tcp_connect() => tcp_transmit_skb() => ip_queue_xmit() =>ip_local_out => dst_output() => ip_output() => ip_finish_output()=> ip_finish_output2() => neigh_resolve_output()

 

5.        进化成以太网数据包

neigh_resolve_output() => neigh_hh_init()

 

6.        发送以太网数据包

neith->ops->queue_xmit();

arp_hh_ops中queue_xmit() 对应dev_queue_xmit();

 

neigh_resolve_output() => dev_queue_xmit();


建立连接的过程


接收数据包

注册网卡设备驱动函数

以cs89x0为例, 网卡设备驱动函数调用如下:

init_module() => cs89x0_probe1() => dev->netdev_ops= &net_ops; => register_netdev(dev);

 

1.        当使用ifconfig eth0 up启动网卡时会执行系统调用sys_ioctl(), 最终内核会执行dev_open();

 

dev_open() =>__dev_open();

 

如下,__dev_open()中最终会调用net_ops中的net_open();

 

 

2.        在net_open()中会注册中断函数net_ineterrupt(), 如下:

 

3.        中断到来时会调用net_interrupt(), 如果是由于接收数据包产生的中断, 则调用net_rx();

 

4.        在net_rx()中

a)        分配数据包结构和缓冲块

b)       将数据读入到数据包的数据块中,并调用skb_put调整数据块

c)        记录协议

d)       调用netif_rx()通知内核接收数据包

5.        netif_rx()处理数据包, 使用NAPI,采用轮询的方式获取数据包,改善网络处理的性能.

 

这里的backlog在net_dev_init()中初始化, 如下:

l  初始化接收数据包队列和NAPI队列

l  设置数据包处理函数process_backlog();

l  注册发送数据包的软中断函数net_tx_action();

l  注册接收数据包的软中断函数net_rx_action();

 


 

6.        在net_rx_action()中, 如下, poll()会调用上面注册的函数process_backlog()处理数据包.

do_softirq() => net_rx_action() => process_backlog()

 

7.        在process_backlog()中调用netif_receive_skb()向上层传递数据包.

8.        在netif_receive_skb()中查看是否是bridge, vlan, 是则进入相应的处理, 不是则根据数据包的协议类型, 调用deliver_skb()传递数据包.

此处的pt_prev->func() 由如下的实现在inet_init()中注册.

 


 


对于ip 数据包, packet_type在inet_init()函数中注册, 如下:

 



IP处理数据包

 

1.        调用ip_rcv(), 进入IP数据包的处理流程, 同时进入netfilter系统.

a)        Ip_rcv()首先解析IP数据包,如包头, checksum等;

b)       调用NF_HOOK, 进入NF_INET_PRE_ROUTING处理, 处理结束后调用ip_rcv_finish();

c)        ip_rcv_finish()主要处理两件事情:

                        i.             明确数据包是本地接收还是转发, 如果是转发就需要进一步明确转发的网络设备和跳转出口.

                      ii.             分析和处理关于IP选项的内容

d)       接下来通过dst_input()调用路由表的输入处理函数:

                        i.             如果是转发的数据包, 转发路由表指定的输入处理函数为ip_forward(), 这个函数最终调用dst_output函数转发数据包.

Ip_rcv_finish()=> ip_route_input() => ip_route_input_slow() => ip_mkroute_input()=> __mkroute_input()

 

                                      i.             Ip_forward() 进入netfilter的后续处理

 


 

 

ip_finish_output()=> ip_finish_output2() => net_ratelimit();

 

                      ii.             如果是本地的数据包, 本地路由表指定的输入处理函数为ip_local_deliver()这个函数继续处理数据包.

 

           Ip_rcv_finish() => ip_route_input() => ip_route_input_slow()

 

                                      i.             对数据包IP头部进行检查, 查看是否是分段数据包, 如果是则调用ip_defrage()将分段数据包插入分段队列; 如果是接收的最后一个分段数据包, 则重组数据包.

                                    ii.             无论是重组后的数据包还是直接接收的数据包都要进入ip_local_deliver_finish()函数交给传输层处理.


TCP数据包处理及三次握手


1.        根据IP头部获取当前数据包的协议类型;

2.        传递给raw socket处理

3.        获取传输层函数表的数据结构, 调用传输层函数表的处理函数

 

 

 

a)        传输层函数表是由inet_init()注册. (此处内核注册了对不同协议类型的数据包的处理)

 


 

b)       对于tcp, 即调用tcp_v4_rcv();

 

4.        Tcp_v4_rcv()及三次握手



发送与接收数据包

发送和接收数据包的函数有: 文件系统APIs: read(), write(), SOCKET APIs: send(), recv(), sendto(),recvfrom(), sendmsg(), recvmsg(). 经分析, 无论是文件系统APIs, 还是socket APIs最终都会调用sock_sendmsg()/__sock_sendmsg(),sock_recvmsg()/__sock_recvmsg().

 

针对不同类型的数据类型的socket, 内核注册了不同的针对socket操作的处理函数, 见概要流程 #3.



发送数据包






接收数据包













  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值