0

点赞

0

回复

544

浏览

Linux守护进程

1 守护进程是什么? 在Linux/UNIX系统引导的时候会开启很多服务,这些服务称为守护进程(Daemon进程)。守护进程是脱离于控制终端并且在后台周期性地执行某种任务或等待处理某些事件的进程,脱离终端是为了避免进程在执行过程中的信息在任何终端上显示并且进程也不会被任何终端所产生的中断信息所终止。 2 创建守护进程步 2.1 创建子进程,退出父进程 为了脱离控制终端需要退出父进程,之后的工作都由子进程完成。在Linux中父进程先于子进程退出会造成子进程成为孤儿进程,而每当系统发现一个孤儿进程时,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程。 2.2 在子进程中创建新的会话 setsid函数作用:用于创建一个新的会话,并担任该会话组的组长。调用setsid有3个作用 1. 让进程摆脱原会话的控制; 2. 让进程摆脱原进程组的控制; 3. 让进程摆脱原控制终端的控制; 使用setsid函数的目的:由于创建守护进程的第一步调用了fork函数来创建子进程再将父进程退出。由于在调用fork函数时,子进程拷贝了父进程的会话期、进程组、控制终端等,虽然父进程退出了,但会话期、进程组、控制终端等并没有改变,因此,这还不是真正意义上的独立开了。使用setsid函数后,能够使进程完全独立出来,从而摆脱其他进程的控制。 2.3 改变当前目录为根目录 使用fork创建的子进程继承了父进程的当前的工作目录。由于在进程运行中,当前目录所在的文件系统是不能卸载的,这对以后的使用会造成诸多的麻烦。因此,通常的做法是让根目录”/”作为守护进程的当前工作目录。这样就可以避免上述的问题。如有特殊的需求,也可以把当前工作目录换成其他的路径。改变工作目录的方法是使用chdir函数。 2.4 重设文件权限掩码 文件权限掩码:是指屏蔽掉文件权限中的对应位。例如,有个文件权限掩码是050,它就屏蔽了文件组拥有者的可读与可执行权限(对应二进制为,rwx, 101)。由于fork函数创建的子进程继承了父进程的文件权限掩码,这就给子进程使用文件带来了诸多的麻烦。因此,把文件权限掩码设置为0(即,不屏蔽任何权限),可以增强该守护进程的灵活性。设置文件权限掩码的函数是umask。通常的使用方法为umask(0)。 2.5 关闭文件描述符 用fork创建的子进程也会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读写,但它们一样消耗系统资源,而且可能导致所在的文件系统无法卸载。在使用setsid调用之后,守护进程已经与所属的控制终端失去了联系,因此从终端输入的字符不可能达到守护进程,守护进程中用常规方法(如printf)输出的字符也不可能在终端上显示出来。所以,文件描述符为0、1、2(即,标准输入、标准输出、标准错误输出)的三个文件已经失去了存在的价值,也应该关闭。 2.6 守护进程退出处理 当用户需要外部停止守护进程时,通常使用kill命令停止该守护进程。所以,守护进程中需要编码来实现kill发出的signal信号处理,达到进程正常退出。 3 DEMO include include include include // open include include include include include define MAXFILE 65535 volatile sig_atomic_t _running = 1; int fd; // signal handler void sigterm_handler(int arg) { } int main() {  / 屏蔽一些有关控制终端操作的信号   防止在守护进程没有正常运转起来时,因控制终端受到干扰退出或挂起   /  signal(SIGINT,// 终端中断  signal(SIGHUP,// 连接挂断 // 终端退出 // 向无读进程的管道写数据 // 后台程序尝试写操作 // 后台程序尝试读操作 // 终止  // test // try cmd: ./test kill s SIGTERM PID  // 1 fork child process and exit father process  if(pid 0)  {    }  // 2 create a new session  // 3 set current path  if(getcwd(szPath, sizeof(szPath)) == NULL)  {      }  else  {      }  // 4 umask 0  // 5 close useless fd i ++i) i ++i)  {    }  // 6 set termianl signal  // open file and set rw limit  if((fd = open("outfile", O_CREAT|O_WRONLY|O_APPEND, 0600)) 0)  {      }  // do sth in loop  while(_running)  {   if (write(fd, buf, strlen(buf)) != strlen(buf))   {            }  // 1 s  }  // print data  if((fd = open("outfile", O_RDONLY)) 0)  {      }  if(read(fd, szBuf, sizeof(szBuf)) == 1)  {      } } /    gcc Wall g o test test.c    ps ux | grep v grep | grep test    tail f outfile    kill s SIGTERM PID   /   ...

linuxprocessdaemon

0

点赞

0

回复

637

浏览

rpm、dpkg、yum、apt-get详解

在Linux下进行软件安装或者升级的时候,往往会Google到一些安装命令,包括 apt get install dpkg i yum install 等等 执行之后软件安装了,也知道是在线安装了软件,但是这些命令背后做了什么,以及相互之间的关系和区别是什么?这是不清楚的,趁着清明写个博文总结之。 1 TARBALL(源码编译安装) 这是最早的软件安装方式,即通过源代码编译安装。所谓的 Tarball 文件,其实就是将软件的所有原始码文件先以 tar 打包,然后再以压缩技术来压缩。 Tarball 是一个软件包, 解压缩之后,里面的文件通常就会有:原始程序码文件;侦测程序文件 (可能是 configure 或 config 等档名);本软件的简易说明与安装说明 (INSTALL 或 README)。 一般通过: ./configure prefix= with ...

yumrpmdpkglinuxapt-get

0

点赞

0

回复

557

浏览

Linux下的多进程通信

1 IPC综述 1.1 IPC是什么? 进程间通信就是在不同进程之间传播或交换信息,那么不同进程之间存在着什么双方都可以访问的介质呢?进程的用户空间是互相独立的,一般而言是不能互相访问的,唯一的例外是共享内存区。但是,系统空间却是“公共场所”,所以内核显然可以提供这样的条件。除此以外,那就是双方都可以访问的外设了。在这个意义上,两个进程当然也可以通过磁盘上的普通文件交换信息,或者通过“注册表”或其它数据库中的某些表项和记录交换信息。广义上这也是进程间通信的手段,但是一般都不把这算作“进程间通信”。因为那些通信手段的效率太低了,而人们对进程间通信的要求是要有一定的实时性。 1.2 IPC的目的 进程通信有如下一些目的: 1. 数据传输:一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 2. 共享数据:多个进程想要操作共享数据,一个进程对共享数据的修改,别的进程应该立刻看到。 3. 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。 4. 资源共享:多个进程之间共享同样的资源。为了作到这一点,需要内核提供锁和同步机制。 5. 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。进程通信 Linux 进程间通信(IPC)以下以几部分发展而来:早期UNIX进程间通信、基于System V进程间通信、基于Socket进程间通信和POSIX进程间通信。 1. UNIX进程间通信方式包括:管道、FIFO、信号。 2. System V进程间通信方式包括:System V消息队列、System V信号灯、System V共享内存 3. POSIX进程间通信包括:posix消息队列、posix信号灯、posix共享内存。 1.3 现有LINUX IPC方式 1. 管道(pipe) 2. 有名管道(FIFO) 3. 信号(signal) 4. 消息队列 5. 共享内存 6. 信号量 7. 套接字(socket) 2 IPC技术详解 2.1 无名管道 管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的道端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。管道主要用于不同进程间通信。 创建一个简单的管道,可以使用系统调用pipe()。它接受一个参数,也就是一个包括两个整数的数组。如果系统调用成功,此数组将包括管道使用的两个文件描述符。创建一个管道之后,一般情况下进程将产生一个新的进程。代码如下所示 include ...

linux进程通信多进程

1

点赞

1

回复

835

浏览

又拍云首席架构师张聪谈《操作系统革命 Revolution OS 》

张聪早在小学就拥有了属于自己的电脑,这并非父母对儿子的未来高瞻远瞩或自身热爱互联网,而是由于他们买了张聪的学习光盘却没地方播放。张聪的小学、初中、高中最爱干的事情,就是体验不同的软件。他甚至在“天空软件站”的每个分类内,挨个下载相似软件,然后找到最适合自己的。 对不同软件的好奇连带着对计算机的好奇,让张聪在高考前就确定了大学专业的方向——计算机科学与技术。“读大学以前,我身边真正了解计算机的人特别少,可以说几乎没有。那时候我虽然喜欢计算机,但视野非常窄。”张聪说, “回过头看,我觉得一个人的视野非常重要,而纪录片《操作系统革命 Revolution OS 》就是一部打开我视野的佳作。” 上大学后的张聪在学长的介绍下知道了 Linux 操作系统,完全开源的操作系统迷住了张聪。他在搜索 Linux 相关内容时,找到了它的开创者 Linus Torvalds,继而发现 Linus Torvalds的自传《 Just for fun 》。阅读完这本书后,张聪被优秀程序员做事专注、带人温和、坚持不懈以及不断创新的特质所感动。随后发现 J.T.S. Moore 参照此书,在 2001 年拍摄了纪录片《操作系统革命 Revolution OS 》。 谈及收获,张聪想了想说,《操作系统革命 Revolution OS 》给了他三点启发。首先,影片向他打开了计算机世界的大门,使得他对 Linux 相关的技术更加感兴趣,片中一些提及的知识点,相关的事件背后,会有 paper 和书籍去支撑,”所以我在看完影片后,继续寻找了相关书籍来阅读。“张聪回忆道。 其次,他对开源软件和商业授权软件的看法有了不同的认识。此前的张聪并没有特别注重版权意识,也并不真正关心开源软件和商业授权软件的区别。《操作系统革命 Revolution OS 》让他了解到,开源软件在基础层面快速推进了整个技术的发展,而商业授权软件在更贴近消费者的层面引领着技术的走向。 简单说,适宜于各项技术滋长的土壤即是开源软件,它的共享性质让大家能更快的开始种植自己需要的成果。行业顶尖的技术人员开发出软件被授权就好像出售打包的成品,如果消费者不花钱去消费,成果就会因为无人买单而渐渐凋零,这是一个完整的生态链。 更重要的是,这部纪录片间接影响了张聪日后的择业方向。”受这部影片启发,我在随后了解了大量计算机行业相关信息,发现自己更加喜欢做底层的建设,如果说面对消费者的终端是最终的树叶,我更加想知道这棵树的根部是怎么样的,如何影响树叶的生长,这也是为什么我现在正在从事系统开发工程师的工作。” 11 月 28 日,张聪将出席了“ UPYUN 架构与运维大会『北京站』”,进行了主题为《ngx_lua 在 UPYUN 的实践》的精彩演讲。 查看&下载他的分享课件请访问: 《ngx_lua 在 UPYUN 的实践》 http://lock522.b0.upaiyun.com/zc.pdf —— 本文整理自张聪的口述—— 张聪 UPYUN 首席架构师 系统开发工程师,C / Lua 程序员,目前主要负责 UPYUN CDN 相关的设计和开发工作,兼部分 UPYUN 分布式存储系统相关的运维工作 在 NGINX C 模块和 OpenResty / ngx_lua 模块的开发和维护方面有一些经验积累,同时热衷于推动公司内部的测试及运维自动化。崇尚简单实用的工程实践,用程序去解决问题。 ...

操作系统革命-revolution-oslinux架构师

1

点赞

2

回复

858

浏览

常见Linux命令

这是一篇手册文章,总结了常用的linux命令,以及它们的一些常用参数和场景。 SOURCE 执行某个文件,效果等同于 . ,都是在当前进程的上下文执行。 BASH 以bash执行某个文件,作为子进程。 x 参数可以查看调试信息。 GDB 用来调试C程序,打开一个调试: gdb a.out...

linuxbash

0

点赞

0

回复

693

浏览

UPYUN 运维总监谈bLinux学习

“我在 98 年下半年才拥有了第一台电脑,那个时代的稀罕玩意儿,最适合有整块整块的时间和自由,但又不想浪费大好青春的大学生活。”邵海杨说完这句话,身体往座椅一靠,眼中若有所思。 邵海杨是 UPYUN 的运维总监,业界知名的资深系统运维架构师。 当谈到自己与电脑“结缘”的最初时光,他的话匣子一下就打开了。很显然,即便这些已算得上久远,但对他来说仍是记忆犹新。 他透露,自己对电脑的热爱源于高中学五笔打字。那时,海杨打了一手好五笔,上了大学发现竟然没几个人会,而当时的全国计算机二级考试,主要的一项就是五笔打字。 为很多同学“代打”了之后,海杨收获了不少崇敬的目光。“当时隐隐觉得自己是喜欢电脑的,得到别人的肯定以后,坚定了自己的想法。”海杨笑道,“于是就拼命攒钱,自己钻研了半年的电脑报,最终说服父母,给我买了一台。”当年电脑的 cpu 要用砂皮打磨,显卡和显示器都是二手的,内存才 64M,价格却贵得要命。 海杨的大学是在桂林读的机电工程(万金油专业),相比起一线城市和沿海城市,桂林的生活比较闭塞清静,出生并成长在浙江的海杨深深体会到了这一点。当 98 年下半年,他同学在美国读书工作搞 IT 的表哥到桂林游玩并探望他同学的时候,带来的海量前沿消息让海杨大为新奇,并且带来了一句奠定海杨日后事业走向的话:在美国, Linux 非常火 。 出于对留学美国的人的羡慕以及自己体会到的信息闭塞,使得海杨一下就把这句话记在了心里。随后他和同学两人跑遍整个桂林,终于买到了安装 Linux 的盘。“这里还有个小插曲,当时卖光碟的老板信誓旦旦的说,这张盘一定是正版,后来我们都知道 Linux 本身是一套免费使用和自由传播的系统,根本不存在正版盗版之说。老板也是为卖光盘杀红了眼,哈哈。” 邵海杨认为自己是一个喜欢与众不同、新奇事物的人,也特别喜欢一个人旅游。他回忆说,当初会坚持玩 Linux ,有一部分是因为 windows 系统已经满大街都是,而 Linux 够小众。他不禁感慨了一番“当年慢”的味道,输入一条代码和命令,就可以看到黑屏白字,一行行信息在眼前慢慢移动。“仿佛就是告诉你,我现在正在努力工作呢,这感觉非常酷。”海杨情不自禁的笑起来。 海杨的大学由于地处偏远,氛围非常的纯净。没有花花世界的干扰,他一头钻进了 Linux 中,不可自拔。当年有关 Linux 的书籍非常少,他不得不借与 Unix 相关的书籍研读,而手抄笔记本就是在那时诞生的。 海杨在手抄笔记本上摘录下了每一个他不懂的知识点,想要编写的程序等。“那时由于电脑都不联网,也不需要对别人提供服务,基本上是自己嗨,找资料把各种服务都实现一遍,编译内核,打补丁,想怎么折腾就怎么折腾。借此真的学到了很多。” 说到这,海杨移近了身子,半认真道,“我现在回头想,觉得大学里就应该学习知识,这是最重要的。当年由于不能上网,我们有不懂的知识点,会去网吧包通宵查找相关的资料,大学里得到的这笔财富,足以令我受益终生。” 如今,这本手抄笔记本静静的躺在邵海杨家里的书架上,它几乎代表了海杨整个闪光的青春年少,也因此成为了他的独一珍宝。 11 月 28 日,邵海杨将出席“ UPYUN 架构与运维大会·北京站”,作为三个分会场之一的“高性能运维专场”的出品人,他将负责会场的全程主持,并发表《 云运维的启示和架构设计 》的主题技术实战分享 ,讲述 UPYUN 从草根创业到如今三千台服务器的部署、架构、管理的实践,并附带上人员互备、高效团队建设的小彩蛋。 “UPYUN 架构与运维大会·北京站”的详情请&报名参会请访问: 2015 架构与运维的年度大趴! http://upyun archops beijing.eventdove.com/ ...

linux技术职涯运维

0

点赞

0

回复

1427

浏览

优雅地使用命令行:Tmux 终端复用

你是否曾经开过一大堆的Terminal?有没有把它们都保存下来的冲动?Tmux 的Session就是做这件事情的!你可以随时退出或者进入任何一个Session。每个Session有若干个Window,每个Window又可以分成多个窗格(Pane)。 即使iTerm/Terminal/Konsole意外关闭也没关系。Session可以完全恢复!但是关机就不可以了,不过你可以写脚本来恢复! Tmux是一个终端复用软件,BSD协议发布。一般用于在一个命令行窗口中访问多个命令行会话,或者在一个命令行终端中同时使用多个程序。Tmux用起来是怎样的呢?看图: Tmux 最经典的使用场景便是用 Tmux+Vim 来做一个IDE,其中Vim部分的配置过程记录在了 这里 http://harttle.com/2015/11/04/vim ide.html ,本文介绍Tmux的配置和使用。 ITERM的窗格和TMUX有什么区别? iTerm是一个GUI软件,它的窗格只是窗格而已!而Tmux是终端复用,在一个命令行窗口中不仅可以显示多个Shell的内容,而且可以保持多个会话。 最重要的是:Tmux和Vim一样,属于字符终端软件,不需要任何GUI的支持,在远程登录时尤其有用。 TMUX和SCREEN有什么区别? 这两个都是做终端复用的,我在阿里云ECS上 搭建Node.js API服务器 http://harttle.com/2015/02/24/node web api.html 时用过 screen ,它是GNU软件,而Tmux是BSD的协议。 它们最主要的区别是Tmux支持Vi/Emacs风格的键盘映射,更好的接口和文档,以及更好的脚本控制。所以建议使用Tmux! 安装TMUX OSX brew install tmux...

linuxvimtmux

0

点赞

1

回复

2513

浏览

用 Vim 来打造自己心仪的 IDE

一年前我从Vim切换到了WebStorm,是因为WebStorm强大的重构功能,以及Super Search功能。涉及多文件编辑和重构时WebStorm的优势便非常明显。 最近到手了HHKB,从键盘到触摸板的切换还是挺麻烦的,于是Vim编辑的需求又来了。。加之WebStorm经常假死,我决定重新启用Vim。同时重新打造了我的Vim,使它能够满足我在IDE中的所有需求。这篇文章便来记述整个过程,或许有些帮助。先上图: 上图中,下面的Console是通过Tmux搞的。Tmux的配置和使用参见: 优雅地使用命令行:Tmux终端复用 http://harttle.com/2015/11/06/tmux startup.html 。 准备工作 安装Git、Homebrew(如果你是Mac),并安装新版本的Vim( =7.3)。一般linux发行版都会预装Vim,你需要检查一下vim的版本: $ vim version...

idelinuxvim

新建主题 记录代码

学员动态

  • N**i向课程作业中提交了代码
  • B**N向课程作业中提交了代码
  • N**i向课程作业中提交了代码
  • g**g添加了笔记:方法的返回值和参数构...
  • B**N向课程作业中提交了代码
  • S**S评论了f**n在课程中的作业:File file ...
  • y**_向课程作业中提交了代码
  • f**o在课程作业中回复了老师:作业截...
  • 2**b在课程作业中回复了老师:老师,这题没有头绪啊...
  • w**3评论了幻**梨在课程中的作业:题目说是建立一个Li...
  • S**S回复了k**e在课程中的问题:编译错误 检查一下 ...
  • d**1创建了代码片段:个人介...
  • 幻**梨向课程作业中提交了代码
  • w**3评论了o**n在课程中的作业:字符要用单引号将字符...
  • z**g添加了笔记:利用静态代码块可以对...
  • w**3回复了k**m在课程中的问题:换一个浏览器试试。 ...
  • X**O向课程作业中提交了代码
  • k**m在课程中提出了问题:看不了视频怎么办...
  • 幻**梨在课程作业中回复了老师:您的代码在测试中出错...
  • .**G创建了代码片段:Day3...
  • a**e在课程中提出了问题:提交到了overvi...
  • 2**b向课程作业中提交了代码
  • S**S回复了M**2在课程中的问题:搞定了吗? 关于ma...
  • 2**b向课程作业中提交了代码
  • g**g添加了笔记:方法的返回值和参数构...
  • S**S评论了o**n在课程中的作业:a是变量名称,你需要...
  • 幻**梨在课程作业中回复了老师:ok,已解决,谢...
  • d**_添加了笔记:byte、short...
  • g**g添加了笔记:方法的返回值和参数构...
  • s**d在课程作业中回复了老师:老师,请帮忙看看作业...
  • B**N向课程作业中提交了代码
  • d**1创建了代码片段:11...
  • w**3评论了2**b在课程中的作业:要自己改写啊,这不是...
  • S**S回复了k**e在课程中的问题:可以尝试命令行 工具...
  • N**i向课程作业中提交了代码
  • b**2向课程作业中提交了代码
  • S**y创建了代码片段:我的信...
  • N**i向课程作业中提交了代码
  • 2**b向课程作业中提交了代码
  • k**e在课程中提出了问题:如果搞不定 可以尝试...
  • 2**b向课程作业中提交了代码
  • g**g添加了笔记:方法的返回值和参数构...
  • 阳**徐创建了代码片段:自我介...
  • B**N向课程作业中提交了代码
  • 天**君评论了y**_在课程中的作业:不好意思,我们用来测...
  • f**o在课程作业中回复了老师
  • 1**3创建了代码片段:qwertyuio...
  • S**S回复了a**e在课程中的问题:先提交作业看下代码。...
  • b**t添加了笔记:.;%JAVA_HO...
  • 天**君回复了a**e在课程中的问题:欢迎来到天码营学习,...
  • l**g评论了
  • .**G创建了代码片段:Day3...
  • w**3评论了幻**梨在课程中的作业:实现一个静态方法,L...
  • f**o在课程中提出了问题:第 4 课 CSS基...
  • S**S回复了k**e在课程中的问题:http://blo...
  • 2**b向课程作业中提交了代码
  • z**6向课程作业中提交了代码
  • g**g添加了笔记:方法的返回值和参数构...
  • S**S回复了a**e在课程中的问题:你提交的东西什么都没...
  • 幻**梨向课程作业中提交了代码
  • S**S回复了k**e在课程中的问题:等一会儿 就可以了。...
  • d**1创建了代码片段:11...
  • .**G创建了代码片段:Day3...
  • 9**9添加了笔记:用法1:接受2个参数...
  • 2**b在课程作业中回复了老师:老师,这一行有必要吗...
  • k**e在课程中提出了问题
  • 2**b在课程作业中回复了老师:老师i,请问一下怎么...
  • 天**君回复了T**e在课程中的问题:欢迎来到天码营学习,...
  • 幻**梨在课程作业中回复了老师:请问这块代码的问题在...
  • d**_向课程作业中提交了代码
  • 天**君回复了k**m在课程中的问题:欢迎来到天码营学习,...
  • s**d在课程作业中回复了老师:老师,两个问题请您帮...
  • d**n向课程作业中提交了代码
  • g**g添加了笔记:方法的返回值和参数构...
  • 天**君回复了k**e在课程中的问题:欢迎来到天码营学习,...
  • k**e在课程中提出了问题:老师maven导入存...
  • S**S回复了k**e在课程中的问题:如果搞不定 可以尝试...
  • z**g添加了笔记:通过类名.方法的方式...
  • 2**b向课程作业中提交了代码
  • w**3评论了2**b在课程中的作业:car本身定义了成员...
  • 1**i创建了代码片段:小组组员介...
  • j**2向课程作业中提交了代码
  • d**_向课程作业中提交了代码
  • S**S向课程作业中提交了代码
  • X**O向课程作业中提交了代码
  • k**e向课程作业中提交了代码
  • g**g添加了笔记:Scanner sc...
  • 2**b在课程作业中回复了老师:老师这个要改写成什么...
  • N**i向课程作业中提交了代码
  • 天**君回复了y**_在课程中的问题:欢迎来到天码营学习,...
  • t**1向课程作业中提交了代码
  • k**e在课程中提出了问题:老师, 好像第一次加...
  • k**e添加了笔记:使用泛型类时,注意实...
  • C**G添加了笔记:'=='和'!='作...
  • S**S评论了s**d在课程中的作业:@GetMappin...
  • .**G创建了代码片段:Day3...
  • 2**b向课程作业中提交了代码
  • 天**君回复了h**u在课程中的问题:欢迎来到天码营学习,...
  • S**S回复了a**e在课程中的问题:提交到指定分支才能看...
  • 天**君回复了.**G在课程中的问题:欢迎来到天码营学习,...
反馈意见