leevis.com
leevis.com copied to clipboard
linux-1.2.0 tcp/ip实现
概述
linux-0.98可能是最早支持tcp/ip的linux内核版本,该版本由Ross Biro开发,随着内核版本变迁,tcp/ip实现也跟着进行了升级迭代, 随后,Fred N. van Kempen在Ross Biro的基础上,改写了代码的主要部分,发不了Net-2版本。后来Alan Cox等人又对Net-2版本的代码进行了重构和扩充,发布了Net-3版本。而linux-1.2.0(net代码中的版本是1.1.93)应该已经是Net-3版本的代码的最早实现了。
代码
在Linux0.98的代码里,通过fd查找socket时,还需要遍历sockets数组。该版本已经做了优化,不再遍历了。
并且,支持的协议族也是通过调用函数注册的,而不是硬编码到代码里了。
还是先来串一下代码调用流程。
在init/main.c文件的start_kernel
函数中调用net/socket.c文件中的sock_init
初始化网络子系统。
unix socket 则调用的是net/unix/sock.c文件中的unix_proto_init
函数。
inet协议则是调用的net/inet/af_inet.c文件的inet_proto_init
函数。
void inet_proto_init(struct net_proto *pro)
{
struct inet_protocol *p;
int i;
printk("Swansea University Computer Society TCP/IP for NET3.019\n");
/*
* Tell SOCKET that we are alive...
*/
// 注册网络协议族回调函数
(void) sock_register(inet_proto_ops.family, &inet_proto_ops);
seq_offset = CURRENT_TIME*250;
/*
* Add all the protocols.
*/
for(i = 0; i < SOCK_ARRAY_SIZE; i++)
{
// tcp协议
tcp_prot.sock_array[i] = NULL;
// udp协议
udp_prot.sock_array[i] = NULL;
// 原始套接字
raw_prot.sock_array[i] = NULL;
}
tcp_prot.inuse = 0;
tcp_prot.highestinuse = 0;
udp_prot.inuse = 0;
udp_prot.highestinuse = 0;
raw_prot.inuse = 0;
raw_prot.highestinuse = 0;
printk("IP Protocols: ");
// net/inet/protocol.c文件中,定义了TCP、UDP、IMCP等协议
for(p = inet_protocol_base; p != NULL;)
{
struct inet_protocol *tmp = (struct inet_protocol *) p->next;
inet_add_protocol(p);
printk("%s%s",p->name,tmp?", ":"\n");
p = tmp;
}
/*
* Set the ARP module up
*/
arp_init();
/*
* Set the IP module up
*/
ip_init();
}
当应用程序调用socket函数创建socket套接字fd时,实际上是调用了sock_socket
函数,该函数根据协议族(domain)又调用了af_inet 文件中inet_proto_ops
结构体中的inet_create
函数。
应用程序调用bind
时,实际调用了sock_bind
函数, 该函数根据协议族(domain)又调用了af_inet 文件中inet_proto_ops
结构体中的inet_bind
函数。
c文件组织:net/socket.c -> net/inet/af_inet.c -> net/inet/tcp.c 头文件组织:net.h -> sock.h