用户使用socket系统调用编写应用程序时,通过一个数字来表示一个socket,所有的操作都在该数字上进行,这个数字称为套接字描述符。在系统调用 的实现函数里,这个数字就会被映射成一个表示socket的结构体,该结构体保存了该socket的所有属性和数据。在内核的协议中实现中,关于表示 socket的结构体,是一个比较复杂的东西,下面一一介绍。 
    struct socket。 
    这是一个基本的BSD socket,我们调用socket系统调用创建的各种不同类型的socket,开始创建的都是它,到后面,各种不同类型的socket在它的基础上进行 各种扩展。struct socket是在虚拟文件系统上被创建出来的,可以把它看成一个文件,是可以被安全地扩展的。下面是其完整定义:

  1. struct socket {
  2. socket_state            state;
  3. unsigned long           flags;
  4. const struct proto_ops *ops;
  5. struct fasync_struct    *fasync_list;
  6. struct file             *file;
  7. struct sock             *sk;
  8. wait_queue_head_t       wait;
  9. short                   type;
  10. };

state用于表示socket所处的状态,是一个枚举变量,其类型定义如下:

  1. typedef enum {
  2. SS_FREE = 0,            //该socket还未分配
  3. SS_UNCONNECTED,         //未连向任何socket
  4. SS_CONNECTING,          //正在连接过程中
  5. SS_CONNECTED,           //已连向一个socket
  6. SS_DISCONNECTING        //正在断开连接的过程中
  7. }socket_state;

该成员只对TCP socket有用,因为只有tcp是面向连接的协议,udp跟raw不需要维护socket状态。 
    flags是一组标志位,在内核中并没有发现被使用。 
    ops是协议相关的一组操作集,结构体struct proto_ops的定义如下:

  1. struct proto_ops {
  2. int     family;
  3. struct module   *owner;
  4. int (*release)(struct socket *sock);
  5. int (*bind)(struct socket *sock, struct sockaddr *myaddr, int sockaddr_len);
  6. int (*connect)(struct socket *sock, struct sockaddr *vaddr, int sockaddr_len, int flags);
  7. int (*socketpair)(struct socket *sock1, struct socket *sock2);
  8. int (*accept)(struct socket *sock,struct socket *newsock, int flags);
  9. int (*getname)(struct socket *sock, struct sockaddr *addr,int *sockaddr_len, int peer);
  10. unsigned int (*poll)(struct file *file, struct socket *sock,
  11. struct poll_table_struct *wait);
  12. int (*ioctl)(struct socket *sock, unsigned int cmd, unsigned long arg);
  13. int (*listen)(struct socket *sock, int len);
  14. int (*shutdown)(struct socket *sock, int flags);
  15. int (*setsockopt)(struct socket *sock, int level,
  16. int optname, char __user *optval, int optlen);
  17. int (*getsockopt)(struct socket *sock, int level,
  18. int optname, char __user *optval, int __user *optlen);
  19. int (*sendmsg)(struct kiocb *iocb, struct socket *sock,
  20. struct msghdr *m, size_t total_len);
  21. int (*recvmsg)(struct kiocb *iocb, struct socket *sock,
  22. struct msghdr *m, size_t total_len, int flags);
  23. int (*mmap)(struct file *file, struct socket *sock,struct vm_area_struct * vma);
  24. ssize_t (*sendpage)(struct socket *sock, struct page *page,
  25. int offset, size_t size, int flags);
  26. };

协议栈中总共定义了三个strcut proto_ops类型的变量,分别是myinet_stream_ops, myinet_dgram_ops, myinet_sockraw_ops,对应流协议, 数据报和原始套接口协议的操作函数集。 
    type是socket的类型,对应的取值如下:

  1. enum sock_type {
  2. SOCK_DGRAM = 1,
  3. SOCK_STREAM = 2,
  4. SOCK_RAW    = 3,
  5. SOCK_RDM    = 4,
  6. SOCK_SEQPACKET = 5,
  7. SOCK_DCCP   = 6,
  8. SOCK_PACKET = 10,
  9. };

sk是网络层对于socket的表示,结构体struct sock比较庞大,这里不详细列出,只介绍一些重要的成员, 
    sk_prot和sk_prot_creator,这两个成员指向特定的协议处理函数集,其类型是结构体struct proto,该结构体也是跟struct proto_ops相似的一组协议操作函数集。这两者之间的概念似乎有些混淆,可以这么理解,struct proto_ops的成员操作struct socket层次上的数据,处理完了,再由它们调用成员sk->sk_prot的函数,操作struct sock层次上的数据。即它们之间存在着层次上的差异。struct proto类型的变量在协议栈中总共也有三个,分别是mytcp_prot,myudp_prot,myraw_prot,对应TCP, UDP和RAW协议。 
    sk_state表示socket当前的连接状态,是一个比struct socket的state更为精细的状态,其可能的取值如下:

  1. enum {
  2. TCP_ESTABLISHED = 1,
  3. TCP_SYN_SENT,
  4. TCP_SYN_RECV,
  5. TCP_FIN_WAIT1,
  6. TCP_FIN_WAIT2,
  7. TCP_TIME_WAIT,
  8. TCP_CLOSE,
  9. TCP_CLOSE_WAIT,
  10. TCP_LAST_ACK,
  11. TCP_LISTEN,
  12. TCP_CLOSING,
  13. TCP_MAX_STATES
  14. ;

这些取值从名字上看,似乎只使用于TCP协议,但事实上,UDP和RAW也借用了其中一些值,在一个socket创建之初,其取值都是 TCP_CLOSE,一个UDP socket connect完成后,将这个值改为TCP_ESTABLISHED,最后,关闭sockt前置回TCP_CLOSE,RAW也一样。 
    sk_rcvbuf和sk_sndbuf分别表示接收和发送缓冲区的大小。sk_receive_queue和sk_write_queue分别为接收缓 冲队列和发送缓冲队列,队列里排列的是套接字缓冲区struct sk_buff,队列中的struct sk_buff的字节数总和不能超过缓冲区大小的设定。

接着上一篇,继续介绍struct sock。 
    sk_rmem_alloc, sk_wmem_alloc和sk_omem_alloc分别表示接收缓冲队列,发送缓冲队列及其它缓冲队列中已经分配的字节数,用于跟踪缓冲区的使用情况。 
    struct sock有一个struct sock_common成员,因为struct inet_timewait_sock也要用到它,所以把它单独归到一个结构体中,其定义如下:

  1. struct sock_common {
  2. unsigned short      skc_family;
  3. volatile unsigned char skc_state;
  4. unsigned char       skc_reuse;
  5. int         skc_bound_dev_if;
  6. struct hlist_node   skc_node;
  7. struct hlist_node   skc_bind_node;
  8. atomic_t        skc_refcnt;
  9. unsigned int        skc_hash;
  10. struct proto        *skc_prot;
  11. };

struct inet_sock。 
    这是INET域专用的一个socket表示,它是在struct sock的基础上进行的扩展,在基本socket的属性已具备的基础上,struct inet_sock提供了INET域专有的一些属性,比如TTL,组播列表,IP地址,端口等,下面是其完整定义:

  1. struct inet_sock {
  2. struct sock     sk;
  3. #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
  4. struct ipv6_pinfo   *pinet6;
  5. #endif
  6. __u32           daddr;          //IPv4的目的地址。
  7. __u32           rcv_saddr;      //IPv4的本地接收地址。
  8. __u16           dport;          //目的端口。
  9. __u16           num;            //本地端口(主机字节序)。
  10. __u32           saddr;          //发送地址。
  11. __s16           uc_ttl;         //单播的ttl。
  12. __u16           cmsg_flags;
  13. struct ip_options   *opt;
  14. __u16           sport;          //源端口。
  15. __u16           id;             //单调递增的一个值,用于赋给iphdr的id域。
  16. __u8            tos;            //服务类型。
  17. __u8            mc_ttl;         //组播的ttl
  18. __u8            pmtudisc;
  19. __u8            recverr:1,
  20. is_icsk:1,
  21. freebind:1,
  22. hdrincl:1,      //是否自己构建ip首部(用于raw协议)
  23. mc_loop:1;      //组播是否发向回路。
  24. int             mc_index;       //组播使用的本地设备接口的索引。
  25. __u32           mc_addr;        //组播源地址。
  26. struct ip_mc_socklist   *mc_list;   //组播组列表。
  27. struct {
  28. unsigned int        flags;
  29. unsigned int        fragsize;
  30. struct ip_options   *opt;
  31. struct rtable       *rt;
  32. int                 length;
  33. u32                 addr;
  34. struct flowi        fl;
  35. } cork;
  36. };

struct raw_sock 
    这是RAW协议专用的一个socket的表示,它是在struct inet_sock基础上的扩展,因为RAW协议要处理ICMP协议的过滤设置,其定义如下:

  1. struct raw_sock {
  2. struct inet_sock   inet;
  3. struct icmp_filter filter;
  4. };

struct udp_sock 
    这是UDP协议专用的一个socket表示,它是在struct inet_sock基础上的扩展,其定义如下:

  1. struct udp_sock {
  2. struct inet_sock inet;
  3. int             pending;
  4. unsigned int    corkflag;
  5. __u16           encap_type;
  6. __u16           len;
  7. };

struct inet_connection_sock 
    看完上面两个,我们觉得第三个应该就是struct tcp_sock了,但事实上,struct tcp_sock并不直接从struct inet_sock上扩展,而是从struct inet_connection_sock基础上进行扩展,struct inet_connection_sock是所有面向连接的socket的表示,关于该socket,及下面所有tcp相关的socket,我们在分析 tcp实现时再详细介绍,这里只列出它们的关系。

strcut tcp_sock 
    这是TCP协议专用的一个socket表示,它是在struct inet_connection_sock基础进行扩展,主要是增加了滑动窗口协议,避免拥塞算法等一些TCP专有属性。

struct inet_timewait_sock

struct tcp_timewait_sock 
    在struct inet_timewait_sock的基础上进行扩展。

struct inet_request_sock

struct tcp_request_sock 
    在struct inet_request_sock的基础上进行扩展。 

struct socket 结构详解的更多相关文章

  1. struct socket结构体详解

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://weiguozhihui.blog.51cto.com/3060615/15852 ...

  2. socket原理详解

    1.什么是socket 我们知道进程通信的方法有管道.命名管道.信号.消息队列.共享内存.信号量,这些方法都要求通信的两个进程位于同一个主机.但是如果通信双方不在同一个主机又该如何进行通信呢?在计算机 ...

  3. windows socket函数详解

    windows socket函数详解 近期一直用第三方库写网络编程,反倒是遗忘了网络编程最底层的知识.因而产生了整理Winsock函数库的想法.以下知识点均来源于MSDN,本人只做翻译工作.虽然很多前 ...

  4. PHP扩展代码结构详解

    PHP扩展代码结构详解: 这个是继:使用ext_skel和phpize构建php5扩展  内容 (拆分出来) Zend_API:深入_PHP_内核:http://cn2.php.net/manual/ ...

  5. c/c++ socket函数详解

    c/c++ socket函数详解 注意: 使用socketAPI前,要先将相关链接库(Ws2_32.lib)加入链接,并使用WSAStartUp函数初始化.每个socket函数都可能失败(返回-1), ...

  6. Linux的SOCKET编程详解(转)

    Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系 ...

  7. 常用socket函数详解

    常用socket函数详解 关于socket函数,每个的意义和基本功能都知道,但每次使用都会去百度,参数到底是什么,返回值代表什么意义,就是说用的少,也记得不够精确.每次都查半天,经常烦恼于此.索性都弄 ...

  8. 【ARM-Linux开发】Linux的SOCKET编程详解

    Linux的SOCKET编程详解 1. 网络中进程之间如何通信 进 程通信的概念最初来源于单机系统.由于每个进程都在自己的地址范围内运行,为保证两个相互通信的进 程之间既互不干扰又协调一致工作,操作系 ...

  9. Socket 死连接详解

    Socket 死连接详解 当使用 Socket 进行通信时,由于各种不同的因素,都有可能导致死连接停留在服务器端,假如服务端需要处理的连接较多,就有可能造成服务器资源严重浪费,对此,本文将阐述其原理以 ...

随机推荐

  1. Boost配置

    =================================版权声明================================= 版权声明:本文为博主原创文章 未经许可不得转载  请通过右 ...

  2. DOS命令批量重命名文件配合Excel 操作备忘

    批量取得文件夹下文件名 有时候文件夹下有好多图片什么的,文件名称不是统一的格式,想统一一下,于是google找到以下方法,进入要操作的目录,按住shift键的同时,单击鼠标右键,你会看到在此处打开命令 ...

  3. linux下如何打包压缩?解包解压?.tar文件.gz文件

    ===文件打包.压缩 ==打包 tar [root@521478.com]# tar -cvf etc1.tar /etc //c创建 v详细 f打包后文件名 [root@521478.com]# t ...

  4. CCommandManager 类

    CCommandManager类 CCommandManager 类管理命令及其与图像的关联.描述CCommandManager :: CleanUp从命令列表和全局和用户映射中删除所有元素.CCom ...

  5. 初涉Linux ----------> 打造自己的 Vim IDE

    一.  开篇前言 (图片显示越界的话,请刷新) 装好Ubuntu15.04系统之后呢,玩了玩 Ubuntu,感觉还是很不错的.比windows快,一开机就可以打开你想要的程序,但是在windows下你 ...

  6. Windows Azure 虚拟机备份

    如果我们要在Windows Azure的虚拟机上进行一些“重要且高危”的操作,我们通常会想到使用快照或者备份功能.但是在Windows Azure上是没有虚拟机快照功能的,尽管我们可以对虚拟机的磁盘文 ...

  7. JDK环境变量详细讲解

    首先,你应该已经安装了 java 的 JDK 了,笔者安装的是:jdk-8u65-windows-x64 下载地址: http://www.oracle.com/technetwork/java/ja ...

  8. POJ3013 Big Christmas Tree[转换 最短路]

    Big Christmas Tree Time Limit: 3000MS   Memory Limit: 131072K Total Submissions: 23387   Accepted: 5 ...

  9. jsp的九大内置对象和四大作用域

    定义:可以不加声明就在JSP页面脚本(Java程序片和Java表达式)中使用的成员变量? JSP共有以下9种基本内置组件(可与ASP的6种内部组件相对应):? 1.request对象(作用域)? 客户 ...

  10. Android的4种文件类型Java,class,dex,apk

    Java文件-----应用程序源文件 Android本身相当一部分都是用java编写而成(基本上架构图里头蓝色的部份都是用Java开发的),android的应用必须使用java来开发 Class文件- ...