Linux内核中协议族有INET协议族,UNIX协议族等,我们还是以INET协议族为例。

下面是内核中的协议族声明:

[cpp] view plaincopy
  1. /* Supported address families. */
  2. #define AF_UNSPEC   0
  3. #define AF_UNIX     1   /* Unix domain sockets      */
  4. #define AF_LOCAL    1   /* POSIX name for AF_UNIX   */
  5. #define AF_INET     2   /* Internet IP Protocol     */
  6. #define AF_AX25     3   /* Amateur Radio AX.25      */
  7. #define AF_IPX      4   /* Novell IPX           */
  8. #define AF_APPLETALK    5   /* AppleTalk DDP        */
  9. #define AF_NETROM   6   /* Amateur Radio NET/ROM    */
  10. #define AF_BRIDGE   7   /* Multiprotocol bridge     */
  11. #define AF_ATMPVC   8   /* ATM PVCs         */
  12. #define AF_X25      9   /* Reserved for X.25 project    */
  13. #define AF_INET6    10  /* IP version 6         */
  14. #define AF_ROSE     11  /* Amateur Radio X.25 PLP   */
  15. #define AF_DECnet   12  /* Reserved for DECnet project  */
  16. #define AF_NETBEUI  13  /* Reserved for 802.2LLC project*/
  17. #define AF_SECURITY 14  /* Security callback pseudo AF */
  18. #define AF_KEY      15      /* PF_KEY key management API */
  19. #define AF_NETLINK  16
  20. #define AF_ROUTE    AF_NETLINK /* Alias to emulate 4.4BSD */
  21. #define AF_PACKET   17  /* Packet family        */
  22. #define AF_ASH      18  /* Ash              */
  23. #define AF_ECONET   19  /* Acorn Econet         */
  24. #define AF_ATMSVC   20  /* ATM SVCs         */
  25. #define AF_RDS      21  /* RDS sockets          */
  26. #define AF_SNA      22  /* Linux SNA Project (nutters!) */
  27. #define AF_IRDA     23  /* IRDA sockets         */
  28. #define AF_PPPOX    24  /* PPPoX sockets        */
  29. #define AF_WANPIPE  25  /* Wanpipe API Sockets */
  30. #define AF_LLC      26  /* Linux LLC            */
  31. #define AF_CAN      29  /* Controller Area Network      */
  32. #define AF_TIPC     30  /* TIPC sockets         */
  33. #define AF_BLUETOOTH    31  /* Bluetooth sockets        */
  34. #define AF_IUCV     32  /* IUCV sockets         */
  35. #define AF_RXRPC    33  /* RxRPC sockets        */
  36. #define AF_ISDN     34  /* mISDN sockets        */
  37. #define AF_PHONET   35  /* Phonet sockets       */
  38. #define AF_IEEE802154   36  /* IEEE802154 sockets       */
  39. #define AF_CAIF     37  /* CAIF sockets         */
  40. #define AF_ALG      38  /* Algorithm sockets        */
  41. #define AF_NFC      39  /* NFC sockets          */
  42. #define AF_MAX      40  /* For now.. */

内核中的PF_***和AF_***其实可以混用,它的宏定义如下:

[cpp] view plaincopy
  1. /* Protocol families, same as address families. */
  2. #define PF_UNSPEC   AF_UNSPEC
  3. #define PF_UNIX     AF_UNIX
  4. #define PF_LOCAL    AF_LOCAL
  5. #define PF_INET     AF_INET
  6. #define PF_AX25     AF_AX25
  7. #define PF_IPX      AF_IPX
  8. #define PF_APPLETALK    AF_APPLETALK
  9. #define PF_NETROM   AF_NETROM
  10. #define PF_BRIDGE   AF_BRIDGE
  11. #define PF_ATMPVC   AF_ATMPVC
  12. #define PF_X25      AF_X25
  13. #define PF_INET6    AF_INET6
  14. #define PF_ROSE     AF_ROSE
  15. #define PF_DECnet   AF_DECnet
  16. #define PF_NETBEUI  AF_NETBEUI
  17. #define PF_SECURITY AF_SECURITY
  18. #define PF_KEY      AF_KEY
  19. #define PF_NETLINK  AF_NETLINK
  20. #define PF_ROUTE    AF_ROUTE
  21. #define PF_PACKET   AF_PACKET
  22. #define PF_ASH      AF_ASH
  23. #define PF_ECONET   AF_ECONET
  24. #define PF_ATMSVC   AF_ATMSVC
  25. #define PF_RDS      AF_RDS
  26. #define PF_SNA      AF_SNA
  27. #define PF_IRDA     AF_IRDA
  28. #define PF_PPPOX    AF_PPPOX
  29. #define PF_WANPIPE  AF_WANPIPE
  30. #define PF_LLC      AF_LLC
  31. #define PF_CAN      AF_CAN
  32. #define PF_TIPC     AF_TIPC
  33. #define PF_BLUETOOTH    AF_BLUETOOTH
  34. #define PF_IUCV     AF_IUCV
  35. #define PF_RXRPC    AF_RXRPC
  36. #define PF_ISDN     AF_ISDN
  37. #define PF_PHONET   AF_PHONET
  38. #define PF_IEEE802154   AF_IEEE802154
  39. #define PF_CAIF     AF_CAIF
  40. #define PF_ALG      AF_ALG
  41. #define PF_NFC      AF_NFC
  42. #define PF_MAX      AF_MAX

以后的分析就是以INET协议族为例来分析的。

下面的结构体就是在系统初始化时用来管理协议族初始化的结构体:

[cpp] view plaincopy
  1. struct net_proto_family {
  2. int     family;
  3. int     (*create)(struct net *net, struct socket *sock,
  4. int protocol, int kern);
  5. struct module   *owner;
  6. };

第一个属性就是协议族的宏定义,如PF_INET;

第二个属性就是协议族对应的初始化函数指针;

INET协议族对应该结构的定义如下:

[cpp] view plaincopy
  1. static const struct net_proto_family inet_family_ops = {
  2. .family = PF_INET,
  3. .create = inet_create,
  4. .owner  = THIS_MODULE,
  5. };

下面结构体是协议族操作集结构体定义:

[cpp] view plaincopy
  1. struct proto_ops {
  2. int     family;
  3. struct module   *owner;
  4. int     (*release)   (struct socket *sock);
  5. int     (*bind)      (struct socket *sock,
  6. struct sockaddr *myaddr,
  7. int sockaddr_len);
  8. int     (*connect)   (struct socket *sock,
  9. struct sockaddr *vaddr,
  10. int sockaddr_len, int flags);
  11. int     (*socketpair)(struct socket *sock1,
  12. struct socket *sock2);
  13. int     (*accept)    (struct socket *sock,
  14. struct socket *newsock, int flags);
  15. int     (*getname)   (struct socket *sock,
  16. struct sockaddr *addr,
  17. int *sockaddr_len, int peer);
  18. unsigned int    (*poll)      (struct file *file, struct socket *sock,
  19. struct poll_table_struct *wait);
  20. int     (*ioctl)     (struct socket *sock, unsigned int cmd,
  21. unsigned long arg);
  22. #ifdef CONFIG_COMPAT
  23. int     (*compat_ioctl) (struct socket *sock, unsigned int cmd,
  24. unsigned long arg);
  25. #endif
  26. int     (*listen)    (struct socket *sock, int len);
  27. int     (*shutdown)  (struct socket *sock, int flags);
  28. int     (*setsockopt)(struct socket *sock, int level,
  29. int optname, char __user *optval, unsigned int optlen);
  30. int     (*getsockopt)(struct socket *sock, int level,
  31. int optname, char __user *optval, int __user *optlen);
  32. #ifdef CONFIG_COMPAT
  33. int     (*compat_setsockopt)(struct socket *sock, int level,
  34. int optname, char __user *optval, unsigned int optlen);
  35. int     (*compat_getsockopt)(struct socket *sock, int level,
  36. int optname, char __user *optval, int __user *optlen);
  37. #endif
  38. int     (*sendmsg)   (struct kiocb *iocb, struct socket *sock,
  39. struct msghdr *m, size_t total_len);
  40. int     (*recvmsg)   (struct kiocb *iocb, struct socket *sock,
  41. struct msghdr *m, size_t total_len,
  42. int flags);
  43. int     (*mmap)      (struct file *file, struct socket *sock,
  44. struct vm_area_struct * vma);
  45. ssize_t     (*sendpage)  (struct socket *sock, struct page *page,
  46. int offset, size_t size, int flags);
  47. ssize_t     (*splice_read)(struct socket *sock,  loff_t *ppos,
  48. struct pipe_inode_info *pipe, size_t len, unsigned int flags);
  49. };

INET协议族中TCP和UDP协议对应的上述操作集的定义不同:

TCP协议z在INET层操作集inet_stream_ops

[cpp] view plaincopy
  1. const struct proto_ops inet_stream_ops = {
  2. .family        = PF_INET,
  3. .owner         = THIS_MODULE,
  4. .release       = inet_release,
  5. .bind          = inet_bind,
  6. .connect       = inet_stream_connect,
  7. .socketpair    = sock_no_socketpair,
  8. .accept        = inet_accept,
  9. .getname       = inet_getname,
  10. .poll          = tcp_poll,
  11. .ioctl         = inet_ioctl,
  12. .listen        = inet_listen,
  13. .shutdown      = inet_shutdown,
  14. .setsockopt    = sock_common_setsockopt,
  15. .getsockopt    = sock_common_getsockopt,
  16. .sendmsg       = inet_sendmsg,
  17. .recvmsg       = inet_recvmsg,
  18. .mmap          = sock_no_mmap,
  19. .sendpage      = inet_sendpage,
  20. .splice_read       = tcp_splice_read,
  21. #ifdef CONFIG_COMPAT
  22. .compat_setsockopt = compat_sock_common_setsockopt,
  23. .compat_getsockopt = compat_sock_common_getsockopt,
  24. .compat_ioctl      = inet_compat_ioctl,
  25. #endif
  26. };

UDP协议在INET层操作集inet_dgram_ops

[cpp] view plaincopy
  1. const struct proto_ops inet_dgram_ops = {
  2. .family        = PF_INET,
  3. .owner         = THIS_MODULE,
  4. .release       = inet_release,
  5. .bind          = inet_bind,
  6. .connect       = inet_dgram_connect,
  7. .socketpair    = sock_no_socketpair,
  8. .accept        = sock_no_accept,
  9. .getname       = inet_getname,
  10. .poll          = udp_poll,
  11. .ioctl         = inet_ioctl,
  12. .listen        = sock_no_listen,
  13. .shutdown      = inet_shutdown,
  14. .setsockopt    = sock_common_setsockopt,
  15. .getsockopt    = sock_common_getsockopt,
  16. .sendmsg       = inet_sendmsg,
  17. .recvmsg       = inet_recvmsg,
  18. .mmap          = sock_no_mmap,
  19. .sendpage      = inet_sendpage,
  20. #ifdef CONFIG_COMPAT
  21. .compat_setsockopt = compat_sock_common_setsockopt,
  22. .compat_getsockopt = compat_sock_common_getsockopt,
  23. .compat_ioctl      = inet_compat_ioctl,
  24. #endif
  25. };

上面两个操作集是属于INET协议族层次,可以由协议族层套接字socket来管理,下面是协议族层析的套接字结构体(BSD Socket)定义:

[cpp] view plaincopy
  1. /**
  2. *  struct socket - general BSD socket
  3. *  @state: socket state (%SS_CONNECTED, etc)
  4. *  @type: socket type (%SOCK_STREAM, etc)
  5. *  @flags: socket flags (%SOCK_ASYNC_NOSPACE, etc)
  6. *  @ops: protocol specific socket operations
  7. *  @file: File back pointer for gc
  8. *  @sk: internal networking protocol agnostic socket representation
  9. *  @wq: wait queue for several uses
  10. */
  11. struct socket {
  12. socket_state        state;
  13. kmemcheck_bitfield_begin(type);
  14. short           type;
  15. kmemcheck_bitfield_end(type);
  16. unsigned long       flags;
  17. struct socket_wq __rcu  *wq;
  18. struct file     *file;
  19. struct sock     *sk;
  20. const struct proto_ops  *ops;
  21. };

最后一个属性就指向了上面所述的操作集。若使用TCP协议,ops就是inet_stream_ops,若是UDP协议,ops就是inet_dgram_ops。

short type属性的取值可以是如下值:

[cpp] view plaincopy
  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. };

传输层的协议操作集结构体定义:

[cpp] view plaincopy
  1. struct proto {
  2. void            (*close)(struct sock *sk,
  3. long timeout);
  4. int         (*connect)(struct sock *sk,
  5. struct sockaddr *uaddr,
  6. int addr_len);
  7. int         (*disconnect)(struct sock *sk, int flags);
  8. struct sock *       (*accept) (struct sock *sk, int flags, int *err);
  9. int         (*ioctl)(struct sock *sk, int cmd,
  10. unsigned long arg);
  11. int         (*init)(struct sock *sk);
  12. void            (*destroy)(struct sock *sk);
  13. void            (*shutdown)(struct sock *sk, int how);
  14. int         (*setsockopt)(struct sock *sk, int level,
  15. int optname, char __user *optval,
  16. unsigned int optlen);
  17. int         (*getsockopt)(struct sock *sk, int level,
  18. int optname, char __user *optval,
  19. int __user *option);
  20. #ifdef CONFIG_COMPAT
  21. int         (*compat_setsockopt)(struct sock *sk,
  22. int level,
  23. int optname, char __user *optval,
  24. unsigned int optlen);
  25. int         (*compat_getsockopt)(struct sock *sk,
  26. int level,
  27. int optname, char __user *optval,
  28. int __user *option);
  29. int         (*compat_ioctl)(struct sock *sk,
  30. unsigned int cmd, unsigned long arg);
  31. #endif
  32. int         (*sendmsg)(struct kiocb *iocb, struct sock *sk,
  33. struct msghdr *msg, size_t len);
  34. int         (*recvmsg)(struct kiocb *iocb, struct sock *sk,
  35. struct msghdr *msg,
  36. size_t len, int noblock, int flags,
  37. int *addr_len);
  38. int         (*sendpage)(struct sock *sk, struct page *page,
  39. int offset, size_t size, int flags);
  40. int         (*bind)(struct sock *sk,
  41. struct sockaddr *uaddr, int addr_len);
  42. int         (*backlog_rcv) (struct sock *sk,
  43. struct sk_buff *skb);
  44. /* Keeping track of sk's, looking them up, and port selection methods. */
  45. void            (*hash)(struct sock *sk);
  46. void            (*unhash)(struct sock *sk);
  47. void            (*rehash)(struct sock *sk);
  48. int         (*get_port)(struct sock *sk, unsigned short snum);
  49. void            (*clear_sk)(struct sock *sk, int size);
  50. /* Keeping track of sockets in use */
  51. #ifdef CONFIG_PROC_FS
  52. unsigned int        inuse_idx;
  53. #endif
  54. /* Memory pressure */
  55. void            (*enter_memory_pressure)(struct sock *sk);
  56. atomic_long_t       *memory_allocated;  /* Current allocated memory. */
  57. struct percpu_counter   *sockets_allocated; /* Current number of sockets. */
  58. /*
  59. * Pressure flag: try to collapse.
  60. * Technical note: it is used by multiple contexts non atomically.
  61. * All the __sk_mem_schedule() is of this nature: accounting
  62. * is strict, actions are advisory and have some latency.
  63. */
  64. int         *memory_pressure;
  65. long            *sysctl_mem;
  66. int         *sysctl_wmem;
  67. int         *sysctl_rmem;
  68. int         max_header;
  69. bool            no_autobind;
  70. struct kmem_cache   *slab;
  71. unsigned int        obj_size;
  72. int         slab_flags;
  73. struct percpu_counter   *orphan_count;
  74. struct request_sock_ops *rsk_prot;
  75. struct timewait_sock_ops *twsk_prot;
  76. union {
  77. struct inet_hashinfo    *hashinfo;
  78. struct udp_table    *udp_table;
  79. struct raw_hashinfo *raw_hash;
  80. } h;
  81. struct module       *owner;
  82. char            name[32];
  83. struct list_head    node;
  84. #ifdef SOCK_REFCNT_DEBUG
  85. atomic_t        socks;
  86. #endif
  87. };

该结构体和proto_ops的区别是:该结构体和具体的传输层协议相关,其中的函数指针指向对应的协议的相应的操作函数。

TCP协议的操作集定义如下:

[cpp] view plaincopy
  1. struct proto tcp_prot = {
  2. .name           = "TCP",
  3. .owner          = THIS_MODULE,
  4. .close          = tcp_close,
  5. .connect        = tcp_v4_connect,
  6. .disconnect     = tcp_disconnect,
  7. .accept         = inet_csk_accept,
  8. .ioctl          = tcp_ioctl,
  9. .init           = tcp_v4_init_sock,
  10. .destroy        = tcp_v4_destroy_sock,
  11. .shutdown       = tcp_shutdown,
  12. .setsockopt     = tcp_setsockopt,
  13. .getsockopt     = tcp_getsockopt,
  14. .recvmsg        = tcp_recvmsg,
  15. .sendmsg        = tcp_sendmsg,
  16. .sendpage       = tcp_sendpage,
  17. .backlog_rcv        = tcp_v4_do_rcv,
  18. .hash           = inet_hash,
  19. .unhash         = inet_unhash,
  20. .get_port       = inet_csk_get_port,
  21. .enter_memory_pressure  = tcp_enter_memory_pressure,
  22. .sockets_allocated  = &tcp_sockets_allocated,
  23. .orphan_count       = &tcp_orphan_count,
  24. .memory_allocated   = &tcp_memory_allocated,
  25. .memory_pressure    = &tcp_memory_pressure,
  26. .sysctl_mem     = sysctl_tcp_mem,
  27. .sysctl_wmem        = sysctl_tcp_wmem,
  28. .sysctl_rmem        = sysctl_tcp_rmem,
  29. .max_header     = MAX_TCP_HEADER,
  30. .obj_size       = sizeof(struct tcp_sock),
  31. .slab_flags     = SLAB_DESTROY_BY_RCU,
  32. .twsk_prot      = &tcp_timewait_sock_ops,
  33. .rsk_prot       = &tcp_request_sock_ops,
  34. .h.hashinfo     = &tcp_hashinfo,
  35. .no_autobind        = true,
  36. #ifdef CONFIG_COMPAT
  37. .compat_setsockopt  = compat_tcp_setsockopt,
  38. .compat_getsockopt  = compat_tcp_getsockopt,
  39. #endif
  40. };

UDP协议的操作集则为:

[cpp] view plaincopy
  1. struct proto udp_prot = {
  2. .name          = "UDP",
  3. .owner         = THIS_MODULE,
  4. .close         = udp_lib_close,
  5. .connect       = ip4_datagram_connect,
  6. .disconnect    = udp_disconnect,
  7. .ioctl         = udp_ioctl,
  8. .destroy       = udp_destroy_sock,
  9. .setsockopt    = udp_setsockopt,
  10. .getsockopt    = udp_getsockopt,
  11. .sendmsg       = udp_sendmsg,
  12. .recvmsg       = udp_recvmsg,
  13. .sendpage      = udp_sendpage,
  14. .backlog_rcv       = __udp_queue_rcv_skb,
  15. .hash          = udp_lib_hash,
  16. .unhash        = udp_lib_unhash,
  17. .rehash        = udp_v4_rehash,
  18. .get_port      = udp_v4_get_port,
  19. .memory_allocated  = &udp_memory_allocated,
  20. .sysctl_mem    = sysctl_udp_mem,
  21. .sysctl_wmem       = &sysctl_udp_wmem_min,
  22. .sysctl_rmem       = &sysctl_udp_rmem_min,
  23. .obj_size      = sizeof(struct udp_sock),
  24. .slab_flags    = SLAB_DESTROY_BY_RCU,
  25. .h.udp_table       = &udp_table,
  26. #ifdef CONFIG_COMPAT
  27. .compat_setsockopt = compat_udp_setsockopt,
  28. .compat_getsockopt = compat_udp_getsockopt,
  29. #endif
  30. .clear_sk      = sk_prot_clear_portaddr_nulls,
  31. };

现在介绍struct socket结构体中一个属性struct sock类型的结构体指针,这个结构体就是传输层的套接字,所有套接字通过该结构来使用网络协议的所有服务。定义如下:

[cpp] view plaincopy
  1. struct sock {
  2. /*
  3. * Now struct inet_timewait_sock also uses sock_common, so please just
  4. * don't add nothing before this first member (__sk_common) --acme
  5. */
  6. struct sock_common  __sk_common;
  7. #define sk_node         __sk_common.skc_node
  8. #define sk_nulls_node       __sk_common.skc_nulls_node
  9. #define sk_refcnt       __sk_common.skc_refcnt
  10. #define sk_tx_queue_mapping __sk_common.skc_tx_queue_mapping
  11. #define sk_dontcopy_begin   __sk_common.skc_dontcopy_begin
  12. #define sk_dontcopy_end     __sk_common.skc_dontcopy_end
  13. #define sk_hash         __sk_common.skc_hash
  14. #define sk_family       __sk_common.skc_family
  15. #define sk_state        __sk_common.skc_state
  16. #define sk_reuse        __sk_common.skc_reuse
  17. #define sk_bound_dev_if     __sk_common.skc_bound_dev_if
  18. #define sk_bind_node        __sk_common.skc_bind_node
  19. #define sk_prot         __sk_common.skc_prot
  20. #define sk_net          __sk_common.skc_net
  21. socket_lock_t       sk_lock;
  22. struct sk_buff_head sk_receive_queue;
  23. /*
  24. * The backlog queue is special, it is always used with
  25. * the per-socket spinlock held and requires low latency
  26. * access. Therefore we special case it's implementation.
  27. * Note : rmem_alloc is in this structure to fill a hole
  28. * on 64bit arches, not because its logically part of
  29. * backlog.
  30. */
  31. struct {
  32. atomic_t    rmem_alloc;
  33. int     len;
  34. struct sk_buff  *head;
  35. struct sk_buff  *tail;
  36. } sk_backlog;
  37. #define sk_rmem_alloc sk_backlog.rmem_alloc
  38. int         sk_forward_alloc;
  39. #ifdef CONFIG_RPS
  40. __u32           sk_rxhash;
  41. #endif
  42. atomic_t        sk_drops;
  43. int         sk_rcvbuf;
  44. struct sk_filter __rcu  *sk_filter;
  45. struct socket_wq __rcu  *sk_wq;
  46. #ifdef CONFIG_NET_DMA
  47. struct sk_buff_head sk_async_wait_queue;
  48. #endif
  49. #ifdef CONFIG_XFRM
  50. struct xfrm_policy  *sk_policy[2];
  51. #endif
  52. unsigned long       sk_flags;
  53. struct dst_entry    *sk_dst_cache;
  54. spinlock_t      sk_dst_lock;
  55. atomic_t        sk_wmem_alloc;
  56. atomic_t        sk_omem_alloc;
  57. int         sk_sndbuf;
  58. struct sk_buff_head sk_write_queue;
  59. kmemcheck_bitfield_begin(flags);
  60. unsigned int        sk_shutdown  : 2,
  61. sk_no_check  : 2,
  62. sk_userlocks : 4,
  63. sk_protocol  : 8,
  64. sk_type      : 16;
  65. kmemcheck_bitfield_end(flags);
  66. int         sk_wmem_queued;
  67. gfp_t           sk_allocation;
  68. int         sk_route_caps;
  69. int         sk_route_nocaps;
  70. int         sk_gso_type;
  71. unsigned int        sk_gso_max_size;
  72. int         sk_rcvlowat;
  73. unsigned long           sk_lingertime;
  74. struct sk_buff_head sk_error_queue;
  75. struct proto        *sk_prot_creator;
  76. rwlock_t        sk_callback_lock;
  77. int         sk_err,
  78. sk_err_soft;
  79. unsigned short      sk_ack_backlog;
  80. unsigned short      sk_max_ack_backlog;
  81. __u32           sk_priority;
  82. struct pid      *sk_peer_pid;
  83. const struct cred   *sk_peer_cred;
  84. long            sk_rcvtimeo;
  85. long            sk_sndtimeo;
  86. void            *sk_protinfo;
  87. struct timer_list   sk_timer;
  88. ktime_t         sk_stamp;
  89. struct socket       *sk_socket;
  90. void            *sk_user_data;
  91. struct page     *sk_sndmsg_page;
  92. struct sk_buff      *sk_send_head;
  93. __u32           sk_sndmsg_off;
  94. int         sk_write_pending;
  95. #ifdef CONFIG_SECURITY
  96. void            *sk_security;
  97. #endif
  98. __u32           sk_mark;
  99. u32         sk_classid;
  100. void            (*sk_state_change)(struct sock *sk);
  101. void            (*sk_data_ready)(struct sock *sk, int bytes);
  102. void            (*sk_write_space)(struct sock *sk);
  103. void            (*sk_error_report)(struct sock *sk);
  104. int         (*sk_backlog_rcv)(struct sock *sk,
  105. struct sk_buff *skb);
  106. void                    (*sk_destruct)(struct sock *sk);
  107. };

若sk_family是PF_INET,则sk_type可以取值:SOCK_STREAM,SOCK_DGRAM,SOCK_RAW。其中sk_prot就是指向具体协议的操作集,如TCP协议就为tcp_prot。

若要将协议族操作集和具体协议操作集整合起来为IP协议提供接口,就需要下面的结构体定义:

[cpp] view plaincopy
  1. struct inet_protosw {
  2. struct list_head list;
  3. /* These two fields form the lookup key.  */
  4. unsigned short   type;     /* This is the 2nd argument to socket(2). */
  5. unsigned short   protocol; /* This is the L4 protocol number.  */
  6. struct proto     *prot;
  7. const struct proto_ops *ops;
  8. char             no_check;   /* checksum on rcv/xmit/none? */
  9. unsigned char    flags;      /* See INET_PROTOSW_* below.  */
  10. };

INET三种套接字定义的inetsw_array数组如下:

[cpp] view plaincopy
  1. static struct inet_protosw inetsw_array[] =
  2. {
  3. {
  4. .type =       SOCK_STREAM,
  5. .protocol =   IPPROTO_TCP,
  6. .prot =       &tcp_prot,
  7. .ops =        &inet_stream_ops,
  8. .no_check =   0,
  9. .flags =      INET_PROTOSW_PERMANENT |
  10. INET_PROTOSW_ICSK,
  11. },
  12. {
  13. .type =       SOCK_DGRAM,
  14. .protocol =   IPPROTO_UDP,
  15. .prot =       &udp_prot,
  16. .ops =        &inet_dgram_ops,
  17. .no_check =   UDP_CSUM_DEFAULT,
  18. .flags =      INET_PROTOSW_PERMANENT,
  19. },
  20. {
  21. .type =       SOCK_DGRAM,
  22. .protocol =   IPPROTO_ICMP,
  23. .prot =       &ping_prot,
  24. .ops =        &inet_dgram_ops,
  25. .no_check =   UDP_CSUM_DEFAULT,
  26. .flags =      INET_PROTOSW_REUSE,
  27. },
  28. {
  29. .type =       SOCK_RAW,
  30. .protocol =   IPPROTO_IP,    /* wild card */
  31. .prot =       &raw_prot,
  32. .ops =        &inet_sockraw_ops,
  33. .no_check =   UDP_CSUM_DEFAULT,
  34. .flags =      INET_PROTOSW_REUSE,
  35. }
  36. };

不过,在初始化的时候我们会将上面数组中的的元素按套接字类型插入inetsw链表数组中。其定义如下:

[cpp] view plaincopy
  1. static struct list_head inetsw[SOCK_MAX];

那内核中套接字struct socket、struct sock、struct inet_sock、struct tcp_sock、struct raw_sock、struct udp_sock、struct inet_connection_sock、struct inet_timewait_sock和struct tcp_timewait_sock的关系是怎样的呢?

*struct socket这个是BSD层的socket,应用程序会用过系统调用首先创建该类型套接字,它和具体协议无关。

*struct inet_sock是INET协议族使用的socket结构,可以看成位于INET层,是struct sock的一个扩展。它的第一个属性就是struct sock结构。

*struct sock是与具体传输层协议相关的套接字,所有内核的操作都基于这个套接字。

*struct tcp_sock是TCP协议的套接字表示,它是对struct inet_connection_sock的扩展,其第一个属性就是struct inet_connection_sock inet_conn。

*struct raw_sock是原始类型的套接字表示,ICMP协议就使用这种套接字,其是对struct sock的扩展。

*struct udp_sock是UDP协议套接字表示,其是对struct inet_sock套接字的扩展。

*struct inet_connetction_sock是所有面向连接协议的套接字,是对struct inet_sock套接字扩展。

后面两个是用于控制超时的套接字。

就拿struct inet_sock和struct sock为例来说明,为什么内核中可以直接将sock结构体首地址强制转换成inet_sock的首地址?并且inet_sock的大小要大于sock,直接进行如下强制转换

[cpp] view plaincopy
  1. inet = inet_sk(sk);
[cpp] view plaincopy
  1. static inline struct inet_sock *inet_sk(const struct sock *sk)
  2. {
  3. return (struct inet_sock *)sk;
  4. }

不会发生内存非法访问吗?!那就是在分配的时候并不只是分配的struct sock结构体大小的存储空间!

可以细看sock结构体分配的代码:

[cpp] view plaincopy
  1. struct sock *sk_alloc(struct net *net, int family, gfp_t priority,
  2. struct proto *prot)
  3. {
  4. struct sock *sk;
  5. sk = sk_prot_alloc(prot, priority | __GFP_ZERO, family);
  6. if (sk) {
  7. sk->sk_family = family;
  8. sk->sk_prot = sk->sk_prot_creator = prot;
  9. sock_lock_init(sk);
  10. sock_net_set(sk, get_net(net));
  11. atomic_set(&sk->sk_wmem_alloc, 1);
  12. sock_update_classid(sk);
  13. }
  14. return sk;
  15. }

紧接着调用sk_prot_alloc函数分配:

[cpp] view plaincopy
  1. static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,
  2. int family)
  3. {
  4. struct sock *sk;
  5. struct kmem_cache *slab;
  6. slab = prot->slab;
  7. if (slab != NULL) {
  8. sk = kmem_cache_alloc(slab, priority & ~__GFP_ZERO);
  9. ..............................
  10. } else
  11. sk = kmalloc(prot->obj_size, priority);
  12. .....................
  13. return sk;
  14. ......................
  15. }

上面的代码中首先判断高速缓存中是否可用,如果不可用,直接在内存分配空间,不过大小都是prot->obj_size。

如果是TCP协议中的tcp_prot中指明该属性的大小为.obj_size = sizeof(struct tcp_sock)。

所以,程序中给struct sock指针分配的不是该结构体的实际大小,而是大于其实际大小,以便其扩展套接字的属性占用。
以图例说明tcp_sock是如何从sock强制转换来的:

下篇将分析套接字的绑定、连接等一系列操作的实现。

下篇将分析套接字的操作函数。

网络协议栈深入分析(三)--BSD socket和传输层sock相关推荐

  1. 网络协议栈深入分析(四)--套接字内核初始化和创建过程

    1.系统初始化过程中会调用sock_init函数进行套接字的初始化,主要是进行缓存的初始化 [cpp] view plaincopy static int __init sock_init(void) ...

  2. [转]linux网络协议栈(1)——socket入门(1)(2)

    [转自 https://www.cnblogs.com/hustcat/archive/2009/09/17/1568738.html https://www.cnblogs.com/hustcat/ ...

  3. Linux内核网络协议栈4-创建socket(2)

    接上篇"创建socket" 一文: 5.分配sock结构: 本文中的例子会调用inet_family_ops.create方法即inet_create方法完成socket的创建工作 ...

  4. 【Linux系统与网络编程】15:Socket文件传输1

    Socket文件传输1 在socket多线程实现多客户端连接服务器进行聊天的基础上,添加文件传输功能. fix1 在server.c中添加file_info结构体,用于单独接受某次客户端发送的file ...

  5. 【Linux系统与网络编程】16:Socket文件传输2

    Socket文件传输2 OVERVIEW Socket文件传输2 在socket文件传输1中使用了一种在buff缓冲数组后添加\0的方式实现文件的传输. 实现方法2:根据TCP在数据传输过程中进行粘包 ...

  6. Linux内核网络协议栈3-创建socket(1)

    1.示例及函数入口: 1) 示例代码如下: C代码   int server_sockfd = socket(AF_INET, SOCK_STREAM, 0); 2) 入口: net/Socket.c ...

  7. 网络协议栈深入分析(五)--套接字的绑定、监听、连接和断开

    1.套接字的绑定 创建完套接字服务器端会在应用层使用bind函数进行套接字的绑定,这时会产生系统调用,sys_bind内核函数进行套接字. 系统调用函数的具体实现 [cpp] view plainco ...

  8. Linux内核--网络协议栈深入分析(一)--与sk_buff有关的几个重要的数据结构

    本文分析基于Linux Kernel 3.2.1 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7971463 更多请查看专栏htt ...

  9. Linux内核--网络协议栈深入分析(二)--sk_buff的操作函数

    本文分析基于Linux Kernel 3.2.1 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7972647 更多请查看网络栈分析 ...

最新文章

  1. HTTP Status 500 – Internal Server Error
  2. C++ Primer 5th笔记(chap 19 特殊工具与技术)局部类
  3. 【随手拍解救单身男女(1)】数据分析师书豪
  4. Windows + Eclipse + Gtk 环境(总结)
  5. [html] 谈谈你对input元素中readonly和disabled属性的理解
  6. Azkaban运行报错:我找到的几个错误问题
  7. nmap入门之主机发现
  8. 使用仿真软件查看机器人在一条直线上移动的 configuration
  9. php7 viewmodel,【初念科技】| php框架实例: Laravel之Model Observer模型
  10. Google 是如何做 Code Review 的?| 原力计划
  11. 视频编解码(十四):机顶盒调试编解码器显示总结
  12. centos npm install 超时报错
  13. 机器学习sklearn中决策树模型参数释义
  14. Conda更新失败:SSL错误:[SSL:CERTIFICATE_VERIFY_FAILED]证书验证失败
  15. Android studio实现财务记账系统软件android studio开发课程设计
  16. netstat 的10个基本用法
  17. 软件工程 - chapter02 - 敏捷开发
  18. VirtualBox成功安装Ubuntu18.04设置共享文件夹总结
  19. Springboot开启APR模式
  20. python bmp转jpg_python将bmp转换为jpg格式并删除原图的具体操作

热门文章

  1. 鸿蒙ACE框架-使用JS调用C++(1)
  2. 中移4G模块-ML302-OpenCpu开发-GPIO
  3. mysql page directory_【innodb】page directory的二分查找问题
  4. python sklearn 绘制决策树模型的节点图
  5. sr锁存器 数电_C06. SR锁存器的认识
  6. ctf 抓捕赵德汉_2017年网络空间安全技术大赛部分writeup
  7. JAVA中for循环缩制表位_用vim中的空格替换制表符
  8. 美国伯克利大学计算机研究生学几年,美国加州大学伯克利分校计算机CS研究生申请条件一览...
  9. codeblocks 调试
  10. 关于类模版迭代器提出时的错误