`
simohayha
  • 浏览: 1386247 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

linux内核中socket的实现

阅读更多
首先来看整个与socket相关的操作提供了一个统一的接口sys_socketcall.

下面就是它的代码片段:

asmlinkage long sys_socketcall(int call, unsigned long __user *args)
{
	unsigned long a[6];
	unsigned long a0, a1;
	int err;
..........................................

	a0 = a[0];
	a1 = a[1];

	switch (call) {
	case SYS_SOCKET:
		err = sys_socket(a0, a1, a[2]);
		break;
	case SYS_BIND:
		err = sys_bind(a0, (struct sockaddr __user *)a1, a[2]);
		break;
	case SYS_CONNECT:
		err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
		break;
	case SYS_LISTEN:
		err = sys_listen(a0, a1);
		break;
	case SYS_ACCEPT:
		err =
		    do_accept(a0, (struct sockaddr __user *)a1,
			      (int __user *)a[2], 0);
		break;
	case SYS_GETSOCKNAME:
		err =
		    sys_getsockname(a0, (struct sockaddr __user *)a1,
				    (int __user *)a[2]);
		break;
.....................................
	return err;
}


可以看到代码比较简单,就是通过传递进来的call类型,来调用相应的socket相关的函数.

这里你可能注意到了,那就是一般文件句柄相关的操作,比如write,read,aio,poll这些并没有看到(也就是file_operations).这是因为socket上面其实还有一层vfs层,内核把socket当做一个文件系统来处理,并实现了相应的vfs方法.因此下面我们先来了解下vfs.然后会描述下进程如何通过vfs存取句柄.

vfs其实就相当于对下层的文件系统和上层应用之间的粘合层,它定义了文件系统需要实现的相关的操作,然后下层的文件系统只需要实现这些方法就可以了,也就是说在内核其他部分和上层应用看来,所有的文件系统没有任何区别.

下面的这张图就是从用户空间调用write的大体流程:



vfs中有4种主要的数据结构:

1 超级块对象,代表一个已安装的文件系统.super_block

2 索引节点对象,代表一个文件.inode

3 目录项对象,代表一个目录项.dentry

4 文件对象,表示一个被进程打开的文件.file

其中每种对象都包含一个操作对象.依次为super_operations,inode_operations,dentry_operations以及file_operations.各自操作不同的层次.然后我们的文件系统只需要实现这些方法,然后注册到内核就可以了.

接下来我们来看和vfs相应的结构:

第一个就是file_system_type结构,这个结构表示了一个文件系统:
struct file_system_type {
	const char *name;
	int fs_flags;
///最关键的函数,得到文件系统的超级块.
	int (*get_sb) (struct file_system_type *, int,
		       const char *, void *, struct vfsmount *);
	void (*kill_sb) (struct super_block *);
...........................................
};


然后是vfsmount结构,它表示了一个安装点,换句话说也就是一个文件系统实例.

第三个是files_struct结构,它主要是为每个进程来维护它所打开的句柄.这里只需要注意一个就是fd_array和fstable中的fd的区别.当进程数比较少也就是小于NR_OPEN_DEFAULT(32)时,句柄就会存放在fd_array中,而当句柄数超过32则就会重新分配数组,然后将fd指针指向它(然后我们通过fd就可以取得相应的file结构).

而且files_struct是每个进程只有一个的.

struct files_struct {
  /*
   * read mostly part
   */
	atomic_t count;
	struct fdtable *fdt;
	struct fdtable fdtab;
  /*
   * written part on a separate cache line in SMP
   */
	spinlock_t file_lock ____cacheline_aligned_in_smp;
	int next_fd;
	struct embedded_fd_set close_on_exec_init;
	struct embedded_fd_set open_fds_init;
///所打开的所有文件
	struct file * fd_array[NR_OPEN_DEFAULT];
};


struct fdtable {
	unsigned int max_fds;
	struct file ** fd;      /* current fd array */
	fd_set *close_on_exec;
	fd_set *open_fds;
	struct rcu_head rcu;
	struct fdtable *next;
};



还有两个一个是fs_struct,一个是namespace也都是进程相关的.这里就不一一介绍了.

我这里vfs介绍只是个大概,需要详细了解的,可以去看ulk的vfs相关章节和linux内核设计与实现的相关章节.

因此下面的图表示了进程和socket的关系:




上面的这张图有些老了,新的内核中的inode节点中已经没有u这个联合体了,对应的是会有一个包含socket和inode的一个结构体,然后我们通过inode,而inode中专门有个i_mode域来判断相应的inode类型,比如socket就是 S_IFSOCK.就可以直接计算出相应的socket的地址,然后就可以存取socket了.后面我们会介绍.

内核中标售socket有两个数据结构,一个是socket,另一个是sock,其中socket是一个general BSD socket, 它也就是应用程序和4层协议之间的一个接口,屏蔽掉了相关的4层协议部分.而在内核中,socket所需要使用的相关的4层协议的信息全部是保存在sock结构当中的,而socket和sock这两个结构都有保存对方的指针,因此可以很容易的存取对方.

还有一个就是ops域,这个域保存了所有的相关的4层协议的操作函数..

而在sock中有一个sk_common保存了一个skc_prot域,这个域保存的是相应的协议簇的操作函数的集合.


后面介绍到socket创建的时候,我们会分析proto_ops和proto的区别.其实proto相当于对proto_ops的一层封装,最终会在proto中调用proto_ops.



/**
 *  struct socket - general BSD socket
 *  @state: socket state (%SS_CONNECTED, etc)
 *  @type: socket type (%SOCK_STREAM, etc)
 *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
 *  @ops: protocol specific socket operations
 *  @fasync_list: Asynchronous wake up list
 *  @file: File back pointer for gc
 *  @sk: internal networking protocol agnostic socket representation
 *  @wait: wait queue for several uses
 */
struct socket {
	socket_state		state;
	short			type;
	unsigned long		flags;
	const struct proto_ops	*ops;
	struct fasync_struct	*fasync_list;
	struct file		*file;
	struct sock		*sk;
	wait_queue_head_t	wait;
};

struct sock_common {
	unsigned short		skc_family;
	volatile unsigned char	skc_state;
	unsigned char		skc_reuse;
	int			skc_bound_dev_if;
	struct hlist_node	skc_node;
	struct hlist_node	skc_bind_node;
	atomic_t		skc_refcnt;
	unsigned int		skc_hash;
	struct proto		*skc_prot;
#ifdef CONFIG_NET_NS
	struct net	 	*skc_net;
#endif
};

struct proto_ops {
	int		family;
	struct module	*owner;
	int		(*release)   (struct socket *sock);
	int		(*bind)	     (struct socket *sock,
				      struct sockaddr *myaddr,
				      int sockaddr_len);
	int		(*connect)   (struct socket *sock,
				      struct sockaddr *vaddr,
				      int sockaddr_len, int flags);
...................................................
};




然后我们来看sock_init的实现,在这个函数中,将socket注册为一个伪文件系统,并安装相应的mount点:


///相应的mount对象
static struct vfsmount *sock_mnt __read_mostly;
///文件系统对象.
static struct file_system_type sock_fs_type = {
	.name =		"sockfs",
	.get_sb =	sockfs_get_sb,
	.kill_sb =	kill_anon_super,
};

static int __init sock_init(void)
{
	/*
	 *      Initialize sock SLAB cache.
	 */

	sk_init();

	/*
	 *      Initialize skbuff SLAB cache
	 */
	skb_init();

///初始化一个inodecache.
	init_inodecache();
///注册文件系统到内核.
	register_filesystem(&sock_fs_type);
///安装mount点.
	sock_mnt = kern_mount(&sock_fs_type);

#ifdef CONFIG_NETFILTER
	netfilter_init();
#endif
	return 0;
}



我们知道每次创建一个socket,都是要依赖于当前的protocol family类型的(后面会分析sys_socket的源码的时候会看到).而在内核中,每种类型的protocol family都会有一个相对应的net_proto_family结构,然后将这个结构注册到内核的net_families数组中,这样我们创建socket的时候,就可以调用这个数组来创建socket.


我们先来看sock_register的源码,也就是如何将一个net_proto_family注册到相应的数组:


static const struct net_proto_family *net_families[NPROTO] __read_mostly;

int sock_register(const struct net_proto_family *ops)
{
	int err;

	if (ops->family >= NPROTO) {
		printk(KERN_CRIT "protocol %d >= NPROTO(%d)\n", ops->family,
		       NPROTO);
		return -ENOBUFS;
	}

	spin_lock(&net_family_lock);
///代码非常简单,就是根据类型,然后放到相应的位置.
	if (net_families[ops->family])
		err = -EEXIST;
	else {
		net_families[ops->family] = ops;
		err = 0;
	}
	spin_unlock(&net_family_lock);

	printk(KERN_INFO "NET: Registered protocol family %d\n", ops->family);
	return err;
}



我们知道每个协议簇和相应的套接口都对应有好多种组合,因此在协议簇的实现中保存了一个相应的结构来保存这些组合,然后后面就首先通过family然后确定到某个结构,再根据套接口的类型来得到这个结构,并赋值给sock.

这里要注意我们只分析af_inet的实现,其他的协议簇都差不多:


我们来看这个的实现:


///可以看到这是一个数组,每个元素都是一个链表,也就是每种类型的socket就是一个链表.而这个链表所包含的是不同4层协议的inetsw.可是在inet中,现在每种类型的socket只对应一个4层协议.这里只是为了以后扩展.
static struct list_head inetsw[SOCK_MAX];

///相应的socket的对应的信息的结构.
struct inet_protosw {
	struct list_head list;

///需要这两个key才能定位一个inet_protosw.
	unsigned short	 type;	   /* This is the 2nd argument to socket(2). */
	unsigned short	 protocol; /* This is the L4 protocol number.  */

///相应的基于ipv4的4层协议的操作集合.
	struct proto	 *prot;
///相应的协议簇的操作信息.
	const struct proto_ops *ops;
  
	int              capability; /* Which (if any) capability do
				      * we need to use this socket
				      * interface?
                                      */
	char             no_check;   /* checksum on rcv/xmit/none? */
	unsigned char	 flags;      /* See INET_PROTOSW_* below.  */
};

void inet_register_protosw(struct inet_protosw *p)
{
	struct list_head *lh;
	struct inet_protosw *answer;
	int protocol = p->protocol;
	struct list_head *last_perm;
.............................................
	answer = NULL;
	last_perm = &inetsw[p->type];
///这个操作也很简单,就是将inet_protosw根据套接口类型插入到全局链表数组.
	list_for_each(lh, &inetsw[p->type]) {
		answer = list_entry(lh, struct inet_protosw, list);

		/* Check only the non-wild match. */
		if (INET_PROTOSW_PERMANENT & answer->flags) {
			if (protocol == answer->protocol)
				break;
			last_perm = lh;
		}

		answer = NULL;
	}
	if (answer)
		goto out_permanent;
///插入链表.
	list_add_rcu(&p->list, last_perm);
..............................



接下来来分析inet_init的源码.

///表示了所有的可能的当前协议簇和套接口类型的组合.
static struct inet_protosw inetsw_array[] =
{
	{
		.type =       SOCK_STREAM,
		.protocol =   IPPROTO_TCP,
		.prot =       &tcp_prot,
		.ops =        &inet_stream_ops,
		.capability = -1,
		.no_check =   0,
		.flags =      INET_PROTOSW_PERMANENT |
			      INET_PROTOSW_ICSK,
	},

	{
		.type =       SOCK_DGRAM,
		.protocol =   IPPROTO_UDP,
		.prot =       &udp_prot,
		.ops =        &inet_dgram_ops,
		.capability = -1,
		.no_check =   UDP_CSUM_DEFAULT,
		.flags =      INET_PROTOSW_PERMANENT,
       },


       {
	       .type =       SOCK_RAW,
	       .protocol =   IPPROTO_IP,	/* wild card */
	       .prot =       &raw_prot,
	       .ops =        &inet_sockraw_ops,
	       .capability = CAP_NET_RAW,
	       .no_check =   UDP_CSUM_DEFAULT,
	       .flags =      INET_PROTOSW_REUSE,
       }
};

///协议簇的创建函数.
static struct net_proto_family inet_family_ops = {
	.family = PF_INET,
	.create = inet_create,
	.owner	= THIS_MODULE,
};

static int __init inet_init(void)
{
.............................................

///注册相应的proto到全局链表中.
	rc = proto_register(&tcp_prot, 1);
	if (rc)
		goto out;

	rc = proto_register(&udp_prot, 1);
	if (rc)
		goto out_unregister_tcp_proto;

	rc = proto_register(&raw_prot, 1);
	if (rc)
		goto out_unregister_udp_proto;

///注册协议簇的操作函数(后面socket创建的时候会用到).
	(void)sock_register(&inet_family_ops);

.............................................
	/* Register the socket-side information for inet_create. */
	for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)
		INIT_LIST_HEAD(r);

///将inetsw_array插入到相应的数组链表.
	for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q)
		inet_register_protosw(q);
...........................................

}



接下来我们来通过分析创建socket的函数sys_socket,来更加好的理解socket的实现.


asmlinkage long sys_socket(int family, int type, int protocol)
{
...............................................
///主要是两个函数,一个是创建socket
	retval = sock_create(family, type, protocol, &sock);
	if (retval < 0)
		goto out;
///这个是相应的文件系统的操作.
	retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
....................................
}


sock_create的具体流程我们就不分析了,我们只需要知道最终他会通过传递进来的family的值,来取得相应的family中注册的creat函数.然后会调用这个函数来完成socket的创建.而在上面的代码分析中,我们知道在af_inet中,注册的create函数是inet_create函数,因此我们来看这个函数的实现:



static int inet_create(struct net *net, struct socket *sock, int protocol)
{
	struct sock *sk;
	struct inet_protosw *answer;
	struct inet_sock *inet;
	struct proto *answer_prot;
	unsigned char answer_flags;
	char answer_no_check;
	int try_loading_module = 0;
	int err;
...........................................................
///首先给socket状态赋值.

	sock->state = SS_UNCONNECTED;

	/* Look for the requested type/protocol pair. */
lookup_protocol:
	err = -ESOCKTNOSUPPORT;
	rcu_read_lock();
///通过type和protocl的值,来查找到相应的inet_protosw结构.
	list_for_each_entry_rcu(answer, &inetsw[sock->type], list) {

		err = 0;
		/* 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;
	}

	..........................................

///开始给socket赋值.这里我们可以看到最终socket的ops域所得到的值就是相应的协议簇的操作集合(比如inet_stream_ops这些)..
	sock->ops = answer->ops;
	answer_prot = answer->prot;
	answer_no_check = answer->no_check;
	answer_flags = answer->flags;
	rcu_read_unlock();

	WARN_ON(answer_prot->slab == NULL);

	err = -ENOBUFS;
///alloc一个sock结构,其中将刚才取得的inet_protosw中的pro 域赋值给sock的sk_prot域和sk_prot_creator.以及family域也被相应的赋值.
	sk = sk_alloc(net, PF_INET, GFP_KERNEL, answer_prot);
	if (sk == NULL)
		goto out;
....................................................................

///这个函数中会初始化相应的socket中的写队列,读队列以及错误队列.并将sk指针和sock连接起来.而且还将初始化相应的定时器.

	sock_init_data(sock, sk);
..........................................
///调用相应的初始化.

	if (sk->sk_prot->init) {
///其实也就是相对应4层协议的初始化函数,它会初始化一些协议相关的东西.
		err = sk->sk_prot->init(sk);
		if (err)
			sk_common_release(sk);
	}
out:
	return err;
out_rcu_unlock:
	rcu_read_unlock();
	goto out;
}



这里举个例子,来看一下tcp_v4_init_sock的实现,也就是tcp的初始化函数.

static int tcp_v4_init_sock(struct sock *sk)
{
	struct inet_connection_sock *icsk = inet_csk(sk);
	struct tcp_sock *tp = tcp_sk(sk);

	skb_queue_head_init(&tp->out_of_order_queue);
///初始化定时器,也就是tcp的那3个定时器,write,delay以及keepalive定时器.
	tcp_init_xmit_timers(sk);
	tcp_prequeue_init(tp);
...................................
///状态赋值.初始状态.
	sk->sk_state = TCP_CLOSE;

..................................

	return 0;
}


上面我们看到有两个新的结构inet_connection_sock以及tcp_sock.我们接下来就来看这两个结构.

inet_connection_sock也就是所有面向连接的协议的socket的相关信息.它的第一个域是inet_sock,因此我们可以很方便的进行转换.而tcp_sock 相当与inet_connection_sock得一个子类,保存有所有tcp相关的socket的信息.它的第一个域就是inet_connection_sock.

可以看到其实tcp_socket类似于inet_sock(前面的blog有介绍),都是保存了本层的相关的信息.

这里就不列出这两个结构了,内核中这两个结构的注释都是很详细的..



在看sock_map_fd实现之前,我们先来看内核中socket类型的inode节点的实现:

这里看到,我们只要拥有了inode节点,通过containof宏我们就可以计算出socket的地址,从而就可以得到整个socket的信息了.
struct socket_alloc {
	struct socket socket;
	struct inode vfs_inode;
};



而inode节点的赋值是在sock_alloc中实现的,而这个函数是在__sock_create中被调用的,也就是在init_cteate被调用之前.

static struct socket *sock_alloc(void)
{
	struct inode *inode;
	struct socket *sock;

///新建一个inode,sock_mnt就是sock_init中被安装的mount点.
	inode = new_inode(sock_mnt->mnt_sb);
	if (!inode)
		return NULL;
///然后组合inode和socket结构.
	sock = SOCKET_I(inode);
///设置inode类型.
	inode->i_mode = S_IFSOCK | S_IRWXUGO;
	inode->i_uid = current->fsuid;
	inode->i_gid = current->fsgid;
///将sockets_in_use(也就是当前创建的socket)加一.
	get_cpu_var(sockets_in_use)++;
	put_cpu_var(sockets_in_use);
	return sock;
}


然后我们来看sock_map_fd的实现.我们首先要知道,socket是没有open函数的,因此要通过vfs层的调用,必须要在create的时候,映射一个file结构,从而将句柄与这个file关联起来.

int sock_map_fd(struct socket *sock, int flags)
{
	struct file *newfile;
///找到一个可用的fd,并找到一个可用的file结构并返回.
	int fd = sock_alloc_fd(&newfile, flags);

	if (likely(fd >= 0)) {
///初始化这个file结构.
		int err = sock_attach_fd(sock, newfile, flags);

		if (unlikely(err < 0)) {
			put_filp(newfile);
			put_unused_fd(fd);
			return err;
		}
///将句柄和文件指针关联起来.
		fd_install(fd, newfile);
	}
	return fd;
}

sock_alloc_fd实现比较简单,这里就不分析了.


就来看下sock_attach_fd的实现.:


这里要注意,内核通过把socket指针赋值给file的private_data,这样就可以通过句柄,在fdtable中得到file对象,然后轻松取得socket对象.

///目录项的操作集合
static struct dentry_operations sockfs_dentry_operations = {
	.d_delete = sockfs_delete_dentry,
	.d_dname  = sockfs_dname,
};
///文件的操作集合.这些函数最终调用的还是socket的ops域中的函数.而我们上面已经提过最终他们调用sock域的proto中的函数.
static const struct file_operations socket_file_ops = {
	.owner =	THIS_MODULE,
	.llseek =	no_llseek,
	.aio_read =	sock_aio_read,
	.aio_write =	sock_aio_write,
	.poll =		sock_poll,
	.unlocked_ioctl = sock_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl = compat_sock_ioctl,
#endif
	.mmap =		sock_mmap,
	.open =		sock_no_open,	/* special open code to disallow open via /proc */
	.release =	sock_close,
	.fasync =	sock_fasync,
	.sendpage =	sock_sendpage,
	.splice_write = generic_splice_sendpage,
	.splice_read =	sock_splice_read,
};

static int sock_attach_fd(struct socket *sock, struct file *file, int flags)
{
	struct dentry *dentry;
	struct qstr name = { .name = "" };
///根据装载点的mnt_sb(super block)的root域来创建一个目录项.
	dentry = d_alloc(sock_mnt->mnt_sb->s_root, &name);
	if (unlikely(!dentry))
		return -ENOMEM;
///将sockfs的目录项操作集合赋值.
	dentry->d_op = &sockfs_dentry_operations;
	/*
	 * We dont want to push this dentry into global dentry hash table.
	 * We pretend dentry is already hashed, by unsetting DCACHE_UNHASHED
	 * This permits a working /proc/$pid/fd/XXX on sockets
	 */
	dentry->d_flags &= ~DCACHE_UNHASHED;
///将inode和目录项关联起来.
	d_instantiate(dentry, SOCK_INODE(sock));

	sock->file = file;
///初始化文件对象,主要就是将socket_file_ops赋值给file结构的f_op域.
	init_file(file, sock_mnt, dentry, FMODE_READ | FMODE_WRITE,
		  &socket_file_ops);
	SOCK_INODE(sock)->i_fop = &socket_file_ops;
	file->f_flags = O_RDWR | (flags & O_NONBLOCK);
	file->f_pos = 0;
///将sock赋值给private_data,这样我们就能通过file轻松获得socket结构(在后面会用到).
	file->private_data = sock;

	return 0;
}



下面就是sys_socket的流程图:





最终来总结一下.内核中,socket是作为一个伪文件系统来实现的,它在初始化时注册到内核,而每个进程的files_struct域保存了所有的句柄,包括socket的.一般的文件操作的话,内核直接调用vfs层的方法,然后会自动调用socket实现的相关方法.内核通过inode结构的imode域就可以知道当前的句柄所关联的是不是socket类型,这时遇到socket独有的操作,就通过containof方法,来计算出socket的地址,从而就可以进行相关的操作.


最后我们要注意的是,内核在调用相关操作都是直接调用socket的ops域,然后在ops域中调用相应的sock结构体中的sock_common域的skc_prot的操作集中的相对应的函数.

举个例子,假设现在我们使用tcp协议然后调用bind方法,内核会先调用sys_bind方法:

asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
................................................
			if (!err)
				err = sock->ops->bind(sock,
						      (struct sockaddr *)
						      &address, addrlen);
...................................................
}


可以看到它调用的是ops域的bind方法.而这时我们的ops域是inet_stream_ops,来看它的bind方法:

int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
..............................................

	/* If the socket has its own bind function then use it. (RAW) */
	if (sk->sk_prot->bind) {
		err = sk->sk_prot->bind(sk, uaddr, addr_len);
		goto out;
	}
................................................
}

它最终调用的是sock结构的sk_prot域(也就是sock_common的skc_prot域)的bind方法,而此时我们的skc_prot的值是tcp_prot,因此最终会调用tcp_prot的bind方法.

下面就是示意图:



PS:随便抱怨下,linux kernel的socket实现也太复杂了..不知道其他的操作系统的socket实现的怎么样..


  • 大小: 21.3 KB
  • 大小: 29.4 KB
  • 大小: 55.6 KB
  • 大小: 39.3 KB
1
0
分享到:
评论
4 楼 luyc 2010-08-27  
luyc 写道

我也想知道

找到了,是《TCP/IP ARCHITECTURE, DESIGN, AND IMPLEMENTATION IN LINUX》
3 楼 luyc 2010-08-24  
sunzixun 写道
哥们,你好

你最后一张图 3.4 是来自哪一本书啊。谢谢

我也想知道
2 楼 sunzixun 2010-08-20  
哥们,你好

你最后一张图 3.4 是来自哪一本书啊。谢谢
1 楼 mryufeng 2009-08-31  
bsd的更复杂

相关推荐

    linux内核中sock和socket数据结构

    详细分析了linux内核中sock和socket数据结构的含义

    linux 内核socket相关数据结构介绍

    文章详细介绍了linux 内核中有关socket 相关知识的数据结构介绍。一共有41个重要数据结构。数据结构中关键字段都有中文注释,并标明该字段在linux 内核中的作用及用法。要理解清楚linux 内核源码逻辑,数据结构的...

    Linux内核源代码情景分析 (上下册 高清非扫描 )

    1.4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户堆栈的扩展 2.6 ...

    linux 内核socket的创建与初始化

    文章详细介绍了linux 内核中有关socket 的创建与初始化。文章中各个函数调用关系清晰,重要代码逻辑都有中文注释及中文旁白解释。是一篇很好的学习linux 内核网络子系统的文章。

    深入分析Linux内核源码.chm

    1.3走进Linux内核 1.4 分析Linux内核的意义 1.5 Linux内核结构 1.6 Linux内核源代码 1.7 Linux内核源代码分析工具 第二章 Linux运行的硬件基础 2.1 i386的寄存器 2.2 内存地址 2.3 段机制和描述符 2.4 分页机制 2.5 ...

    Linux内核网络栈源代码情景分析

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

    linux 内核 socket相关的协议栈初始化

    文章详细介绍了linux 内核中有关socket 相关的协议栈的初始化部分。文章中各个函数调用关系清晰,重要代码逻辑都有中文注释及中文旁白解释。是一篇很好的学习linux 内核网络子系统的文章。

    linux内核中sock和socket数据结构可用.pdf

    linux内核中sock和socket数据结构可用.pdf

    Linux内核网络栈源代码情景分析.pdf

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

    Linux 内核中listen系统调用

    这段代码是 Linux 内核中负责设置 socket 监听状态的 C 函数。 首先定义了一个内核函数 __sys_listen,这个函数是设置 socket 进入监听状态的实际实现。它接受两个参数:`fd` 和 backlog。`fd` 是文件描述符,代表一...

    Linux内核 内容很全

    处理器 115 10.1 X86 115 10.2 ARM 115 10.3 Alpha AXP处理器 115 第11章 Linux内核源代码 117 11.1 怎样得到Linux内核源码 117 11.2 内核源码的编排 117 11.3 从何处看起 118 第12章 Linux...

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

    本书主要对Linux 1.2.13内核协议栈的全部源代码做了详细的分析,该版本所有代码都在一个文件夹中,每种协议的实现都只有一个文件与之对应,分析该版本源代码可以...本书适合Linux网络开发人员及Linux内核爱好者阅读。

    基于LINUX内核中的TCPIP的核心过程分析

    在我的博客中的- 如何从实践引领进入linux内核类别日志中我详细分析了Unix的socket的创建、发送、接收、关闭的过程,这节开始进入探讨IPV4的TCP的socket的创建,我们在linux/unix的socket从实践到内核分析部分 ...

    SocketTool(很好用的socket测试工具)

    SocketTool(很好用的socket测试工具)

    深入分析Linux内核源码

    1.5.1 Linux内核在整个操系统中的位置 1.5.2 Linux内核的作用 1.5.3 Linux内核的抽象结构 1.6 Linux内核源代码 1.6.1 多版本的内核源代码 1.6.2 Linux内核源代码的结构 1.6.3 从何处开始阅读源代码 ...

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

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

    linux内核skb处理流程图

    权威人士根据linux内核进行图解,很全对skb的处理,有arp、ip、等多种报文,还有socket等,很全,很实用

    cpp-高性能的内核Socket实现Fastsocket

    Fastsocket 是一个高扩展性的 Socket 以及 Linux 内核的底层网络实现。可以在多核机器上提供极好的性能,此外使用和维护还非常简单

    linux 内核源代码分析

    1. 4 Linux内核源代码中的C语言代码 1.5 Linux内核源代码中的汇编语言代码 第2章 存储管理 2.1 Linux内存管理的基本框架 2.2 地址映射的全过程 2.3 几个重要的数据结构和函数 2.4 越界访问 2.5 用户...

    Linux编程--Linux内核

    Linux内核 前言 第1章 硬件基础与软件基础 6 1.1 硬件基础 6 1.1.1 CPU 7 1.1.2 存储器 8 1.1.3 总线 8 1.1.4 控制器和外设 8 1.1.5 地址空间 9 1.1.6 时钟 9 1.2 软件基础 9 1.2.1 计算机语言 9 1.2.2 什么是操作...

Global site tag (gtag.js) - Google Analytics