这里以教科书版的视角去解读。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 应用层(Application) | http Telent Ftp SMTP SMTP NFS
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 表示层(Presentation layer)| JPEG ASCII GIF DES MPEG
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 会话层(session) | SQL RPC NFS
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 传输层(transport) | TCP UDP SPX
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 网络层(network) | IP IPX
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 数据链路层(link) | MAC (媒介访问控制) LLC(逻辑链路控制)
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ PPP ATM IEEE802.3/2
^
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 物理层(physical) | RS-232 RJ-45 FDDI
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
物理层:提供物理通路,二进制数据传输、 定义机械 电气特性和接口 比特流
链路层: 数据链路的释放、流量控制、 构成链路数据单元、差错的检测与恢复、 帧界定与同步、传送以帧(frame)为单位的信息 数据帧
网络层:路由的选择与中继 网络链接的激活与终止 网络链接的多路复用、差错的检测与恢复 、排序与流量的控制、服务选择 数据包
传输层:映射传输地址到网络地址、传输链接的建立与释放、多路复用与分割、差错控制与恢复、分段与重组、组片与分片、序号及流量控制 信息报文
会话层:: 会话链接到传输链接、会话链接的恢复与释放、会话参数的协商、服务选择、活动管理与令牌管理、数据传输 同上
表示层:数据语法的转换、数据加密与数据压缩、语法表示与链接管理 同上
应用层: 用户应用程序执行任务所需的协议与功能 同上
原因还是非常的简单,对指针的理解不透彻。 是这样的,在一个字符串中,有大小写的字符,请将其中的大写字母转化为小写字母,让你们见笑了。
char* toLowerCase(char* str) {
int len = strlen(str);
int i;
/* 第一种情况: */
for(i = 0; i < len; i++){
if(str[i] >= 'A' && str[i] <= 'Z')
str[i] = str[i] + 32;
}
return str;
使用指针,这里有个问题:
char *p = str;
while(*p){
if(*p >= 'A' && *p <= 'Z')
*p = *p + 32;
p++;
}
p = p - len;
return p;
你如果想要返回字符指针也就是p,必须将指针调整回原头步,即减去移动的长度,也可以直接返回str.
char* toLowerCase(char* str) {
int len = strlen(str);
while(*str){
if(*str >= 'A' && *str <= 'Z')
*str += 32;
str++;
}
str = str - len;
return str;
}
其中,way three比way two 快太多了
目前,leetcode的解题思路都是运用使用python、java、c++等语言,为啥呢? 因为简单啊,一些现用的库函数拿起来就是用很爽的,但是,我的思路先用pure c 啃完大部分题目,即便是自己造轮子,这个时候就是学习积累,工作中当然使用现成的 标准库了。
也许leetcode从测试的角度来考虑在线提交的代码,对于c来说有点变态,也许是自己没有 考虑全面。但是,强如内核都没见这样的使用案例,下面是错误汇总。
下面是引自leetcode的官方手册:
/*
The input [1,null,2,3] represents the serialized format of a binary tree using level order traversal, where null signifies a path terminator where no node exists below.
We provide a Tree Visualizer tool to help you visualize the binary tree. By opening the console panel, you should see a Tree Visualizer toggle switch under the TestCase tab. Click on it and it will show the test case's binary tree representation.
5
/ \
1 4
/ \
3 6
代表:[5,1,4,null,null,3,6]
也就是树的遍历为层次遍历,如果节点为空,则使用null.而且,还注意:
[]
Empty tree.
The root is a reference to NULL (C/C++), null (Java/C#/Javascript), None (Python), or nil (Ruby).
这个错误太突然了,貌似是在某个时间点才引入这个检查。bug 重现:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
};
作为一个定义很常见的代码。 但是,以convert-sorted-array-to-binary-search-tree为例:
struct TreeNode *sortedArrayToBST(int *nums, int numsSize)
{
struct TreeNode *root = (struct TreeNode *)malloc(sizeof(struct TreeNode));
// root->left = NULL;
// root->right = NULL;
// root->val = NULL;
int head = 0;
int tail;
if (numsSize >= 1) {
tail = numsSize - 1;
toBST(root, nums, head, tail);
}
else
return root = NULL;
printf("trace\n");
//show(root);
return root;
}
也就是说,上面的代码在提交的时候,就会报上面的错误。当你申请一个带指针成员的结构体时,一定要在 使用前初始化他,貌似这个规定内核中也不常见啊。 改正的方法就是注释掉的语句,将里面的指针成员初始化为NULL;
如果像上面的代码中,怎么处理一个空的树,如果直接
return root;
那么结果很有可能不正确,在我的代码中,提交后会明显看到(输入[]),输出[-122541545465] 明显是个垃圾值,正确的处理方式是
return root = NULL;
我一开始还把输入和输出的结果考虑全面了,其实是不用的,比如,结果要求
[“1->2->3”, “1->5”] 实际你不用管开始和结尾的”[“或者’]’符号,只需把字符串存入一个地方,并能读取出来就行。
这也是我不经意间发现的,就是你的输出结果不必和给出的案例一致,我估计这是为什么使用”[]”的原因。
之前一直在寻找快速开发linux kernel的方法,有兴趣的同学们可以参考kernel系列文章。众所周知,kernel的开发不同于用户空间的程序,一个是本身系统的复杂性,众多子系统需要一名合格的内核开发者去掌握;二是编译内核程序的复杂性,除了编写module程序。但是我相信大多数同学经历过自己编译内核的经历,以满足自身的需要。以前我在想,怎么才能让编译内核快一些,无论是时间还是空间,其中,基于libvirt的qemu是最符合我这个要求的,请参看本文。这个方法的思路是安装一个无图形界面的debian系统,然后使用make deb-pkg
,生成*.deb包,这样就可以测试你自己的kernel程序,这种方法可以,但是重新编译了整个内核,这还不是最痛苦的,最痛苦的地方在于它会生成5个包,其中包含一个gdb调戏信息的内核镜像,眼见的消耗时间是单个vmlinux*4的数量可以,但是笨重。
还有这篇here
其中,这个链接下面还会再次提到,因为这个涉及到了qemu,本篇会继续使用这个工具。
直到今日,本人终于找到了一个理论上最完美的一个方案,之所以这么说,是因为:一,它就是我梦中最理想的方案,几乎与我想象的一模一样,当然,我也只能想象了,行动并没有实施;二,基本再没有提高的空间,对,就是这样,没有了。
我把我的构思给大家提前分享下:
你只需重新编译很少的选项,嗯,如果只是测试某些程序,交互就用ssh就可以了,并不需要一些硬件资源,比如,键盘、屏幕、鼠标、无线…也就是最小量的编译选项,仅仅这一点,就大大节省了时间和空间。
用户空间的程序可以重用,也就是安装内核后可以接着使用原来的工具,按道理说这个要求绝大多数的编译内核都会满足。但是,我希望不借助重新启动进入新的内核去使用这些,这又节省了时间。
好了,仅凭上面的两点,我相信此方案绝对就可以独领风骚了。
这个是什么请自己google,这篇文章的第一个链接就是这个项目的介绍。
这里涉及到了kbuild的一些细节,其实也可以不使用这个,但是,使用没有坏处。
前期编译好qemu,一定对应自己的平台,可以自己私自修改。
export KBUILD_OUTPUT=$HOME/src/kernel-build
这个(可能需要提前创建需要的目录),这个目录下就把源代码进行了一份拷贝并生成了可执行文件,最后组成了一个镜像文件,简而言之就是和主目录的内容一样,只不过在另外一个目录下也有同样的内容。
minimal-configuration
就可以生成最小量的.config
.sudo make modules_install install {INSTALL_MOD_PATH,INSTALL_PATH}=$HOME/src/kernel-dev
也就是说,此时你在$HONE/src
下:
yubo@debian:~$ ls src/
kernel-build kernel-dev
其中,kernel-dev下是
yubo@debian:~$ ls src/kernel-dev/
config-5.0.0-rc7+ lib System.map-5.0.0-rc7+ vmlinuz-5.0.0-rc7+
其实,这也是一份来自/boot
的拷贝。至此,前期的准备工作已经完成的差不多了,其中,我可能完全不会KBUILD的使用方案,请朋友们指正。
eudyptula-boot
脚本去启动自己编译好的内核:yubo@debian:~/git/configure_file/kernel-fast-dev$ ./eudyptula-boot --kernel ~/src/kernel-dev/vmlinuz-5.0.0-rc7+
[✔] All dependencies are met.
[✔] Found kernel 5.0.0-rc7+.
[✔] Kernel configuration checked. overlayfs present.
[✔] Modules are in /home/yubo/src/kernel-dev/lib/modules/5.0.0-rc7+.
[∗] TMP is /tmp/tmp.0NkeE3lzn9.
[✔] initrd built in /tmp/tmp.0NkeE3lzn9/initrd.gz.
[∗] Start VM eudyptula-5-0-0-rc7+.
[∗] GDB server listening on /tmp/tmp.0NkeE3lzn9/vm-eudyptula-5-0-0-rc7+-gdb.pipe.
[∗] monitor listening on /tmp/tmp.0NkeE3lzn9/vm-eudyptula-5-0-0-rc7+-console.pipe.
[∗] ttyS1 listening on /tmp/tmp.0NkeE3lzn9/vm-eudyptula-5-0-0-rc7+-serial.pipe.
[ 0.810771] mce: Unable to init MCE device (rc: -5)
[∗] initrd started.
[∗] Loading modules.
[✔] Configuration loaded.
[✔] Root file system setup.
[✔] /tmp, /run and others are clean.
[∗] Change root.
[✔] /proc and /sys setup.
[✔] /root mounted.
[✔] /lib/modules mounted.
[…] Starting udev... starting version 232
[✔] udev started.
[✔] Network configured.
[∗] Setup terminal.
[✔] Terminal size is 80×23.
[∗] QEMU PID is 28311.
[∗] Spawning a shell.
其中,请注意
[∗] GDB server listening on /tmp/tmp.0NkeE3lzn9/vm-eudyptula-5-0-0-rc7+-gdb.pipe.
这个语句可以用来调试内核的。 看到没有,已经启动了一个VM,可以看一下内核版本:
root@eudyptula-5-0-0-rc7+:~/git/configure_file/kernel-fast-dev# uname -r
5.0.0-rc7+
大家发现了没有,我们在主操作系统中开了一个镜像进程,而且这个内核居然可以使用原来用户空间的程序。
经过上面的准备,我们要对修改的代码进行验证才可以。 教材 这个文章就是根据这篇改编过来。
这个部分是我后来补写的,那么,gdb server
的信息为
[∗] GDB server listening on /tmp/tmp.Aec21mkPjO/vm-eudyptula-5-0-0-next-20190306-00003-g801cbc0c69c2-dirty-gdb.pipe.
vmlinux
可以是你内核代码源目录下的那个,也可以是~/src/kernel-dev/lib/build/vmlinux
文件。gdb vmlinux
GNU gdb (Debian 7.12-6) 7.12.0.20161007-git
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from vmlinux...done.
warning: File "/home/yubo/git/linux/scripts/gdb/vmlinux-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /home/yubo/git/linux/scripts/gdb/vmlinux-gdb.py
line to your configuration file "/home/yubo/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/home/yubo/.gdbinit".
For more information about this security protection see the
---Type <return> to continue, or q <return> to quit---
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
(gdb)
(gdb) target remote | socat UNIX:/tmp/tmp.6pDwCfUhbz/vm-eudyptula-5-0-0-next-20190306-00003-g801cbc0c69c2-dirty-gdb.pipe -
Remote debugging using | socat UNIX:/tmp/tmp.6pDwCfUhbz/vm-eudyptula-5-0-0-next-20190306-00003-g801cbc0c69c2-dirty-gdb.pipe -
__read_once_size (size=<optimized out>, res=<optimized out>, p=<optimized out>)
at ./include/linux/compiler.h:197
197 __READ_ONCE_SIZE;
(gdb)
注意,我的监听地址变化了好几次,请注意。注意上面的地址。 有什么问题大家可以问我,谢谢大家
在github上产生pull-request请求后,还需要你能够及时的sync原来的仓库,要不然 你克隆的仓库就失去了价值,无法继续进行相应的开发,下面讲讲我的心得.
对,当你fork一个仓库后,就会在你的github主页上产生一个你fork的备份。以这个为例,单击一下fork
后,回到你的主页就会显示相应的仓库,这也是你产生pull request
的第一步。
#1 fork https://github.com/netoptimizer/prototype-kernel on the origin page
git clone https://github.com/yuzibo/prototype-kernel.git
#2 这儿就是你克隆自己fork的仓库
所谓的上游仓库就是你刚才fork的原来的仓库,添加一个upstream
的标签,这个就是为了同步用的。
git remote add upstream https://github.com/netoptimizer/prototype-kernel.git
接着使用命令:
yubo-2@debian:~/git/yubo-prototype$ git remote -v
origin https://github.com/yuzibo/prototype-kernel.git (fetch)
origin https://github.com/yuzibo/prototype-kernel.git (push)
upstream https://github.com/netoptimizer/prototype-kernel.git (fetch)
upstream https://github.com/netoptimizer/prototype-kernel.git (push)
更新上游的最新修改,保存在本地的upstream/master
分支。
yubo-2@debian:~/git/yubo-prototype$ git fetch upstream
remote: Enumerating objects: 1, done.
remote: Counting objects: 100% (1/1), done.
remote: Total 1 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (1/1), done.
From https://github.com/netoptimizer/prototype-kernel
* [new branch] master -> upstream/master
git checkout master
从你刚才的upstream/master
分支合并最新最全的内容到master
分支,并且不会修改你在master
分支所做的目录。
yubo-2@debian:~/git/yubo-prototype$ git merge upstream/master
Updating ae6f3eb..a94339c
Fast-forward
kernel/Documentation/bpf/ebpf_maps_types.rst | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
你这个时候就可以把上游的变化推进到github账户去了,接下来就可以产生相应的pull request
了。
git push origin master
这里需要注意就是你要推送到哪个分支,这里就是主分支,与产生pull request的分支是不一样的,请注意一下.
Use the Kubernetes command-line tool, kubectl, to deploy and manage applications on Kubernetes. Using kubectl, you can inspect cluster resources; create, delete, and update components; look at your new cluster; and bring up example apps.
kubectlhere很明显不能通过正常途径下载成功,只能使用github的二进制文件。 github选择Current release,点击进去选择Dowdloads for v1.14.0, 也就是你刚才看到的current release版本中的Client Binaries. 选择对应的系统版本。然后就是解压,将”/bin”文件中的kubernets的kubectl可执行文件mv到/usr/local/bin文件夹下。
kubectl version
Client Version: version.Info{Major:"1", Minor:"14", GitVersion:"v1.14.0", GitCommit:"641856db18352033a0d96dbc99153fa3b27298e5", GitTreeState:"clean", BuildDate:"2019-03-25T15:53:57Z", GoVersion:"go1.12.1", Compiler:"gc", Platform:"linux/amd64"}
The connection to the server localhost:8080 was refused - did you specify the right host or port?
这样就是ok的了。
here,还是那个问题,现在应该切换到github 我使用的是.deb包,这里你也可以使用
yubo@debian:~/cilium$ minikube version
minikube version: v1.0.0
Goal of minikube: Our goal is to enable fast local development and to support all Kubernetes features that fit. We hope you enjoy it!