sock结构体是我们在网络编程中遇到的第一个庞大的结构体

struct sock {

  struct options      *opt;/*IP选项缓存于此处*/

  volatile unsigned long   wmem_alloc;/*当前写缓冲区大小,该值不可大于系统规定的最大值*/

  volatile unsigned long   rmem_alloc;/*当前读缓冲区大小,该值不可大于系统规定最大值*/

  unsigned long                 write_seq;/* write_seq 表示应用程序下一次写数据时所对应的第一个字节的序列号*/

  unsigned long                 sent_seq;/* sent_seq 表示本地将要发送的下一个数据包中第一个字节对应的序列号*/

  unsigned long                 acked_seq;/* acked_seq 表示本地希望从远端接收的下一个数据的序列号*/

   unsigned long                 copied_seq; /*  应用程序有待读取(但尚未读取)数据的第一个序列号。*/

  unsigned long                 rcv_ack_seq; /*  表示目前本地接收到的对本地发送数据的应答序列号。*/

   unsigned long                 window_seq;/* 窗口大小,是一个绝对值,表示本地将要发送数据包中所包含最后一个数据的序列号,不可大于 window_seq.*/

  unsigned long                 fin_seq; /*  该字段在对方发送 FIN数据包时使用,在接收到远端发送的 FIN数据包后,fin_seq 被初始化为对方的 FIN 数据包最后一个字节的序列号加 1,表示本地对此 FIN 数据包进行应答的序列号*/

   unsigned long                 urg_seq;

  unsigned long                 urg_data;

/*  以上两个字段用于紧急数据处理,urg_seq 表示紧急数据最大序列号。urg_data 是一个标志位,当设置为 1 时,表示接收到紧急数据。*/

  volatile char                 inuse,/*inuse=1 表示其它进程正在使用该 sock 结构,本进程需等待*/

                      dead,/* dead=1 表示该 sock 结构已处于释放状态*/

                      urginline,/* urginline=1 表示紧急数据将被当作普通数据处理。*/

                      intr,

                      blog,/* blog=1 表示对应套接字处于节制状态,此时接收的数据包均被丢弃*/

                      done,

                      reuse,

                      keepopen,/* keepopen=1 表示使用保活定时器 */

                      linger,/* linger=1 表示在关闭套接字时需要等待一段时间以确认其已关闭。*/

                      delay_acks,/* delay_acks=1表示延迟应答,可一次对多个数据包进行应答 */

                      destroy,/* destroy=1 表示该 sock 结构等待销毁*/

                      ack_timed,

                      no_check,

                      zapped,   /* In ax25 & ipx means not linked */

                      broadcast,

                      nonagle;/* noagle=1 表示不使用 NAGLE 算法*/

  unsigned long                   lingertime;/*表示等待关闭操作的时间,只有当 linger 标志位为 1 时,该字段才有意义。*/

  int                    proc;/* 该 sock 结构(即该套接字)所属的进程的进程号。*/

  struct sock                *next;

  struct sock                *prev;

  struct sock                *pair;

/* 以上三个字段用于 sock 的连接*/

 

  struct sk_buff      * volatile send_head;

  struct sk_buff      * volatile send_tail;

/* send_head, send_tail 用于 TCP协议重发队列。*/

 

  struct sk_buff_head       back_log;/* back_log为接收的数据包缓存队列。用于计算目前累计的应发送而未发送的应答数据包的个数*/

  struct sk_buff      *partial;/*创建最大长度的待发送数据包。*/

  struct timer_list         partial_timer;/*按时发送 partial 指针指向的数据包,以免缓存(等待)时间过长。*/

  long                      retransmits;/* 重发次数*/

/*

write_queue 指向待发送数据包,其与 send_head,send_tail 队列的不同之处在于send_head,send_tail 队列中数据包均已经发送出去,但尚未接收到应答。而 write_queue 中数据包尚未发送。 receive-queue为读队列,其不同于 back_log 队列之处在于 back_log 队列缓存从网络层传 上来的数据包,在用户进行读取操作时,不可操作 back_log 队列,而是从 receive_queue 队列中去数据包读取其中的数据,即数据包首先缓存在 back_log 队列中,然后从 back_log 队列中移动到 receive_queue队列中方可被应用程序读取。而并非所有back_log 队列中缓 存的数据包都可以成功的被移动到 receive_queue队列中,如果此刻读缓存区太小,则当 前从back_log 队列中被取下的被处理的数据包将被直接丢弃,而不会被缓存到receive_queue 队列中。如果从应答的角度看,在back_log队列中的数据包由于有可能被 丢弃,故尚未应答,而将一个数据包从 back_log 移动到 receive_queue时,表示该数据包 已被正式接收,即会发送对该数据包的应答给远端表示本地已经成功接收该数据包。 */

  struct sk_buff_head       write_queue,

                      receive_queue;

 

  struct proto               *prot;/*指向传输层处理函数集*/

  struct wait_queue           **sleep;/*进程等待sock的地位*/

  unsigned long                 daddr;/*套接字的远端地址*/

  unsigned long                 saddr;/*套接字的本地地址*/

  unsigned short          max_unacked;/* 最大未处理请求连接数(应答数) */

  unsigned short          window;/* 远端窗口大小 */

  unsigned short          bytes_rcv;/* 已接收字节总数*/

/* mss is min(mtu, max_window) */

  unsigned short          mtu;       /*最大传输单元*/

  volatile unsigned short  mss;       /*最大报文长度:MSS=MTU-IP 首部长度-TCP首部长度 */

  volatile unsigned short  user_mss;  /*用户指定的 MSS值*/

 

  volatile unsigned short  max_window;

  unsigned long          window_clamp;/*最大窗口大小和窗口大小钳制值 */

 

  unsigned short          num;/* 本地端口号*/

/*

以下三个字段用于拥塞算法

*/  

  volatile unsigned short  cong_window;

  volatile unsigned short  cong_count;

  volatile unsigned short  ssthresh;

  volatile unsigned short  packets_out;/* 本地已发送出去但尚未得到应答的数据包数目*/

  volatile unsigned short  shutdown;/* 本地关闭标志位,用于半关闭操作*/

  volatile unsigned long   rtt;/* 往返时间估计值*/

  volatile unsigned long   mdev;/* mean deviation, 即RTTD,  绝对偏差*/

  volatile unsigned long   rto;/* RTO是用 RTT 和 mdev 用算法计算出的延迟时间值*/

  volatile unsigned short  backoff;/* 退避算法度量值 */

  volatile short        err;/* 错误标志值*/

  unsigned char                 protocol;/* 传输层协议值*/

  volatile unsigned char   state;/* 套接字状态值,如 TCP_ESTABLISHED */

  volatile unsigned char   ack_backlog;/* 缓存的未应答数据包个数*/

  unsigned char                 max_ack_backlog;/* 最大缓存的未应答数据包个数*/

  unsigned char                 priority;/* 该套接字优先级,在硬件缓存发送数据包时使用 */

  unsigned char                 debug;

  unsigned short          rcvbuf;/* 最大接收缓冲区大小*/

  unsigned short          sndbuf;/* 最大发送缓冲区大小*/

  unsigned short          type;/* 类型值如 SOCK_STREAM */

  unsigned char                 localroute;    /* localroute=1 表示只使用本地路由,一般目的端在相同子网时使用。*/

#ifdef CONFIG_IPX

  ipx_address               ipx_dest_addr;

  ipx_interface             *ipx_intrfc;

  unsigned short          ipx_port;

  unsigned short          ipx_type;

#endif

#ifdef CONFIG_AX25

  ax25_address            ax25_source_addr,ax25_dest_addr;

  struct sk_buff *volatile   ax25_retxq[8];

  char                      ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr;

  char                      ax25_condition;

  char                      ax25_retxcnt;

  char                      ax25_xx;

  char                      ax25_retxqi;

  char                      ax25_rrtimer;

  char                      ax25_timer;

  unsigned char                 ax25_n2;

  unsigned short          ax25_t1,ax25_t2,ax25_t3;

  ax25_digi              *ax25_digipeat;

#endif 

#ifdef CONFIG_ATALK

  struct atalk_sock      at;

#endif

 

/* IP 'private area' or will be eventually */

  int                    ip_ttl;       /* IP首部 TTL 字段值,实际上表示路由器跳数*/

  int                    ip_tos;           /* IP首部 TOS字段值,服务类型值*/

  struct tcphdr             dummy_th;/* 缓存的 TCP首部,在 TCP协议中创建一个发送数据包时可以利用此字段快速创建 TCP 首部。*/

  struct timer_list         keepalive_timer;     /*保活定时器,用于探测对方窗口大小,防止对方通报窗口大小的数据包丢弃,从而造成 本地发送通道被阻塞。*/

  struct timer_list         retransmit_timer;    /*重发定时器,用于数据包超时重发*/

  struct timer_list         ack_timer;          /*延迟应答定时器,延迟应答可以减少应答数据包的个数,但不可无限延迟以免造成远端 重发,所以设置定时器定期发送应答数据包。 */

  int                    ip_xmit_timeout;     /*该字段为标志位组合字段,用于表示下文中 timer定时器超时的原因*/

#ifdef CONFIG_IP_MULTICAST 

  int                    ip_mc_ttl;                

  int                    ip_mc_loop;            

  char                      ip_mc_name[MAX_ADDR_LEN]; 

  struct ip_mc_socklist          *ip_mc_list;     

#endif 

/*以上4 个字段用于 IP多播*/

 

  int                    timeout;  

  struct timer_list         timer;

/* 以上两个字段用于通用定时,timeout 表示定时时间值,ip_xmit_timeout表示此次定时的 原因,timer为定时器。 */

  struct timeval       stamp;/* 时间戳*/

  struct socket             *socket;/*对应的socket结构体*/

 

  void                       (*state_change)(struct sock *sk);

  void                       (*data_ready)(struct sock *sk,int bytes);

  void                       (*write_space)(struct sock *sk);

  void                       (*error_report)(struct sock *sk);

/* 以上四个函数指针字段指向回调函数。这些字段的设置为自定义回调函数提供的很大的

灵活性,内核在发生某些时间时,会调用这些函数,如此可以实现自定义响应。目前这

种自定义响应还是完全有内核控制。 */  

};

在inet_create 函数中,这个结构体的成员基本上都被初始化了

static int inet_create(struct socket *sock, int protocol)
{

     ......


 switch(sock->type)
 {

......

case SOCK_STREAM:
  case SOCK_SEQPACKET:
/*
在 socket 系统调用时,我们一般将 protocol 参数设置为 0。如果设置为非 0,
则对于不同的类型,必须赋予正确值,否则可能在此处处理时出现问题。
*/
   if (protocol && protocol != IPPROTO_TCP)
   {
    kfree_s((void *)sk, sizeof(*sk));
    return(-EPROTONOSUPPORT);
   }
   protocol = IPPROTO_TCP;
/*
TCP_NO_CHECK定义为 1,表示对于 TCP协议默认使用校验
*/ 
   sk->no_check = TCP_NO_CHECK;
/*
注意此处prot 变量被初始化为 tcp_prot,稍后 sock 结构的prot 字段将被初始
化为prot 变量值。
*/
   prot = &tcp_prot;
   break;

......

  }

......

sk->socket = sock;/*建立与其对应的 socket结构之间的关系,socket结构先于 sock 结构建立。 */
#ifdef CONFIG_TCP_NAGLE_OFF
 sk->nonagle = 1;
#else   
 sk->nonagle = 0;
#endif 
 sk->type = sock->type;/*初始化 sock 结构 type 字段:套接字类型*/
 sk->stamp.tv_sec=0;
 sk->protocol = protocol;/*传输层协议*/
 sk->wmem_alloc = 0;
 sk->rmem_alloc = 0;
 sk->sndbuf = SK_WMEM_MAX;/*最大发送缓冲区大小*/
 sk->rcvbuf = SK_RMEM_MAX;/*最大接收缓冲区大小*/
 sk->pair = NULL;
 sk->opt = NULL;
 sk->write_seq = 0;
 sk->acked_seq = 0;
 sk->copied_seq = 0;
 sk->fin_seq = 0;
 sk->urg_seq = 0;
 sk->urg_data = 0;
 sk->proc = 0;
 sk->rtt = 0;    /*TCP_WRITE_TIME << 3;*/
 sk->rto = TCP_TIMEOUT_INIT;  /*TCP_WRITE_TIME*/
 sk->mdev = 0;
 sk->backoff = 0;
 sk->packets_out = 0;
/*
cong_window 设置为 1,即 TCP首先进入慢启动阶段。这是 TCP协议处理拥塞的 一种策略
*/
 sk->cong_window = 1; /* start with only sending one packet at a time. */
 sk->cong_count = 0;
 sk->ssthresh = 0;
 sk->max_window = 0;
 sk->urginline = 0;
 sk->intr = 0;
 sk->linger = 0;
 sk->destroy = 0;
 sk->priority = 1;
 sk->shutdown = 0;
 sk->keepopen = 0;
 sk->zapped = 0;
 sk->done = 0;
 sk->ack_backlog = 0;
 sk->window = 0;
 sk->bytes_rcv = 0;
 sk->state = TCP_CLOSE;/*由于尚未进行连接,状态设置为 CLOSE。*/
 sk->dead = 0;
 sk->ack_timed = 0;
 sk->partial = NULL;
 sk->user_mss = 0;
 sk->debug = 0;
/*
设置最大可暂缓应答的字节数
*/
 /* this is how many unacked bytes we will accept for this socket.  */
 sk->max_unacked = 2048; /* needs to be at most 2 full packets. */

 /* how many packets we should send before forcing an ack.
    if this is set to zero it is the same as sk->delay_acks = 0 */
 sk->max_ack_backlog = 0;
 sk->inuse = 0;
 sk->delay_acks = 0;
 skb_queue_head_init(&sk->write_queue);
 skb_queue_head_init(&sk->receive_queue);
 sk->mtu = 576;/*MTU设置为保守的576字节, 该大小在绝大多数连接中不会造成分片*/

 sk->prot = prot;
 sk->sleep = sock->wait;
 sk->daddr = 0;
 sk->saddr = 0 /* ip_my_addr() */;
 sk->err = 0;
 sk->next = NULL;
 sk->pair = NULL;
 sk->send_tail = NULL;
 sk->send_head = NULL;
 sk->timeout = 0;
 sk->broadcast = 0;
 sk->localroute = 0;
 init_timer(&sk->timer);
 init_timer(&sk->retransmit_timer);
 sk->timer.data = (unsigned long)sk;
 sk->timer.function = &net_timer;
 skb_queue_head_init(&sk->back_log);
 sk->blog = 0;
 sock->data =(void *) sk;
/*sock 结构之 dummy_th 字段是 tcphdr结构,该结构与 TCP首部各字段对应*/ 
 sk->dummy_th.doff = sizeof(sk->dummy_th)/4;
 sk->dummy_th.res1=0;
 sk->dummy_th.res2=0;
 sk->dummy_th.urg_ptr = 0;
 sk->dummy_th.fin = 0;
 sk->dummy_th.syn = 0;
 sk->dummy_th.rst = 0;
 sk->dummy_th.psh = 0;
 sk->dummy_th.ack = 0;
 sk->dummy_th.urg = 0;
 sk->dummy_th.dest = 0;
 sk->ip_tos=0;
 sk->ip_ttl=64;
#ifdef CONFIG_IP_MULTICAST
 sk->ip_mc_loop=1;
 sk->ip_mc_ttl=1;
 *sk->ip_mc_name=0;
 sk->ip_mc_list=NULL;
#endif
/*
对 sock 结构中几个回调函数字段的初始化
*/   
 sk->state_change = def_callback1;
 sk->data_ready = def_callback2;
 sk->write_space = def_callback3;
 sk->error_report = def_callback1;
/*
如果该套接字已经分配本地端口号,则对 sock 结构中 dummy_th 结构字段进行赋值
*/
 if (sk->num)
 {
 /*
  * It assumes that any protocol which allows
  * the user to assign a number at socket
  * creation time automatically
  * shares.
  */
  put_sock(sk->num, sk);
  sk->dummy_th.source = ntohs(sk->num);
 }

......

return(0);
}

此后,数据的传送,都由sock结构体作为数据的携带者,传送给下层的传输层,网络层,链路层,链路层

网络协议栈3:sock结构体相关推荐

  1. struct sk_buff与struct socket及struct sock 结构体分析

    sk_buff是Linux网络协议栈最重要的数据结构之一,该数据结构贯穿于整个数据包处理的流程.由于协议采用分层结构,上层向下层传递数据时需要增加包头,下层向上层数据时又需要去掉包头.sk_buff中 ...

  2. linux sock结构体,struct socket结构体详解

    在内核中为什么要有struct socket结构体呢? struct socket结构体的作用是什么? 下面这个图,我觉得可以回答以上两个问题.  由这个图可知,内核中的进程可以通过使用struct ...

  3. 网络驱动之net_device结构体

    在Linux系统中,网络设备都被抽象为struct net_device结构体.它是网络设备硬件与上层协议之间联系的接口,了解它对编写网络驱动程序非常有益,所以本文将着手简要介绍linux-2.6.3 ...

  4. linux sockaddr结构体,linux网络编程笔记 sockaddr_in结构体[转]

    struct sockaddr { unsigned short sa_family; char sa_data[14]; }; 此数据结构用做bind.connect.recvfrom.sendto ...

  5. linux sockaddr结构体,网络编程之sockaddr_ll结构体 | 人人学技术

    sockaddr_ll, 源文件为,结构如下: struct sockaddr_ll { unsigned short int sll_family; /* 一般为AF_PACKET */ unsig ...

  6. 网络协议栈深入分析(三)--BSD socket和传输层sock

    Linux内核中协议族有INET协议族,UNIX协议族等,我们还是以INET协议族为例. 下面是内核中的协议族声明: [cpp] view plaincopy /* Supported address ...

  7. Linux内核网络协议栈

    一.注册时机 1.在内核初始化时完成: 2.内核初始化过程(init/main.c):kernel_init()->do_basic_setup()->do_initcalls()-> ...

  8. Linux 内核网络协议栈运行原理

    封装:当应用程序用 TCP 协议传送数据时,数据首先进入内核网络协议栈中,然后逐一通过 TCP/IP 协议族的每层直到被当作一串比特流送入网络.对于每一层而言,对收到的数据都会封装相应的协议首部信息( ...

  9. 网络协议栈11:Connect函数分解之TCP层

    Connect函数之分解1. 首先,connect函数从参数获得远端的IP,把这个地址赋值给对应的sock结构体的对应变量,并设置了sock结构体中的一些其他变量后,首先分配(skb_buff+用户空 ...

最新文章

  1. c++ map iterator 获取key_前K个高频的元素衍生之Map的Value与Key排序
  2. 甘利俊一 | 信息几何法:理解深度神经网络学习机制的重要工具
  3. 计算机系统的搭建步骤,电脑搭建Node.js开发环境的操作教程[多图]
  4. delphi 调用php接口_新浪图床 API 接口调用与请求方法详细教程
  5. Java虚拟机详解04----GC算法和种类【重要】
  6. Java非访问修饰符
  7. CNCF 公布 2020 年 TOC 选举结果 | 云原生生态周报 Vol. 36
  8. MSSSQL 脚本收藏
  9. 软件设计原则(六)迪米特法则 -Law of Demeter
  10. java request获取文件_request获取路径方式
  11. HDU 1210 Eddy's 洗牌问题(foj1062) || FOJ1050 Number lengths水
  12. 蓝桥杯真题:杨辉三角形
  13. (一)Multisim安装与入门
  14. 联通4g满格但是网速慢_联通4g网络慢是什么原因 联通4g满格但是网速慢
  15. 【DDR3_Electrical Characteristics and AC Timing】_Data Setup,Hold and Slew Rate Derating
  16. python用turtle画字母n、h_详解python使用turtle库来画一朵花
  17. 在图片上涂鸦(其实就是乱画 O(∩_∩)O)
  18. 【Programe.VIM学习】
  19. 区块链+数字经济,我们看到了什么
  20. 6-8.4V自动升降压5V 9V 12V PD快充解决方案 TYPE-C快充

热门文章

  1. js正则表达式实现千分位符
  2. 备份和恢复IMail数据/IMail的服务端口
  3. 超级计算机作文500字初中,自我介绍初中作文500字(精选9篇)
  4. Redis学习一:Redis两种持久化机制
  5. 用Java实现一个抽奖系统(附完整代码)
  6. 投入产出实例matlab,利用MATLAB进行基础的投入产出表分析实验报告.doc
  7. 深度学习在智能机器人中的应用
  8. 自然科学领域期刊分区——什么是核心期刊(核心A、B、C)
  9. “备份集中的数据库备份与现有的数据库不同”解决方法
  10. 画论77 汤贻汾《画筌析览》