1、socket

(include\linux\Socket.h)该结构体socket 主要使用在BSD socket 层,是最上层的结构,在INET socket 层也会有涉及,但很少。

/** Internal representation of a socket. not all the fields are used by* all configurations:**             server                client* conn        client connected to server connected to* iconn      list of clients     -unused-*        awaiting connections* wait     sleep for clients,  sleep for connection,*          sleep for i/o               sleep for i/o*///该结构表示一个网络套接字
struct socket {short            type;       /* 套接字所用的流类型*/socket_state      state;//套接字所处状态long         flags;//标识字段,目前尚无明确作用struct proto_ops    *ops;       /* 操作函数集指针  *//* data保存指向‘私有'数据结构指针,在不同的域指向不同的数据结构      *///在INET域,指向sock结构,UNIX域指向unix_proto_data结构void          *data;  //下面两个字段只用于UNIX域struct socket       *conn;      /* 指向连接的对端套接字   */struct socket     *iconn;     /* 指向正等待连接的客户端(服务器端)    */struct socket     *next;//链表struct wait_queue **wait;     /* 等待队列 */struct inode      *inode;//inode结构指针struct fasync_struct  *fasync_list;   /* 异步唤醒链表结构 */
};

2、sock

(include\linux\Net.h) sock 的使用范围比socket 要大得多,sock结构的使用基本贯穿硬件层、设备接口层、ip层、INET socket 层,而且是作为各层之间的一个联系,主要是因为无论是发送还是接收的数据包都要被缓存到sock 结构中的缓冲队列中。

sock 结构与其对应的 socket 会相互绑定。

/** This structure really needs to be cleaned up.* Most of it is for TCP, and not used by any of* the other protocols.* 大部分功能是为TCP准备的*/
struct sock {struct options     *opt;//IP选项缓冲于此处volatile unsigned long  wmem_alloc;//发送缓冲队列中存放的数据的大小,这两个与后面的rcvbuf和sndbuf一起使用volatile unsigned long  rmem_alloc;//接收缓冲队列中存放的数据的大小/* 下面三个seq用于TCP协议中为保证可靠数据传输而使用的序列号 */unsigned long          write_seq;//unsigned long           sent_seq;//unsigned long            acked_seq;//unsigned long           copied_seq;//应用程序有待读取(但尚未读取)数据的第一个序列号unsigned long          rcv_ack_seq;//目前本地接收到的对本地发送数据的应答序列号unsigned long            window_seq;//窗口大小unsigned long          fin_seq;//应答序列号//下面两个字段用于紧急数据处理unsigned long            urg_seq;//紧急数据最大序列号unsigned long            urg_data;//标志位,1表示收到紧急数据/** Not all are volatile, but some are, so we* might as well say they all are.*/volatile char                 inuse,//表示其他进程正在使用该sock结构,本进程需等待dead,//表示该sock结构已处于释放状态urginline,//=1,表示紧急数据将被当做普通数据处理intr,//blog,done,reuse,keepopen,//=1,使用保活定时器linger,//=1,表示在关闭套接字时需要等待一段时间以确认其已关闭delay_acks,//=1,表示延迟应答destroy,//=1,表示该sock结构等待销毁ack_timed,no_check,zapped,    /* In ax25 & ipx means not linked */broadcast,nonagle;//=1,表示不使用NAGLE算法//NAGLE算法:在前一个发送的数据包被应答之前,不可再继续发送其它数据包unsigned long               lingertime;//等待关闭操作的时间int               proc;//该sock结构所属的进程的进程号struct sock          *next;struct sock           *prev; /* Doubly linked chain.. */struct sock           *pair;//下面两个字段用于TCP协议重发队列struct sk_buff     * volatile send_head;//这个队列中的数据均已经发送出去,但尚未接收到应答struct sk_buff        * volatile send_tail;struct sk_buff_head        back_log;//接收的数据包缓存队列,当套接字正忙时,数据包暂存在这里struct sk_buff      *partial;//用于创建最大长度的待发送数据包struct timer_list     partial_timer;//定时器,用于按时发送partial指针指向的数据包long                retransmits;//重发次数struct sk_buff_head       write_queue,//指向待发送数据包receive_queue;//读队列,表示数据报已被正式接收,该队列中的数据可被应用程序读取?struct proto            *prot;//传输层处理函数集struct wait_queue       **sleep;unsigned long           daddr;//sock结构所代表套接字的远端地址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; //最大报文长度 =mtu-ip首部长度-tcp首部长度,也就是tcp数据包每次能够传输的最大数据分段volatile unsigned short user_mss;  /* mss requested by user in ioctl */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;//绝对偏差volatile unsigned long   rto;//用rtt和mdev 用算法计算出的延迟时间值
/* currently backoff isn't used, but I'm maintaining it in case* we want to go back to a backoff formula that needs it*/volatile unsigned short   backoff;//退避算法度量值volatile short     err;//错误标志值unsigned char            protocol;//传输层协议值volatile unsigned char state;//套接字状态值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_STREAMunsigned char            localroute;//=1,表示只使用本地路由 /* Route locally only */
#ifdef CONFIG_IPXipx_address            ipx_dest_addr;ipx_interface         *ipx_intrfc;unsigned short      ipx_port;unsigned short     ipx_type;
#endif
#ifdef CONFIG_AX25
/* Really we want to add a per protocol private area */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_ATALKstruct atalk_sock        at;
#endif/* IP 'private area' or will be eventually */int                ip_ttl;//ip首部ttl字段值,实际上表示路由器跳数       /* TTL setting */int                ip_tos;//ip首部tos字段值,服务类型值        /* TOS */struct tcphdr          dummy_th;//缓存的tcp首部,在tcp协议中创建一个发送数据包时可以利用此字段快速创建tcp首部struct timer_list       keepalive_timer;//保活定时器,用于探测对方窗口大小,防止对方通报窗口大小的数据包丢弃   /* TCP keepalive hack */struct timer_list       retransmit_timer;//重发定时器,用于数据包超时重发   /* TCP retransmit timer */struct timer_list     ack_timer;//延迟应答定时器     /* TCP delayed ack timer */int              ip_xmit_timeout;//表示定时器超时原因 /* Why the timeout is running *///用于ip多播
#ifdef CONFIG_IP_MULTICAST  int             ip_mc_ttl;          /* Multicasting TTL */int               ip_mc_loop;         /* Loopback (not implemented yet) */char                ip_mc_name[MAX_ADDR_LEN];   /* Multicast device name */struct ip_mc_socklist        *ip_mc_list;            /* Group array */
#endif  /* This part is used for the timeout functions (timer.c). */int             timeout;    /* What are we waiting for? */struct timer_list     timer;      /* This is the TIME_WAIT/receive timer when we are doing IP */struct timeval        stamp;/* identd *///一个套接在在不同的层次上分别由socket结构和sock结构表示struct socket           *socket;/* Callbacks *///回调函数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);};

3、sk_buff

(include\linux\Skbuff.h) sk_buff 是网络数据报在内核中的表现形式,通过源码可以看出,数据包在内核协议栈中是通过这个数据结构来变现的。

从其中的 union 字段可以看出,该结构是贯穿在各个层的,可以说这个结构是用来为网络数据包服务的。其中的字段表明了数据包隶属的套接字、当前所处的协议层、所搭载的数据负载长度(data指针指向)、源端,目的端地址以及相关字段等。

主要重要的一个字段是 data[0],这是一个指针,它指向对应层的数据报(首部+数据负载)内容的首地址。怎么解释呢?

如果在传输层,那么data指向的数据部分的首地址,其数据部分为 TCP 首部 + 有效数据负载。

如果在网络层,data指向的数据部分的首地址,其数据部分为 IP 首部 + TCP 首部 + 有效数据负载。

如果在链路层,data指向的首地址,其数据布局为 MAC 首部 + IP 首部 + TCP 首部 + 有效数据负载。

所以在该skb_buff结构传递时,获取某一层的首部,都是通过拷贝 data 指向地址对应首部大小的数据。

  //sk_buff 结构用来封装网络数据//网络栈代码对数据的处理都是以sk_buff 结构为单元进行的
struct sk_buff {struct sk_buff      * volatile next;struct sk_buff      * volatile prev;//构成队列
#if CONFIG_SKB_CHECKint             magic_debug_cookie; //调试用
#endifstruct sk_buff        * volatile link3; //构成数据包重发队列struct sock            *sk; //数据包所属的套接字volatile unsigned long  when;    //数据包的发送时间,用于计算往返时间RTT/* used to compute rtt's */struct timeval        stamp; //记录时间struct device          *dev; //接收该数据包的接口设备struct sk_buff       *mem_addr; //该sk_buff在内存中的基地址,用于释放该sk_buff结构//联合类型,表示数据报在不同处理层次上所到达的处理位置union {struct tcphdr  *th; //传输层tcp,指向首部第一个字节位置struct ethhdr   *eth; //链路层上,指向以太网首部第一个字节位置struct iphdr  *iph; //网络层上,指向ip首部第一个字节位置struct udphdr  *uh; //传输层udp协议,unsigned char    *raw; //随层次变化而变化,链路层=eth,网络层=iphunsigned long   seq; //针对tcp协议的待发送数据包而言,表示该数据包的ACK值} h;struct iphdr      *ip_hdr; //指向ip首部的指针        /* For IPPROTO_RAW */unsigned long          mem_len; //表示sk_buff结构大小加上数据部分的总长度unsigned long         len; //只表示数据部分长度,len = mem_len - sizeof(sk_buff)unsigned long           fraglen; //分片数据包个数struct sk_buff        *fraglist;  /* Fragment list */unsigned long            truesize; //同men_lenunsigned long       saddr; //源端ip地址unsigned long        daddr; //目的端ip地址unsigned long           raddr; //数据包下一站ip地址     /* next hop addr *///标识字段volatile char      acked, //=1,表示数据报已得到确认,可以从重发队列中删除used, //=1,表示该数据包的数据已被应用程序读完,可以进行释放free, //用于数据包发送,=1表示再进行发送操作后立即释放,无需缓存arp; //用于待发送数据包,=1表示已完成MAC首部的建立,=0表示还不知道目的端MAC地址//已进行tries试发送,该数据包正在被其余部分使用,路由类型,数据包类型unsigned char          tries,lock,localroute,pkt_type;//下面是数据包的类型,即pkt_type的取值
#define PACKET_HOST     0     //发往本机    /* To us */
#define PACKET_BROADCAST    1 //广播
#define PACKET_MULTICAST    2 //多播
#define PACKET_OTHERHOST    3 //其他机器        /* Unmatched promiscuous */unsigned short       users; //使用该数据包的模块数     /* User count - see datagram.c (and soon seqpacket.c/stream.c) */unsigned short     pkt_class;  /* For drivers that need to cache the packet type with the skbuff (new PPP) */
#ifdef CONFIG_SLAVE_BALANCINGunsigned short     in_dev_queue; //该字段是否正在缓存于设备缓存队列中
#endif  unsigned long           padding[0]; //填充字节unsigned char         data[0]; //指向该层数据部分//data指向的数据负载首地址,在各个层对应不同的数据部分
//从侧面看出sk_buff结构基本上是贯穿整个网络栈的非常重要的一个数据结构
};

4、device

(include\linux\Netdevice.h)该结构表明了一个网络设备需要的字段信息。

/** The DEVICE structure.* Actually, this whole structure is a big mistake.  It mixes I/O* data with strictly "high-level" data, and it has to know about* almost every data structure used in the INET module.  *///网络设备结构
struct device
{/** This is the first field of the "visible" part of this structure* (i.e. as seen by users in the "Space.c" file).  It is the name* the interface.*/char            *name;//设备名称/* I/O specific fields - FIXME: Merge these and struct ifmap into one */unsigned long       rmem_end;//设备读缓冲区空间       /* shmem "recv" end   */unsigned long       rmem_start;       /* shmem "recv" start */unsigned long       mem_end;//设备总缓冲区首地址和尾地址       /* sahared mem end  */unsigned long       mem_start;        /* shared mem start */unsigned long       base_addr;//设备寄存器读写IO基地址      /* device I/O address   */unsigned char       irq;  //设备所使用中断号      /* device IRQ number    *//* Low-level status flags. */volatile unsigned char  start,//=1,表示设备已处于工作状态       /* start an operation   */tbusy,//=1,表示设备正忙于数据包发送       /* transmitter busy */interrupt;//=1,软件正在进行设备中断处理       /* interrupt arrived    */struct device       *next;//构成设备队列/* The device initialization function. Called only once. */int            (*init)(struct device *dev);//设备初始化指针(函数指针)/* Some hardware also needs these fields, but they are not part of theusual set specified in Space.c. */unsigned char        if_port;//指定使用的设备端口号      /* Selectable AUI, TP,..*/unsigned char       dma;//设备所用的dma通道号         /* DMA channel      */struct enet_statistics* (*get_stats)(struct device *dev);//设备信息获取函数指针/** This marks the end of the "visible" part of the structure. All* fields hereafter are internal to the system, and may change at* will (read: may be cleaned up at will).*//* These may be needed for future network-power-down code. */unsigned long          trans_start;//用于传输超时计算    /* Time (in jiffies) of last Tx */unsigned long       last_rx;//上次接收一个数据包的时间    /* Time of last Rx      */unsigned short      flags;//标志位   /* interface flags (a la BSD)   */unsigned short      family;//设备所属的域协议 /* address family ID (AF_INET)  */unsigned short      metric;   /* routing metric (not used)    */unsigned short      mtu;//该接口设备的最大传输单元,ip首部+tcp首部+有效数据负载,去掉了以太网帧的帧头 /* interface MTU value*/unsigned short      type;//该设备所属硬件类型      /* interface hardware type  */unsigned short      hard_header_len;//硬件首部长度  /* hardware hdr length  */void            *priv;//私有数据指针    /* pointer to private data  *//* Interface address info. */unsigned char          broadcast[MAX_ADDR_LEN];//链路层硬件广播地址   /* hw bcast add */unsigned char       dev_addr[MAX_ADDR_LEN];//本设备硬件地址  /* hw address   */unsigned char       addr_len;//硬件地址长度 /* hardware address length  */unsigned long       pa_addr;//本地ip地址  /* protocol address     */unsigned long       pa_brdaddr;//网络层广播ip地址    /* protocol broadcast addr  */unsigned long       pa_dstaddr;//点对点网络中对点的ip地址    /* protocol P-P other side addr */unsigned long       pa_mask;//ip地址网络掩码    /* protocol netmask     */unsigned short      pa_alen;//ip地址长度  /* protocol address length  */struct dev_mc_list     *mc_list;//多播地址链表  /* Multicast mac addresses  */int            mc_count;//多播地址数目  /* Number of installed mcasts   */struct ip_mc_list  *ip_mc_list;//网络层ip多播地址链表  /* IP multicast filter chain    *//* For load balancing driver pair support */unsigned long        pkt_queue;//该设备缓存的待发送的数据包个数  /* Packets queued */struct device         *slave;//从设备  /* Slave device *//* Pointer to the interface buffers. */struct sk_buff_head      buffs[DEV_NUMBUFFS];//设备缓存的待发送的数据包//函数指针/* Pointers to interface service routines. */int            (*open)(struct device *dev);int             (*stop)(struct device *dev);int             (*hard_start_xmit) (struct sk_buff *skb,struct device *dev);int             (*hard_header) (unsigned char *buff,struct device *dev,unsigned short type,void *daddr,void *saddr,unsigned len,struct sk_buff *skb);int            (*rebuild_header)(void *eth, struct device *dev,unsigned long raddr, struct sk_buff *skb);//用于从接收到的数据包提取MAC首部中类型字符值,从而将数据包传送给适当的协议处理函数进行处理unsigned short     (*type_trans) (struct sk_buff *skb,struct device *dev);
#define HAVE_MULTICAST           void             (*set_multicast_list)(struct device *dev,int num_addrs, void *addrs);
#define HAVE_SET_MAC_ADDR        int              (*set_mac_address)(struct device *dev, void *addr);
#define HAVE_PRIVATE_IOCTLint             (*do_ioctl)(struct device *dev, struct ifreq *ifr, int cmd);
#define HAVE_SET_CONFIGint            (*set_config)(struct device *dev, struct ifmap *map);};

5、tcp 首部格式

 //tcp首部格式//http://blog.csdn.net/wenqian1991/article/details/44598537
struct tcphdr {__u16    source;//源端口号__u16  dest;//目的端口号__u32   seq;//32位序列号__u32   ack_seq;//32位确认号
#if defined(LITTLE_ENDIAN_BITFIELD)__u16    res1:4,//4位首部长度doff:4,//保留//下面为各个控制位fin:1,//最后控制位,表示数据已全部传输完成syn:1,//同步控制位rst:1,//重置控制位psh:1,//推控制位ack:1,//确认控制位urg:1,//紧急控制位res2:2;//
#elif defined(BIG_ENDIAN_BITFIELD)__u16 doff:4,res1:4,res2:2,urg:1,ack:1,psh:1,rst:1,syn:1,fin:1;
#else
#error  "Adjust your <asm/byteorder.h> defines"
#endif  __u16   window;//16位窗口大小__u16   check;//16位校验和__u16 urg_ptr;//16位紧急指针
};

6、ip 首部格式

 //ip数据报,首部格式
struct iphdr {
#if defined(LITTLE_ENDIAN_BITFIELD)//如果是小端模式__u8    ihl:4,//首部长度version:4;//版本
#elif defined (BIG_ENDIAN_BITFIELD)//大端__u8 version:4,ihl:4;
#else
#error  "Please fix <asm/byteorder.h>"
#endif__u8  tos;//区分服务,用语表示数据报的优先级和服务类型__u16 tot_len;//总长度,标识整个ip数据报的总长度 = 报头+数据部分__u16 id;//表示ip数据报的标识符__u16   frag_off;//片偏移__u8  ttl;//生存时间,即ip数据报在网络中传输的有效期__u8  protocol;//协议,标识此ip数据报在传输层所采用的协议类型__u16  check;//首部校验和__u32  saddr;//源地址__u32    daddr;//目的地址/*The options start here. */
};

7、以太网帧帧头格式

/* This is an Ethernet frame header. */
struct ethhdr {unsigned char        h_dest[ETH_ALEN];//目的地址 /* destination eth addr */unsigned char     h_source[ETH_ALEN];//源地址    /* source ether addr    */unsigned short    h_proto;//类型        /* packet type ID field */
};

8、ARP报文报头

/**  This structure defines an ethernet arp header.*///ARP报文格式(arp报头)
struct arphdr
{unsigned short ar_hrd;//硬件类型       /* format of hardware address   */unsigned short    ar_pro;//上层协议类型     /* format of protocol address   */unsigned char ar_hln;//MAC地址长度        /* length of hardware address   */unsigned char ar_pln;//协议地址长度     /* length of protocol address   */unsigned short    ar_op;//操作类型        /* ARP opcode (command)     */#if 0/**   Ethernet looks like this : This bit is variable sized however...*/unsigned char        ar_sha[ETH_ALEN];//源MAC地址   /* sender hardware address  */unsigned char     ar_sip[4];//源IP地址       /* sender IP address        */unsigned char     ar_tha[ETH_ALEN];//目的MAC地址  /* target hardware address  */unsigned char     ar_tip[4];//目的IP地址      /* target IP address        */
#endif};

网络栈主要结构介绍(socket、sock、sk_buff,etc)相关推荐

  1. Linux内核网络栈1.2.13-af_inet.c概述

    参考资料 <<linux内核网络栈源代码情景分析>> socket常用函数继续调用分析 根据socket提供的常用库函数,socket.read和write等函数,继续往下一层 ...

  2. Linux内核网络栈1.2.13-socket.c函数概述

    参考资料 <<linux内核网络栈源代码情景分析>> socket常用函数概述 根据socket提供的常用的库函数,socket,read,write等函数, 执行的过程 in ...

  3. Linux内核--网络栈实现分析(三)--驱动程序层+链路层(上)

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

  4. 显示驱动包含在Linux内核层,驱动程序层(上) - Linux内核--网络栈实现分析_Linux编程_Linux公社-Linux系统门户网站...

    经过前面两篇博文的分析,已经对Linux的内核网络栈的结构有了一个模糊的认识,这里我们开始从底层开始详细分析Linux内核网络栈的实现.由于这是早期版本,代码的层次隔离做的还不是很好,这里说是从底层分 ...

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

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

  6. 1.socket编程:socket编程,网络字节序,函数介绍,IP地址转换函数,sockaddr数据结构,网络套接字函数,socket相关函数,TCP server和client

     1  Socket编程 socket这个词可以表示很多概念: 在TCP/IP协议中,"IP地址+TCP或UDP端口号"唯一标识网络通讯中的一个进程,"IP 地址+端 ...

  7. linux内核网络栈代码的准备知识

    1. linux内核ipv4网络部分分层结构        BSD socket层: 这一部分处理BSD socket相关操作,每个socket在内核中以struct socket结构体现.这一部分的 ...

  8. [译] Linux 网络栈监控和调优:发送数据(2017)

    转载自:http://arthurchiao.art/blog/tuning-stack-tx-zh/ 点击阅读原文 Published at 2018-12-17 | Last Update 202 ...

  9. Linux内核--网络栈实现分析(二)--数据包的传递过程--转

    转载地址http://blog.csdn.net/yming0221/article/details/7492423 作者:闫明 本文分析基于Linux Kernel 1.2.13 注:标题中的&qu ...

最新文章

  1. 提升面对电脑的工作效率
  2. ADFLogger的SLF4J绑定–缺少的部分
  3. qq文件对方接收后一定会有提示吗_为什么微信、QQ不推出已读功能?因为它敢出网友就敢卸载...
  4. (数据库系统概论|王珊)第七章数据库设计-第四节:逻辑结构设计
  5. Dockerfile 学习:Docker Alpine PHP 安装扩展
  6. paip.银行卡号的发卡行归属地查询
  7. oracle怎么下载安装,Oracle数据库下载与安装的完整步骤
  8. 最新的windows xp sp3序列号(绝对可通过正版验证)
  9. 美国飞机安全事件频发:背后黑手竟然是5G?
  10. window系统查找占用端口号进程并杀死
  11. 使用python将图片改为灰度图或黑白图
  12. [leetcode每日一题2021/5/8]1723. 完成所有工作的最短时间
  13. 灵性图书馆:好书推荐-《荷欧波诺波诺的幸福奇迹》
  14. ppt的字母上面插入尖号
  15. Scratch编程 烧脑算法——换位密码
  16. 电脑怎样设置桌面待办,桌面待办事项软件
  17. php调试技术手册读书笔记,RT-Thread读书笔记之一:开始学习了
  18. CSS用flex布局两端对齐,列不满左对齐
  19. 2.1 法学的历史(一):西方法学的历史
  20. python股票交易时间_python 判断是否股市交易日

热门文章

  1. uni-app获取当前位置并计算出某个地点距离
  2. Datawhale 数据挖掘新手入门笔记 -Task5 模型融合
  3. 微信小程序 | 一文总结全部营销抽奖功能
  4. JVM_06 运行时数据区3-方法区
  5. 逸尘杀菌洗地机2 Pro上手体验
  6. 第四模块MySQL数据库
  7. mybatis-plus insertStrategy、updateStrategy、whereStrategy属性
  8. 打包部署后无法读取jar包里的文件(实测可行,Java中读取jar包中的文件)
  9. JavaScript - 运算符与表达式
  10. 骞云科技SmartCMP v3.0正式发布!