Chinaunix首页 | 论坛 | 博客
  • 博客访问: 183164
  • 博文数量: 67
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 622
  • 用 户 组: 普通用户
  • 注册时间: 2014-11-19 19:12
文章分类

全部博文(67)

分类: C/C++

2014-11-19 19:34:11

转载自http://blog.chinaunix.net/uid-13746440-id-3547287.html

socket是用户API与网络协议栈之间的一个中间接口层,用户通过调用socket api将报文传给协议栈,或者从协议栈读取报文。
对于用户来说,socket就是一个打开的文件,linux内核中为socket定义了sockfs文件类型:
static struct file_system_type sock_fs_type = {
.name =  "sockfs",
.get_sb = sockfs_get_sb,
.kill_sb = kill_anon_super,
};
在sock_init中调用sock_fs_type的注册,文件系统存在后,创建socket,实际上是在sockfs文件系统中创建一个文件节点(inode),并建立struct inode和struct socket结构。
struct socket_alloc {
struct socket socket;
struct inode vfs_inode;
};
内核中实现了socket_alloc结构,将socket和vfs_inode封装在一起,这样通过vfs_inode和socket都可以互相找到对方,同时又保证了inode的独立性,适用于各种文件类型。
在sock_init中首先调用register_filesystem将sock_fs_type挂载全局的file_system链表上,然后调用vfs_kern_mount挂载该文件系统,这个过程会把sock文件系统的一些函
数操作集与超极块关联起来,这样当创建inode节点时,实际上最终使用的是sock文件系统提供的相关函数,这里不细述了,最终会一下申请处一个socket_alloc结构,同时
存在socket和vfs_inode。
接着看看通过task_struct怎么找到socket
current->file->fd_array[fd],fd是文件描述符,不能超过NR_OPEN_DEFAULT(32),通过fd找到file结构,这个结构中包含了目录项f_dentry,而f_dentry中包含了inode,
f_dentry通过inode刚好可以找到socket,这样通过进程描述符就找到了socket了。
下面看看具体的几个关键数据结构:
/**
*  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; // 未分配、未连接、正连接、已连接、断连接,只对TCP生效s
short   type; // socket类型,如SOCK_DGRAM=1,SOCK_STREAM=2,SOCKET_RAW=3

unsigned long  flags; // 无使用
struct fasync_struct *fasync_list;
wait_queue_head_t wait;

struct file  *file;
struct sock  *sk; // 网络层sock的表示,这个是重点,整个协议栈都是围绕这个成员展开
const struct proto_ops *ops; // 操作集,分别对应流协议、数据报和原始套接口协议
};
这样通过文件描述符,可以找到中间层socket,通过socket可以找到网络层的sock,进而操作数据,收发包,这样就展开了。
sock的结构比较复杂,单独进行分析,下面主要讲socket、sock、tcp sock、inet_connection_sock、inet socket等的关系理一下
1. 通过fd可以找到socket,socket->sk指向了struct sock结构
2. struct sock->sk_socket指向了BSD socket,这样socket和sock可以轻松的互相查询
3. 数据报文在tcp入口,通过ip、端口等信息查询到struct sock信息
4. 如果是tcp协议,tcp_sock = struct tcp_sock *tp = tcp_sk(sk);可以强制转换,看一下这几个结构
struct tcp_sock {
/* inet_connection_sock has to be the first member of tcp_sock */
struct inet_connection_sock inet_conn;
......
struct udp_sock {
    /* inet_sock has to be the first member */
    struct inet_sock inet;
......
struct inet_connection_sock {
/* inet_sock has to be the first member! */
struct inet_sock   icsk_inet;
......
struct inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct sock  sk;
......
inet_sock是INET域专用的一个sock表示,在struct sock上扩展而来,除基本sock属性,提供了INET域专用的属性,如TTL、IP地址、端口等
inet_connection_sock是所有面向连接的协议的socket的相关信息,第一个域是inet_sock,可以方便转换
tcp_sock是tcp协议的专用socket表示,在inet_connection_sock基础上扩展,主要增加了滑动窗口协议、拥塞控制算法等TCP专有属性
udp_sock第一个域也是inet_socket,包括一些加密相关的信息接口,暂时不分析

阅读(2675) | 评论(0) | 转发(0) |
0

上一篇:auto extern static const

下一篇:iptables

给主人留下些什么吧!~~