第三章 套接字相关数据结构--基于Linux3.10

2023-11-13

本章是对socket通信过程中使用到的比较重要的据结构罗列和意义的阐述,在阅读其它层的代码前,先来看几个重要的数据结构,这几个数据结构贯串四层模型。

 3.1 socket对应的内核结构体

在用户空间使用socket()函数创建一个套接字。对应的系统调用就是:

asmlinkagelong sys_socketcall(int call, unsigned long __user *args);该系统调用的定义在net/socket.c文件的2436行,调用流程中比较重要的一个函数是:

int __sock_create(struct net *net, int family, int type, int protocol, 
struct socket **res, int kern)
{
struct socket*sock;
const struct net_proto_family *pf;

sock = sock_alloc(); //内存空间分配
//根据对应的协议族(protocol family)创建对应的sock。
err = pf->create(net, sock, protocol, kern);
if (err < 0)
goto out_module_put;
}

该函数首先创建一个structsocket的类型结构体,该结构体对应于用户空间的socket,socket的参数之一是协议族,对于Internet协议,create的函数原型是inet_create,internet对应协议族在内核中的表示如下:

static const struct net_proto_family inet_family_ops = {
.family = PF_INET,
.create = inet_create,
.owner  = THIS_MODULE,
};

这里的inet_create函数作用是创建一个inet协议族下的套接字,并且初始化其中的一些成员。

该套接字传递到内核后,内核会创建structsocket存储来该数据结构:

struct socket {
socket_state  state;           //标记sock状态,如SS_CONNECTED、SS_CONNECTING等
short type;                        //socket类型SOCK_STREAM、SOCK_DGRAM、SOCK_RAW等。
unsigned long  flags;              //socket flag 如SOCK_ASYNC_NOSPACE
struct socket_wq __rcu*wq;      
struct file  *file;                 //垃圾回收的文件指针
struct sock  *sk;                 //因特网内部协议的socket表示,对于PF_INET协议,inet_create会创建该成员的各个字段。
const struct proto_ops*ops;              //协议族相关的操作函数集
};

在应用层socket表示套接字,在网络层(IP层)structsock对应应用层中的套接字。

<include/net/sock.h>

struct sock {
socket_lock_t  sk_lock;  //该sock的访问锁
struct sk_buff_headsk_receive_queue;  //接收到的数据包都放在这个sk_buff_head所指向的队列的头上。
struct {
atomic_t  rmem_alloc;
int len;
struct sk_buff   *head;
struct sk_buff   *tail;
} sk_backlog; //对于接收的frame,其由IP层存放在backlog上,后通过tcp的函数进行接收。
#define sk_rmem_alloc sk_backlog.rmem_alloc
int sk_forward_alloc;  //对于到达的frame非本机,允许forward将会被发送出去
#ifdef CONFIG_RPS //网卡新特性,下篇涉及
__u32 sk_rxhash;
#endif
atomic_t  sk_drops; //丢弃的sock计数器
int sk_rcvbuf;

#ifdef CONFIG_XFRM
struct xfrm_policy  *sk_policy[2];   ///流控策略,属于安全机制
#endif
unsigned long 
sk_flags;
struct dst_entry  *sk_rx_dst; //接收流向的
struct dst_entry __rcu  *sk_dst_cache; //路由项的cache
spinlock_t  sk_dst_lock; //路由锁
int sk_sndbuf;
struct sk_buff_headsk_write_queue;    //发送队列
/*sock 信息、状态的一些标志*/
unsigned int  sk_shutdown  : 2,
sk_no_check  : 2,
sk_userlocks : 4,
sk_protocol  : 8,
sk_type      : 16;
gfp_t sk_allocation; //sock动态获申请内存的Flag标志。
/*网卡的一些信息也记录到这里了*/
netdev_features_tsk_route_caps;
netdev_features_tsk_route_nocaps;
int sk_gso_type;
unsigned int  sk_gso_max_size;
u16 sk_gso_max_segs;
/*sock 的一些错误统计信息在此处*/
struct sk_buff_headsk_error_queue;
struct proto  *sk_prot_creator;
rwlock_t  sk_callback_lock;
int sk_err,
sk_err_soft;
unsigned shortsk_ack_backlog;
unsigned shortsk_max_ack_backlog;
__u32 sk_priority;
/*接收和发送的时间戳*/
long  sk_rcvtimeo;
long  sk_sndtimeo;
void  *sk_protinfo;
struct timer_listsk_timer;
ktime_t  sk_stamp;
struct socket  *sk_socket;
/*分片信息*/
struct page_fragsk_frag;
struct sk_buff   *sk_send_head;// /*分片头信息*/
/*sock自带的一些函数指针集*/
void (*sk_state_change)(struct sock *sk);
void (*sk_data_ready)(struct sock *sk, int bytes);
void (*sk_write_space)(struct sock *sk);
void (*sk_error_report)(struct sock *sk);
int (*sk_backlog_rcv)(struct sock *sk, struct sk_buff *skb);
void       (*sk_destruct)(struct sock *sk);
};

3.2 struct proto_ops

<net/ipv4/af_inet.c>

const struct proto_ops inet_stream_ops = {
.family    = PF_INET,//协议族
.owner    = THIS_MODULE,
.release    = inet_release,
.bind   = inet_bind,
.connect    = inet_stream_connect,
.socketpair    = sock_no_socketpair,
.accept    = inet_accept,
.getname    = inet_getname,
.poll   = tcp_poll,
.ioctl    = inet_ioctl,
.listen    = inet_listen,
.shutdown    = inet_shutdown,
.setsockopt    = sock_common_setsockopt,
.getsockopt    = sock_common_getsockopt,
.sendmsg    = inet_sendmsg,
.recvmsg    = inet_recvmsg,
};

上面函数的指针用户空间时常会用到,sendmsg  和recvmsg   是介于应用层和传输层之间的收发函数。

3.3 structproto

<net/ipv4/tcp_ipv4.c>

struct proto tcp_prot = {
.name = "TCP",
.owner  = THIS_MODULE,
.close  = tcp_close,
.connect  = tcp_v4_connect, //建立连接使用到的函数,对应于用户空间的connect函数
.disconnect  = tcp_disconnect,
.accept  = inet_csk_accept,
.ioctl  = tcp_ioctl,
.init = tcp_v4_init_sock,
.destroy  = tcp_v4_destroy_sock,
.shutdown  = tcp_shutdown,
.setsockopt  = tcp_setsockopt, 
}
该结构体描述的是tcp处理各种任务的若干函数,这些任务包括tcp链接的建立、控制等,这些数据都是由sk_buff_head(用于描述套接字缓存区头)结构体管理,数据本身会存在2.4节描述的sk_buff里。这个buffer使用通过proc的slabinfo可以看到,曾在一个嵌入式视频监控设备上就遇到过由于WiFi导致的sk_buff_head和sk_buff不定时异常增大的情况。

struct sk_buff_head {
/* These two members must be first. */
struct sk_buff*next; //下一个数据存放指针
struct sk_buff*prev;//前一个数据存放指针,next和prev会串接成一个双链表,qlen用于标记双链表的长度
__u32 qlen;//标记
spinlock_t  lock; //保护该结构体的锁
};

3.4 sk_buff(SKB)

SKB存储了用户要求传递的数据,这些数据可能源于视频、图像、文本等,应用层传递到TCP/IP协议栈的数据会保存在sk_buff,不论是http还是rtsp,数据会一直存在sk_buff的结构成员中直到从网卡发送出去,接收也是类似的。网络数据包收发如此频繁,可以想象该结构体必然针对协议实现特点、处理流程以及内存等方面做了一些优化。

<include/linux/skbuff.h>

struct sk_buff {
/* These two members must be first. */
struct sk_buff*next; //指向该SKB的后一个SKB,其头就是上面sk_buff_head 指定的成员。
struct sk_buff*prev; //指向该SKB的前一个SKB
ktime_t  tstamp; //数据包到达的时间戳
struct sock  *sk;  //对应的sock成员,即应用程序的socket在内核的代表,
struct net_device*dev;   //网络设备,数据到达的网络设备或者数据离开的网络设备
//control buffer,协议栈很多地方都使用到了这个字段来存储一些会使用到的信息。
char cb[48] __aligned(8);   
unsigned long  _skb_refdst; //目的入口项
#ifdef CONFIG_XFRM
struct  sec_path *sp; //xfrm安全机制使用,Security path。
#endif
unsigned int  len,  //数据实际长度值
data_len;  //数据的长度,和真实长度的区别在于可能有padding
__u16 mac_len, //MAC的长度
hdr_len; //拷贝skb时,可更改的头长度
union {
__wsum  csum;  //校验和
struct {
__u16 csum_start; //校验和计算起始地址
__u16 csum_offset;//从csum_start开始的校验,这部分校验和会被存储。
};
};
__u32 priority; //packet排队的优先级
kmemcheck_bitfield_begin(flags1);
__u8 local_df:1,  //允许本地分片的标志
cloned:1, //标记头是否可能拷贝,如果不对数据执行更改操作,则只会拷贝头。
ip_summed:2, //驱动程序填写的IP层校验和标志。
nohdr:1, //负载使用
nfctinfo:3;//SKB和tcp连接的关系
__u8 pkt_type:3, //packet所属的类
fclone:2, //复制状态标志,标识该SKB是复制的。
ipvs_property:1,//该SKB为ipvs所有。IP virtual Server,负载均衡,netfilter框架调用
peeked:1, //标志标识统计信息是否还要更新
nf_trace:1;//netfilter 包跟踪标志
kmemcheck_bitfield_end(flags1);
__be16  protocol;  //packet所属的协议
void (*destructor)(struct sk_buff *skb);//解析函数
int skb_iif; //该packet所在设备的接口索引
__u32 rxhash; //接收数据包的哈希标志
__u16 queue_mapping; //支持多队列网卡设备的队列映射
kmemcheck_bitfield_begin(flags2);
__u8 pfmemalloc:1;
__u8 ooo_okay:1;
__u8 l4_rxhash:1;
__u8 wifi_acked_valid:1;
__u8 wifi_acked:1;
__u8 no_fcs:1;
__u8 head_frag:1;
sk_buff_data_tinner_transport_header;   //MAC头、IP头、tcp头。前三个是指封装过的。
sk_buff_data_tinner_network_header;
sk_buff_data_tinner_mac_header;
sk_buff_data_ttransport_header;
sk_buff_data_tnetwork_header;
sk_buff_data_tmac_header;
/* These elements must be at the end, see alloc_skb() for details.  */
sk_buff_data_ttail;
sk_buff_data_tend; //数据的相关指针
unsigned char  *head, *data;
unsigned int  truesize;
atomic_t  users;
};

3.5  softnet_data

softnet_data是一个per-CPU变量,即每个CPU都有一个自己的softnet_data结构体,相比只有一个该结构体由多个CPU共享的变量,每个CPU都有一个队列可以减少锁操作。该结构体管理接收和发送的数据。定义于include/linux/netdevice.h文件。

struct softnet_data {
struct Qdisc  *output_queue;  //有数据包要发送的设备。
struct Qdisc  **output_queue_tailp; //上述结构体的待处理的最后一个元素的指针。
struct list_head  poll_list;
struct sk_buff  *completion_queue; //已经成功发送,占用的空间可以释放了。
struct sk_buff_head   process_queue;
/* stats */
unsigned int  processed;   //每一个处理该数据包的进程会将这里的计数器加1,以标记有多少个进程在其sk_buff。
unsigned int  time_squeeze;
unsigned int  cpu_collision;
unsigned int  received_rps;
#ifdef CONFIG_RPS //网卡多队列,Receive Packet Steering,网卡的硬件特性。
struct softnet_data*rps_ipi_list;
/* Elements below can be accessed between CPUs for RPS */
struct call_single_datacsd ____cacheline_aligned_in_smp;
struct softnet_data*rps_ipi_next;
unsigned int  cpu;
unsigned int  input_queue_head;
unsigned int  input_queue_tail;
#endif
unsigned int  dropped;
struct sk_buff_headinput_pkt_queue; //在net_dev_initz中初始化,在网卡驱动程序处理以前,sk_buff链接到该链表上。
struct napi_structbacklog; //NAPI 处理最开始的那两个元素。
};

3.6 struct packet_type

struct packet_type {
__be16  type; /* This is really htons(ether_type). 标记类型,对于IP而言是 cpu_to_be16(ETH_P_IP),*/ 
struct net_device*dev;/* NULL is wildcarded here    */
//该函数是四层网络模型中的网络层的函数,对于ipv4是ip_rcv,这是在之三文章中tcp/ip协议栈的网络层从网络到主机层接收数据包的函数。
int (*func) (struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);   
bool (*id_match)(struct packet_type *ptype,  struct sock *sk);
void *af_packet_priv;
struct list_headlist;
};

netif_receive_skb函数会从ptype_base协议链表上查找和数据包的type对应的func处理程序,对于IP数据包,其类型是ETH_P_IP,服务函数是ip_rcv。此外还有和TCP/IP相关的一些重要数据结构。

3.7 一些名词简称

csk ---connection sock
icsk--- inet connection sock
ca –congestion avoid
cwr congestion window reduction(cwnd reduction)
ECN: Explicit Congestion Notification
SACK:selective ACK
PSH (1 bit) – Push function. Asks to push the buffered data to the receiving application
TIME-WAIT :
(either server or client) represents waiting for enough time to pass to be sure the remote TCP received the acknowledgment of its connection termination request.







本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

第三章 套接字相关数据结构--基于Linux3.10 的相关文章

  • 从 Java 读取 /dev/input/js0

    我正在尝试阅读 dev input js0来自Java 但我不断得到 java io IOException Invalid argument at java io FileInputStream read0 Native Method a
  • 尝试 SSH 时设备的 ioctl 不合适

    我正在尝试通过 SSH 连接几台服务器并尝试获取sudo l每个服务器的输出 下面是我正在执行的脚本 bin bash serverlist tmp servers while IFS read r server netgroup user
  • 将用户添加到组但运行“id”时未反映

    R 创建了一个名为 Staff 的组 我希望能够在不以 sudo 身份启动 R 的情况下更新软件包 所以我使用以下方法将自己添加到员工中 sudo usermod G adm dialout cdrom plugdev lpadmin ad
  • 命令行参数中的“-”(破折号)有什么魔力?

    例子 创建 ISO 映像并将其直接刻录到 CD mkisofs V Photos r home vivek photos cdrecord v dev dev dvdrw 更改到上一个目录 cd 侦听端口 12345 并解压发送到该端口的数
  • 让“git pull”在拉取不同分支时要求确认

    当同时处理许多项目和分支时 我偶尔会犯一些愚蠢的错误 比如拉入错误的分支 例如在分支上master I did git pull origin dangerous code并且有一段时间没有注意到这一点 这个小错误造成了很大的混乱 当我尝试
  • 从 gitlab docker runner 启动声纳扫描仪

    我有一个 CI 工作流程 集成了 linting 作业和代码质量作业 我的 Linting 工作是一个 docker runner 从应用程序代码启动我的 eslint 脚本 然后我的代码质量工作应该启动声纳扫描仪泊坞窗实例 检查我的代码并
  • 如何查找或计算Linux进程的页表大小和其他内核占用?

    我怎样才能知道 Linux 进程页表有多大 以及任何其他可变大小的进程统计 如果您真的对页表感兴趣 请执行以下操作 cat proc meminfo grep PageTables PageTables 24496 kB
  • 是否有我可以运行的操作系统命令来确定是否在基于 Xen 的虚拟机内运行

    我可以在基于 Xen 的虚拟机中运行一个操作系统命令来告诉我它是一个虚拟机而不是物理机 我听说内核对此有一些自我意识智能 例如就像 ps 输出中的额外列之类的 我知道 vmstat 提供了 st 列 但我在运行 Linux 内核 2 6 1
  • Mono 和 WebRequest 速度 - 测试

    在 mono 4 6 2 linux 中 我注意到 wget 下载文件的速度与webclient DownloadString 所以我做了一个小测试来调查 为什么 wget 明显比 C 快 根据我自己的实验 使用 wget 下载 手动读取文
  • 有关 Linux 内存类型的问题

    关于Linux内存我有以下问题 我知道活动内存是最常访问的内存部分 但是有人可以解释一下 linux 如何考虑将内存位置用于活动内存或非活动内存 主动存储器由哪些部分组成 磁盘 文件缓存是否被视为活动内存的一部分 有什么区别Buffers
  • 对 sf:: 的未定义引用

    我想用 C 制作 GUI 应用程序 发现 SFML 是一个不错的选择 幸运的是 我使用的是 Linux 所以 SFML 2 4 已经安装在我的系统上 所以我开始搜索一些教程并找到了一个制作简单窗口的教程 但是当我运行代码时 出现错误 提示未
  • 使用netcat将unix套接字传输到tcp套接字

    我正在尝试使用以下命令将 unix 套接字公开为 tcp 套接字 nc lkv 44444 nc Uv var run docker sock 当我尝试访问时localhost 44444 containers json从浏览器中 它不会加
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • 在 Ubuntu 上纯粹通过 bash 脚本安装 mysql 5.7

    我想要一个无需任何手动输入即可安装 MySQL 5 7 实例的 bash 脚本 我正在关注数字海洋教程 https www digitalocean com community tutorials how to install mysql
  • 将 stdout 作为命令行 util 的文件名传递?

    我正在使用一个命令行实用程序 该实用程序需要传递文件名以将输出写入 例如 foo o output txt 它唯一写入的东西stdout是一条消息 表明它运行成功 我希望能够通过管道传输写入的所有内容output txt到另一个命令行实用程
  • 在中断时获取 current->pid

    我正在Linux调度程序上写一些东西 我需要知道在我的中断到来之前哪个进程正在运行 当前的结构可用吗 如果我在中断处理程序中执行 current gt pid 我是否可以获得我中断的进程的 pid 你可以 current gt pid存在并
  • UDP 广播发送失败:在 Linux 2.6.30 上“网络无法访问”

    我用udp广播写了一个程序 代码段如下 struct sockaddr in broadcast addr socklen t sock len sizeof broadcast addr bzero broadcast addr sock
  • 如何使用ffmpeg重叠和合并多个音频文件?

    我正在尝试将多个音频文件合并到一个文件中 但我可以使用以下命令来连接 而不是连接 ffmpeg v debug i file1 wav i file2 wav i file3 wav filter complex 0 0 concat n
  • 远程linux服务器到远程linux服务器大型稀疏文件复制 - 如何?

    我有两台 CentOS 5 4 服务器 每台服务器上都安装了 VMware Server 假设我始终对 vmware 虚拟机使用稀疏文件 将虚拟机文件从一台服务器复制到另一台服务器的最可靠 最快速的方法是什么 虚拟机的文件复制起来很痛苦 因
  • 使用命令行将 MediaWiki 维基文本格式转换为 HTML

    我倾向于编写大量文档 因此 MediaWiki 格式对我来说很容易理解 而且比编写传统 HTML 节省了我很多时间 然而 我也写了一篇博客 发现一直从键盘切换到鼠标来输入正确的 HTML 标签会增加很多时间 我希望能够使用 Mediawik

随机推荐

  • 4.3 AI识虫比赛

    文章目录 一 查看环境并准备数据 二 启动训练 三 启动评估 计算精度指标 四 预测单张图片并可视化预测结果 五 提升方案 一 查看环境并准备数据 查看当前挂载的数据集目录 该目录下的变更重启环境后会自动还原 ls home aistudi
  • import cv2

    windows下 环境 Python 3 8 5 可以通过一下指令查看 python version 遇到的坑 1 在程序中 import cv2 无报错 但运行程序没有效果 直接程序退出 直到注释掉该句导入 程序才正常测试 直接在命令行中
  • Java版的数据结构——栈和队列

    目录 1 栈 Stack 1 1 概念 1 2 栈的使用 1 3 栈的模拟实现 1 4 栈的应用场景 1 4 1 改变元素的序列 1 4 2 将递归转化为循环 2 队列 Queue 2 1 概念 2 2 队列的使用 2 3 队列模拟实现 2
  • 4G 网络跟 5G 的区别

    1 5G网络的速度据说保守可以达到4G的10 20倍 下载一些大型文件 例如电影 大型电脑游戏 将会是分分钟的事 2 5G网络将会率先使用云RAN和虚拟RAN这样的新架构 以促进一个更加中心化网络的建立 并通过身处网络边缘的本地化数据中心来
  • 微信小程序 getUserProfile直接进入fail函数,getUserProfile调用失败:fail desc length does not meet the requirements

    问题描述 我刚开始的getUserProfile的desc是这么写的 wx getUserProfile desc 获取你的昵称 头像 地区及性别用于信息注册 success res gt console log res console l
  • c语言中函数的声明和定义

    点击上方蓝字关注我 了解更多咨询 1 函数声明 无需实现该函数的功能 函数声明只是一个空壳 不会有特定的函数实现 2 函数定义 必须实现该函数的功能 要实现函数的实现 include
  • 动作/行为识别调研

    动作识别调研 1 简介 1 1 基本概念 1 2 难点 2 人体动作识别系统 2 1 传统方法 2 1 1 iDT框架 2 2 深度学习方法 2 2 1 Two Stream双流架构 2 2 2 3D卷积架构 2 2 3 CNN LSTM架
  • 【C++】匿名对象

    文章目录 一 基本概念 二 使用场景 三 注意事项 一 基本概念 匿名对象 也叫作临时对象 就是创建时不用取名的对象 它的生命周期只有一行 例子 class A int main 创建匿名对象 A 生命周期只有这一行 下一行就自动调用析构函
  • 如何在 seaborn 中创建三角相关热图?

    在本教程中 我们将学习在 seaborn 中创建三角形相关热图 顾名思义 相关性是一种度量 用于显示变量的相关程度 相关热图是一种表示数值变量之间关系的图 这些图用于了解哪些变量彼此相关以及它们之间的关系强度 而热图是使用不同颜色的数据的二
  • css text-shadow

  • 喜讯

    日前 华院计算因其在AIGC领域的技术突破和创新成果入选数据猿 2023中国AIGC领域最具商业合作价值企业盘点 基于其数智人产品及解决方案 为不同细分场景 行业 领域提供交互式智能终端 虚拟直播平台和智能视频生成平台等产品及服务 凭借其在
  • 【PKMS】- Settings中应用详情页卸载还原系统应用但数据未清除

    PKMS Settings中应用详情页卸载还原系统应用但数据未清除 一 问题描述 最近工作中出现一个问题 系统应用卸载后重装还原发现应用数据还在 复现操作 1 系统预置该应用在system priv app下 手机里预置的是旧版本的该应用
  • 隐私计算 FATE - 多分类神经网络算法测试

    一 说明 本文分享基于 Fate 使用 横向联邦 神经网络算法 对 多分类 的数据进行 模型训练 并使用该模型对数据进行 多分类预测 二分类算法 是指待预测的 label 标签的取值只有两种 直白来讲就是每个实例的可能类别只有两种 0 或者
  • calico单个pod固定IP多pod固定ip池

    原理 主要利用calico组件的两个kubernetes注解 1 cni projectcalico org ipAddrs 2 cni projectcalico org ipv4pools 单个pod固定IP 利用注解cni proje
  • SpringSecurity实现OAuth2.0 - 基础版授权服务

    OAuth2 0协议 OAuth3 0概述 OAuth2 0是一个关于授权的开放网络协议 该协议在第三方应用与服务提供平台之间设置了一个授权层 第三方应用需要服务资源时 并不是直接使用用户帐号密码登录服务提供平台 而是通过服务提供平台的授权
  • Python求100以内的素数和并输出

    求100以内的素数并输出 def isPrime num for i in range 2 num if num i 0 return False return True sum 2 1不是素数 2是素数 对 3 100 内的整数逐一进行判
  • Sublime Text 3 tab快捷键失效解决办法

    快速搭建html框架快捷键 tab发现失效 查资料发现缺少Emmet插件 解决办法如下 1 Ctrl Shift P 搜索package control install 2 按下回车搜索emmet 3 安装emmet 4 安装完成后可通过P
  • 【第01题】A + B

    文章目录 零 写在前面 一 例题1 1 题目描述 2 解题思路 3 代码详解 二 例题2 1 题目描述 2 解题思路 3 代码详解 三 例题3 1 题目描述 2 解题思路 3 代码详解 四 例题4 1 题目描述 2 解题思路 3 代码详解
  • Unity 简单几句代码实现无限循环列表(Scroll View)

    先看效果 这里是Scroll View的设置 using System Collections using System Collections Generic using UnityEngine using UnityEngine UI
  • 第三章 套接字相关数据结构--基于Linux3.10

    本章是对socket通信过程中使用到的比较重要的据结构罗列和意义的阐述 在阅读其它层的代码前 先来看几个重要的数据结构 这几个数据结构贯串四层模型 3 1 socket对应的内核结构体 在用户空间使用socket 函数创建一个套接字 对应的