`
diecui1202
  • 浏览: 98490 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Linux内核网络协议栈4-创建socket(续)

阅读更多

接上篇“创建socket” 一文;

 

5、分配sock结构:

本文中的例子会调用inet_family_ops.create方法即inet_create方法完成socket的创建工作;其调用链如下:

net/Socket.c:sys_socket()->sock_create()->__sock_create()->net/ipv4/Af_inet.c:inet_create();

inet_create()主要完成以下几个工作:

1) 设置socket的状态为SS_UNCONNECTED;

sock->state = SS_UNCONNECTED;

 


2) 根据socket的type找到对应的套接字类型:

list_for_each_rcu(p, &inetsw[sock->type]) {
    answer = list_entry(p, struct inet_protosw, list);

    /* Check the non-wild match. */
    if (protocol == answer->protocol) {
        if (protocol != IPPROTO_IP)
            break;
    } else {
        /* Check for the two wild cases. */
        if (IPPROTO_IP == protocol) {
            protocol = answer->protocol;
            break;
        }
        if (IPPROTO_IP == answer->protocol)
            break;
    }
    err = -EPROTONOSUPPORT;
    answer = NULL;
}
由于同一type不同protocol的套接字保存在inetsw中的同一链表中,因此需要遍历链表来查找;在上面的例子中,会将protocol重新赋值为answer->protocol,即IPPROTO_TCP,其值为6;

3) 使用匹配的协议族操作集初始化socket;
sock->ops = answer->ops;
answer_prot = answer->prot;// 供后面使用
结合例子,sock变量的ops指向inet_stream_ops结构体变量;

4) 分配sock结构体变量net/Socket.c:sys_socket()->sock_create()->__sock_create()->net/ipv4/Af_inet.c:inet_create()->net/core/Sock.c:sk_alloc():
sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);
其中,answer_prot指向tcp_prot结构体变量;
struct sock *sk_alloc(struct net *net, int family, gfp_t priority, struct proto *prot) {
	struct sock *sk;

	sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);
	if (sk) {
		sk->sk_family = family;

		sk->sk_prot = sk->sk_prot_creator = prot;
		sock_lock_init(sk);
		sock_net_set(sk, get_net(net));
	}

	return sk;
}
其中,sk_prot_alloc分配sock结构体变量;由于在inet_init中为不同的套接字分配了高速缓冲区,因此该sock结构体变量会在该缓冲区中分配空间;分配完成后,对其做一些初始化工作:
i) 初始化sk变量的sk_prot和sk_prot_creator;
ii) 初始化sk变量的等待队列;
iii) 设置net空间结构,并增加引用计数;

6、建立socket结构与sock结构的关系:
1) socket, sock, inet_sock, tcp_sock的关系
创建完sk变量后,回到inet_create函数中:
inet = inet_sk(sk);
static inline struct inet_sock *inet_sk(const struct sock *sk)
{
	return (struct inet_sock *)sk;
}
这里是根据sk变量得到inet_sock变量的地址;细心的同学可能会问到:inet_sock是什么?之前分配的是sock变量,与inet_sock有什么关系啊?
a. struct socket:这个是基本的BSD socket,应用程序通过系统调用开始创建的socket都是该结构体,它是基于虚拟文件系统创建出来的;
类型主要有三种,即流式、数据报、原始套接字协议;
其状态比较粗粒度,如下:
typedef enum {
	SS_FREE = 0,			/* not allocated		*/
	SS_UNCONNECTED,			/* unconnected to any socket	*/
	SS_CONNECTING,			/* in process of connecting	*/
	SS_CONNECTED,			/* connected to socket		*/
	SS_DISCONNECTING		/* in process of disconnecting	*/
} socket_state;
b. struct sock:它是网络层的socket;对应有TCP、UDP、RAW三种;
其状态相比socket结构更精细:
enum {
	TCP_ESTABLISHED = 1,
	TCP_SYN_SENT,
	TCP_SYN_RECV,
	TCP_FIN_WAIT1,
	TCP_FIN_WAIT2,
	TCP_TIME_WAIT,
	TCP_CLOSE,
	TCP_CLOSE_WAIT,
	TCP_LAST_ACK,
	TCP_LISTEN,
	TCP_CLOSING,	/* Now a valid state */

	TCP_MAX_STATES	/* Leave at the end! */
};
c. struct inet_sock:它是INET域的socket表示,是对struct sock的一个扩展,提供INET域的一些属性,如TTL,组播列表,IP地址,端口等;
d. struct raw_socket:它是RAW协议的一个socket表示,是对struct inet_sock的扩展,它要处理与ICMP相关的内容;
e. sturct udp_sock:它是UDP协议的socket表示,是对struct inet_sock的扩展;
f. struct inet_connection_sock:它是所有面向连接的socket表示,是对struct inet_sock的扩展;
g. struct tcp_sock:它是TCP协议的socket表示,是对struct inet_connection_sock的扩展,主要增加滑动窗口,拥塞控制一些TCP专用属性;
h. struct inet_timewait_sock:它是网络层用于超时控制的socket表示;
i. struct tcp_timewait_sock:它是TCP协议用于超时控制的socket表示;

上面简单介绍了一下内核中不同的socket相关的结构体的作用;回到inet_create函数中:
inet = inet_sk(sk);
这里为什么能直接将sock结构体变量强制转化为inet_sock结构体变量呢?只有一种可能,那就是在分配sock结构体变量时,真正分配的是inet_sock或是其他结构体;

我们回到分配sock结构体的那块代码(参考前面的5.4小节:net/core/Sock.c):
static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority, int family) {
	struct sock *sk;
	struct kmem_cache *slab;

	slab = prot->slab;
	if (slab != NULL)
		sk = kmem_cache_alloc(slab, priority);
	else
		sk = kmalloc(prot->obj_size, priority);

	return sk;
}
上面的代码在分配sock结构体时,有两种途径,一是从tcp专用高速缓存中分配;二是从内存直接分配;前者在初始化高速缓存时,指定了结构体大小为prot->obj_size;后者也有指定大小为prot->obj_size,
根据这点,我们看下tcp_prot变量中的obj_size(net/ipv4/Tcp_ipv4.c):
.obj_size		= sizeof(struct tcp_sock),
也就是说,分配的真实结构体是tcp_sock;由于tcp_sock、inet_connection_sock、inet_sock、sock之间均为0处偏移量,因此可以直接将tcp_sock直接强制转化为inet_sock;这几个结构体间的关系如下:

2) 建立socket, sock的关系
创建完sock变量之后,便是初始化sock结构体,并建立sock与socket之间的引用关系;调用链如下:
net/Socket.c:sys_socket()->sock_create()->__sock_create()->net/ipv4/Af_inet.c:inet_create()->net/core/Sock.c:sock_init_data():
该函数主要工作是:
a. 初始化sock结构的缓冲区、队列等;
b. 初始化sock结构的状态为TCP_CLOSE;
c. 建立socket与sock结构的相互引用关系;

7、使用tcp协议初始化sock:
inet_create()函数最后,通过相应的协议来初始化sock结构:
if (sk->sk_prot->init) {
    err = sk->sk_prot->init(sk);
    if (err)
        sk_common_release(sk);
}
例子中,这里调用的是tcp_prot的init钩子函数net/ipv4/Tcp_ipv4.c:tcp_v4_init_sock(),它主要是对tcp_sock和inet_connection_sock进行一些初始化;

8、socket与文件系统关联:
回到net/Socket.c:sys_socket()函数:
asmlinkage long sys_socket(int family, int type, int protocol)
{
	int retval;
	struct socket *sock;

	retval = sock_create(family, type, protocol, &sock);
	if (retval < 0)
		goto out;

	retval = sock_map_fd(sock);
	if (retval < 0)
		goto out_release;

out:
	/* It may be already another descriptor 8) Not kernel problem. */
	return retval;

out_release:
	sock_release(sock);
	return retval;
}
创建好与socket相关的结构后,需要与文件系统关联,详见sock_map_fd()函数:
1) 申请文件描述符,并分配file结构和目录项结构;
2) 关联socket相关的文件操作函数表和目录项操作函数表;
3) 将file->private_date指向socket;

socket与文件系统关联后,以后便可以通过文件系统read/write对socket进行操作了;

小结:
1、socket库函数通过内核创建socket,并初始化其状态为TCP_CLOSE;
2、创建完后,与文件系统关联,其文件一般位于/proc/$pid/fd/目录下;
3、应用程序可以通过文件对socket进行操作;
分享到:
评论

相关推荐

    Linux内核协议栈的详解完整版

    详解Linux协议栈的数据流向,SOCKET的操作流程,unicast multicast等等的区别。

    linux-1.2.13 网络协议栈源码

    在Linux内核中,网络协议栈是负责处理网络数据传输的关键部分,它实现了TCP/IP协议族的各个层次,包括链路层、网络层、传输层以及应用层。 1. 链路层:在这个层次,主要涉及的是以太网协议,如Ethernet和ARP(地址...

    linux内核协议栈源码解析(2.6.18内核)

    《Linux内核协议栈源码解析(2.6.18内核)》是一本针对Linux内核网络协议栈深入解析的重要参考资料,尤其适合那些希望深入理解Linux内核以及网络通信机制的IT专业人士。该书详细阐述了Linux 2.6.18版本内核中的网络...

    Linux网络体系结构 Linux内核中网络协议的设计与实现

    Linux内核通过socket API为上层应用提供了与网络协议栈交互的接口。 在设计与实现方面,Linux内核的网络协议栈采用了模块化和层次化的结构,使得代码易于维护和扩展。例如,协议处理函数可以通过注册和注销机制动态...

    linux-2.6.18内核基础上分析网络协议栈,适合初学者看

    4. **缓冲区管理**:网络协议栈中,数据包在内存中的存储和传输依赖于sk_buff(socket buffer)结构体。sk_buff用于在协议栈各层之间传递数据,并维护了关于数据包的元信息。 5. **网络设备驱动**:驱动程序是硬件...

    linux内核协议栈分析

    Linux内核协议栈是Linux操作系统中负责处理网络数据包传输的核心组件。...通过文档的阅读,可以为研究和开发人员提供参考,帮助他们理解网络数据包在网络协议栈中的处理流程以及在Linux内核中的具体实现。

    Linux内核1.2.13网络协议栈初始化及源码剖析

    主要涵盖了Socket编程基础知识和Linux内核网络协议栈的工作方式,其中包括协议实现模块和网络设备驱动的初始化过程;探讨了数据链路层的功能,以及客户端、服务器的简单Socket程序和多线程并发模型的设计与注意事项...

    《linux内核网络栈源代码情景分析》.(曹桂平).[PDF].&ckook;.pdf.zip

    《Linux内核网络栈源代码情景分析》是曹桂平撰写的一本深入解析Linux内核网络处理机制的著作。这本书详细介绍了Linux操作系统如何处理网络数据包,从硬件接口到高层协议栈的每一个环节,帮助读者理解Linux网络内核的...

    基于Linux网络协议栈的嵌入式开发

    3. **集成到Linux内核中**:将VSP协议栈作为模块加载到Linux内核中,确保它与现有的网络协议栈兼容并行。 4. **测试与优化**:进行详尽的测试以确保新协议栈的稳定性和性能,根据测试结果进行必要的调整和优化。 ##...

    linux-网络协议栈流程.pdf

    Linux内核中的网络驱动负责与物理网络设备交互,接收网络帧并将其传递给上层的网络协议栈。这一过程涉及中断处理和DMA(Direct Memory Access)等技术,以确保数据能高效地从网络设备传输到内存中。 接着,数据包在...

    Linux内核 tcp ip协议栈源码分析

    在Linux内核中,TCP/IP协议栈的各个组件通过sk_buff(socket buffer)结构进行交互。这是一个高效的数据结构,用于存储网络数据并传递到不同层次。在`net/core/skbuff.c`中,你可以看到关于sk_buff的详细操作。 4....

    深入分析linux tcp/ip协议栈

    4. **应用层**:应用层是协议栈的最高层,与各种网络应用程序接口。常见的应用层协议有HTTP、FTP、SMTP等。在Linux中,这些协议通常由用户空间的库实现,如libcurl、libssl等,但内核也提供了诸如socket接口供应用...

    linux网络协议栈完全实现

    在这个主题中,我们将深入探讨Linux内核中的网络协议栈实现,包括TCP/IP协议族的主要组件和工作流程。 首先,我们要理解TCP/IP协议族是一个四层模型,包括应用层、传输层、网络层和数据链路层。在Linux中,这些层...

    Linux内核TCP-IP协议栈分析.rar

    Linux内核中的TCP/IP协议栈是操作系统的心脏,负责处理所有网络通信。它是一套复杂的软件,用于实现互联网协议族,使得Linux系统能够与其他设备进行数据传输。在本资料"Linux内核TCP/IP协议栈分析"中,我们将深入...

    linux TCP IP协议栈源码解析

    - `net/`目录下包含所有网络协议栈的源代码,如`tcp.c`处理TCP协议,`ipv4/`处理IPv4。 - `socket`层是用户空间与内核空间通信的接口,通过系统调用如`socket()`、`bind()`、`connect()`等实现。 - `sk_buff`...

    LINUX-1.2.13内核网络栈实现.pdf

    本书主要对Linux 1.2.13内核协议栈的全部源代码做了详细的分析,该版本所有代码都在一个文件夹中,每种协议的实现都只有一个文件与之对应,分析该版本源代码可以方便读者迅速掌握Linux网络协议结构。 本书共分为5个...

    linux内核协议栈源码分析

    Linux内核协议栈是操作系统核心的一部分,负责...通过深入研究Linux内核协议栈源码,不仅可以提升对网络协议的理解,还能为开发高效、稳定的网络应用提供理论支持。同时,这也有助于解决网络问题,提高系统的整体性能。

    linux 内核精髓-精通linux内核必会的75个绝技

    6. **网络编程**:涵盖网络协议栈,从网络接口层到应用层,包括TCP/IP协议、套接字编程、网络服务的实现,以及socket选项和错误处理。 7. **系统调用与内核接口**:解析系统调用的原理,讲解如何利用strace等工具...

    linux内核图解-linux内核图解

    - 网络堆栈:负责网络数据的传输,包括TCP/IP协议栈、socket接口等,实现了网络通信功能。 2. 进程管理 在Linux中,进程是程序的执行实例。内核通过调度器进行进程的调度,根据不同的策略分配CPU时间。Linux还支持...

Global site tag (gtag.js) - Google Analytics