我所不知道的TCP Socket编程(三)-服务器生命周期

2023-11-07

三:服务器生命周期

     

     服务器套接字用于侦听连接而非发起连接,其典型的生命周期如下:

     1)创建;

     2)绑定;

     3)侦听;

     4)接受;

     5)关闭;

     

     创建已经在第一节中介绍完了,继续其余部分;

          

     3.1 服务器绑定

     

     服务器生命周期中的第二步是绑定到监听连接的端口上;

     

     # ./code/snippets/bind.rb
     require 'socket'
     # 首先创建一个新的TCP套接字
     socket = Socket.new(:INET, :STREAM)
     # 创建一个C结构体来保存用于侦听的地址
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     # 执行绑定
     socket.bind(addr)

     

     上面是一段Ruby代码,我们需要知道的就是Socket在创建之后,需要设置监听端口号和地址;

     这个套接字现在被绑定到了本地主机的端口4481上;其他套接字便不能再使用此端口(客户端套接字可以使用该端口号连接服务器套接字,并建立连接);

     

     上述代码运行会推出,代码没错,但还不足以侦听某个链接;go on;

     

     注:

     服务器需要绑定到某个特定的,双向商定的端口号上,客户端套接字随后会连接到该端口;

          

     3.1.1 该绑定到哪个端口

     

     应该选择随机端口吗?该如何知道是否已经有其他的程序将某个端口宣为己有?

     

     任何在0~65535之间的端口都可以使用,但有一些约定:

     1)不要使用0~1024之间的端口:保留给系统了,如http默认使用端口80,SMTP默认使用端口25;绑定到这些端口通常需要root权限;

     2)不要使用49000~65535之间的端口,这些都是临时(ephemeral)端口;通常是那些不需要运行在预定义端口,而只是需要一些端口作为临时之需的服务使用;

     他们也是后面讲的‘链接协商’(connection negotiation)过程的一部分;选择该范围内的端口可能会对一些用户造成麻烦;

     3)1025~48999之间端口的使用一视同仁;

     (如果你打算选用其中一个作为服务端端口,应该看一下IANA的注册端口列表,确保你的选择不会和其他流行的服务器冲突;)

          

     3.1.2 该绑定到那个地址

     

     之前提到过系统中又一个127.0.0.1的环回接口;同时还会有一个物理的、基于硬件的接口,使用不同的IP地址(假设是192.168.0.5);当你绑定到某个由IP地址所描述的特定接口时,套接字就只会在该接口上进行侦听。而忽略其他接口;

     

     如果绑定早127.0.0.1,那么你的套接字就只会监听环回接口;此时,只有到localhost或127.0.0.1的连接才会被服务器套接字接受;环回接口仅限于本地连接使用,无法用于外部连接;

     

     若是其他合规地址,那么任何寻址到这个接口的客户端都在侦听范围内;

     如果你希望侦听每一个接口,那么可以使用0.0.0.0;这样就会绑定到所有可用的接口,环回接口等;

     

     4481 127.0.0.1 # 该套接字将会绑定在环回接口,只侦听来自本地主机的客户端;

     4481 0.0.0.0 # 该套接字将会绑定在所有已知的接口,侦听所有向其发送信息的客户端;

     4481 1.2.3.4 # 该套接字试图绑定一个未知接口,结果导致Errno::EADDRNOTAVAIL;

          

     3.2 服务器侦听

     

     创建套接字并绑定到特定端口之后,需要告诉套接字对接入的链接进行侦听;

     

     # ./code/snippets/listen.rb
     require 'socket'
     # 创建套接字并绑定到端口4481
     socket = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     socket.bind(addr)
     
     # 告诉套接字侦听接入的连接
     socket.listen(5)
     

     运行之后,仍然会退出,因为在服务器套接字能够处理连接之前,还需要另一个步骤,之后会讲,这里先解释下listen;

          

     3.2.1 侦听队列

     

     我们注意到listen的方法传递一个整数参数:这个数字表示服务器套接字能够容纳的待处理(pending)的最大连接数;

     待处理的连接列表被称为侦听队列;

     

     假设服务器正忙于处理某个客户端连接,此时新的客户端连接到达,将会被置于侦听队列;如果新的客户端连接到达且侦听队列已满,那么客户端将会产生Errno::ECONNREFUSED;

          

     3.2.2 侦听队列的长度

     

     为啥不把这个长度设成10000或是比较大的数?

     

     侦听队列长度的限制:通过运行时查看Socket::SOMAXCONN可以获知当前所允许的最大侦听队列长度;比如你没法使用超过128的数;

     root用户可以在有需要的服务器上增加这个系统级别的限制;

     

     如果服务器收到了Errno::ECONNREFUSED,增加队列长度,或需要更多的服务器实例,再或者需要采用其他架构;

     

     你可以使用 server.listen(Socket::SOMAXCONN) 将侦听队列长度设置为允许的最大值;

          

     3.3 接受连接

     

     下面看服务器实际处理接入连接的环节;通过accept方法实现:

     

    # ./code/snippets/listen.rb
     require 'socket'
     # 创建套接字
     server = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     server.bind(addr)
     server.listen(128)
     
     # 接受连接
     connection , _ = server.accept

     

     运行的话,没有退出:因为accept方法会一直阻塞到有连接到达;

     可以使用netcat发起一个连接:

     $ echo ohai | nc localhost 4481

     

     运行顺利的退出的话,说明连接已经建立;

          

     3.3.1 以阻塞方式接受连接

     

     accept是阻塞式的;

     accept会将侦听队列中还未处理的链接从队列中弹出(pop)而已;如果队列为空,那么他就一直等,直到有连接被加入队列为止;

          

     3.3.2 accept调用返回一个数组

     

     上面例子,accept调用获得两个返回值;

     accept方法实际上返回的是一个数组,这个数组包含两个元素:第一个元素是建立好的连接,第二个元素是一个Addrinfo对象(该对象描述了客户端连接的远程地址);

     

     Addrinfo:

     是一个Ruby类,描述了一台主机及其端口号,它将端点信息进行了包装;

     

     可以使用Addrinfo.tcp('localhost',4481)构建这些信息;一些有用的方法包括#ip_address,#ip_port;

     查看$ri Addrinfo:(图)

     



     接下来仔细查看一下#accept返回的连接和地址:

     

     # ./code/snippets/accept_connection_class.rb
     require 'socket'
     # 创建服务器套接字
     server = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     server.bind(addr)
     server.listen(128)
     
     #接受一个新连接
     connection , _ = server.accept
     
     print 'Connection class:'
     p connection.class
     
     print 'Server fileno:'
     p server.fileno
     
     print 'Connection fileno:'
     p connection.fileno
     
     print 'Local address:'
     p connection.local_address
     
     print 'Remote address:'
     p connection.remote_address

     当服务器获得一个连接(nc -t localhost 4481,使用该命令创建一个tcp连接),上述代码会输出:

     

     Connection class:  Socket

     Server fileno:     5

     Connection fileno: 8

     Local address:     #<Addrinfo:127.0.0.1:4481 TCP>

     Remote address:    #<Addrinfo:127.0.0.1:5816 4 TCP>


     下面逐个分析;

          

     3.3.3 连接类

     

     accept返回的第一个参数:

     

     尽管accept返回了一个‘连接’,但上述代码告诉我们并没有特殊的连接类,一个连接实际上就是Socket的一个实例;

     

     3.3.4 文件描述符

     

     知道了accept返回一个Socket的实例,不过这个连接的文件描述符编号和服务器套接字不一样;

     文件描述符是内核用于跟踪当前进程所打开文件的一种方法;-套接字是文件(Unix世界中,一切都是被视为文件);

     

     这表明accept返回了一个不同于服务器套接字的全新Socket;

     这个Socket实例描述了特定的连接(每个连接都由一个全新的Socket对象描述),这样服务器套接字就可以保持不变,不停地接受新的连接;

     

     3.3.5 连接地址

     

     accept返回的第二个参数:

     

     连接对象知道两个地址:本地地址和远程地址,其中远程地址也是accept的第二个返回值,不过也可以从连接中remote_address访问到;

     连接的local_address指的是本地主机的端点;

     

     每一个TCP连接都是由“本地主机 本地端口 远程主机 远程端口”这组唯一的组合定义的;

     

     3.3.6 accept循环

     

     accept会返回一个循环;

     前面的例子中服务端接受一个连接之后退出,我们希望只要有接入的连接,就不停地侦听;这个可以通过循环来实现;

     

    # ./code/snippets/accept_connection_class.rb
     require 'socket'
     # 创建服务器套接字
     server = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     server.bind(addr)
     server.listen(128)
     
     # 进入无限循环,接受并处理连接
     loop do
        connection , _ = server.accept
        #处理链接
        connection.close
     end

     

     Ruby也提供了一些语法糖来简化这些语法;

     

     

     3.4 关闭服务器

     

     一旦服务器接受了某个连接并处理完毕,最后就是关闭该连接;

     这就算完成了一个连接的“创建-处理-关闭”的生命周期;

     

     3.4.1 退出时关闭

     

     程序退出时,系统会帮你关闭所有打开的文件描述符(包括套接字),那为什么还需要手动关闭呢?

     1)资源使用:

        如果你使用了套接字却没有关闭它,那么不再使用的套接字使用可能依然保留;(在Ruby中,垃圾收集器会清理用不着的连接,将它收集到的所有一切全部关闭)

     

     2)打开文件的数量限制:

        所有进程都只能打开一定数量的文件(每一个连接都是一个文件);

     

     获知当前进程所允许打开文件的数量,可以使用Process.getrlimit(: NOFILE)

     返回值是一个数组,包含了软限制(用户配置的设置)和硬限制(系统限制);

     

     如果想将限制设置为最大值,可以使用Process.setrlimit(Process.getrlimit(: NOFILE)[1])

     

     3.4.2 不同的关闭方式

     

     因为套接字允许双向通信(读/写),可以只关闭其中一个通道;

     

     # ./code/snippets/accept_connection_class.rb
     require 'socket'
     # 创建服务器套接字
     server = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     server.bind(addr)
     server.listen(128)
     connection , _ = server.accept
     
     # 该连接随后也许不再需要写入数据,但可能仍然需要进行读取
     connection.close_write
     
     # 该连接不再需要进行任何数据读写操作
     connection.close_read

     

     关闭写操作流(write stream)会发送一个EOF到套接字的另一端(很快会讲到EOF);

     

     close_wirte和close_read方法在底层都用到了shutdown(2),与close(2)明显不同的是:即便是存在着连接的副本,shutdown(2)也可以完全关闭该连接的某一部分;

     

     注:连接副本是怎么回事?

        可以使用Socket#dup创建文件描述符的副本(实际是在os层面上利用dup(2)复制了底层的文件描述符);

        获得一个文件描述符副本的常用方法是用Process.fork方法,创建一个和当前进程一模一样的全新进程(会获得当前进程所有已经打开的文件描述符副本以及内存中的所有内容);

     

     close会关闭调用它的套接字实例;(不会关闭它的副本)

     shutdown会完全关闭当前套接字及其副本上的通信;(但是他并不回收套接字所使用过的资源,每个套接字实例必须使用close结束他的生命周期)

     

     # ./code/snippets/accept_connection_class.rb
     require 'socket'
     # 创建服务器套接字
     server = Socket.new(:INET, :STREAM)
     addr = Socket.pack_sockaddr_in(4481, '0.0.0.0')
     server.bind(addr)
     server.listen(128)
     connection , _ = server.accept
     
     # 创建连接副本
     copy = connection,dup
     
     # 关闭所有连接副本上的通信
     connection.shutdown
     
     # 关闭原始连接(副本会在垃圾收集器进行收集时关闭)
     connection.close

     

     3.5 Ruby包装器

        

     本节原是介绍使用Ruby来创建及使用服务器套接字的扩展的内容,便捷的将样本代码(之前的那些)包装到定制的类中并尽可能的使用Ruby语句块;

     这里仅仅给出一端示例,想深入了解的同学,请自行学习Ruby(看看示例才发现,Ruby如此优雅):

     

     # ./code/snippets/tcp_sercer_loop.rb
     
     require 'socket'
     
     Socket.tcp_server_loop(4481) do | connection |
        #处理链接
        connection.close
     end

     

     稍作解释:创建和循环处理Sockets链接;

        端点是 4481 0.0.0.0;

        Sockets 分别是支持IPv4和IPv6的socket连接server(注意他不是Socket实例了,而是TCPServer实例,一个Ruby包装类);

        队列长度也被设置为默认了,可以调用TCPServer#listen设置;

        循环处理就比较明显了;

     

     3.6 本章涉及的系统调用:

     (每一章都会列出新介绍的系统调用,告诉你如何使用ri或手册页来获得更多的信息)

     ·Socket#bind->bind(2)                  //ri Socket#bind -> man 2 bind

     ·Socket#listen->listen(2)              //ri Socket#listen -> man 2 listen

     ·Socket#accept->accept(2)              //ri Socket#accept -> man 2 accept

     ·Socket#local_address->getsockname(2)  //ri Socket#local_address -> man 2 getsockname

     ·Socket#remote_address->getpeername(2) //ri Socket#remote_address -> man 2 getpeername

     ·Socket#close->close(2)                //ri Socket#close -> man 2 close

     ·Socket#close_write->shutdown(2)       //ri Socket#close_write -> man 2 shutdown

     ·Socket#shutdown->shutdown(2)          //ri Socket#shutdown -> man 2 shutdown

     

     

     总结

     服务器端就这些,下一节介绍客户端的生命周期。

     

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

我所不知道的TCP Socket编程(三)-服务器生命周期 的相关文章

  • select 模型解释

    套接字模式 阻塞套接字和非阻塞套接字 或者叫同步套接字和异步套接字 套接字模型 描述如何对套接字的I O行为进行管理 Winsock提供的I O模型一共有五种 select WSAAsyncSelect WSAEventSelect Ove
  • gethostbyname()函数详解

    基本概念 gethostbyname 函数主要作用 用域名或者主机名获取地址 操作系统提供的库函数 以下的讨论基于linux环境 域名系统 Domain Name System DNS 主要用于主机名字与IP地址之间的映射 每个组织机构往往
  • 九、网络IO原理-创建ServerSocket的过程

    示例 创建ServerSocker过程 创建ServerSocket并注册端口号8090 ServerSocket server new ServerSocket 8090 while true 循环 final Socket socket
  • 一个栈的入栈序列是 a,b,c,d,e,则栈的不可能的输出序列是( ) 。

    一个栈的入栈序列是 a b c d e 则栈的不可能的输出序列是 a edcba b decbac dceab d abcde 堆栈讲究先进后出 后进先出 选项1是abcde先入栈 然后依次出栈 正好是edcba 选项2是abcd先依次入栈
  • 通过socket获取对方ip地址

    struct sockaddr in sa int len sizeof sa if getpeername sockfd struct sockaddr sa len printf 对方IP s inet ntoa sa sin addr
  • Springboot+Netty+Websocket实现消息推送实例

    Springboot Netty Websocket实现消息推送 文章目录 Springboot Netty Websocket实现消息推送 前言 一 引入netty依赖 二 使用步骤 1 引入基础配置类 2 netty服务启动监听器 3
  • 解决java.net.SocketException: No buffer space available (maximum connections reach

    严重 Catalina stop java net SocketException No buffer space available maximum connections reached JVM Bindat java net Plai
  • 使用socket判断http请求或http响应的传输结束

    使用socket判断http请求或http响应的传输结束 先把header直到 r n r n整个地收下来 1 传输完毕就关闭connection 即recv收到0个字节 2 有内容 if Transfer Encoding chunked
  • 从0实现基于Linux socket聊天室-实现聊天室的公聊、私聊功能-4

    前面文章链接如下 从0实现基于Linux socket聊天室 多线程服务器模型 1 从0实现基于Linux socket聊天室 多线程服务器一个很隐晦的错误 2 从0实现基于Linux socket聊天室 实现聊天室的登录 注册功能 3 上
  • 数据链路层六大协议详解

    数据链路层六大协议详解 一些假设 1 无限制的单工协议 乌托邦协议 五点假设 发送方 接收方 接受方 2 单工停 等协议 3 有噪声信道的单工协议 本文图片截取自 学堂在线 华南理工大学的计算机网络课程 一些假设 物理层 数据链路层和网络层
  • Qt之TCP心跳包

    Qt之TCP心跳包 当Qt作为客户端程序 而服务器需要监控客户端的在线状态时 就需要Qt端发送心跳包 心跳包可以是TCP也可以是UDP 这里介绍TCP心跳包的实现方法 心跳包通常要单开一个线程 在进程运行的过程中一直执行 代码示例 h文件
  • java-使用newTaskFor封装任务中非标准取消

    1 使用newTaskFor钩子函数来改进用来封装非标准取消的方法 这是ThreadPoolExecutor的新特性 2 当提交一个callable给ExecutorService时 submit返回一个Future 可以用Future来取
  • C# 网络编程之Tcp实现客户端和服务器聊天

    最近使用Socket网络套接字编程中 在同步与异步通讯中客户端与服务器总是无法响应 但在学习Tcp协议编程中完成了通讯聊天功能 下面简单讲讲我最近学到的及Tcp聊天的源代码及详细注释 Tcp协议是一个传输层的协议 在Tcp协议编程中它通常使
  • Java中的NIO和IO的对比分析

    总的来说 java中的IO和NIO主要有三点区别 IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器 Selectors 1 面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是 IO是面向流的 NIO是面向缓冲区的
  • TCP/IP编程实现远程文件传输

    TCP IP编程实现远程文件传输 在TCP IP网络结构中 为了保证网络安全 网络人员往往需要在路由器上添加防火墙 禁止非法用户用ftp等安全危害较大的TCP IP协议访问主机 而有时系统维护人员需要用ftp将一些文件从中心机房主机传到前端
  • 进程和线程的详解和区别

    1 进程和线程概述 我们都知道计算机的核心是CPU 它承担了所有的计算任务 而操作系统是计算机的管理者 它负责任务的调度 资源的分配和管理 统领整个计算机硬件 应用程序是具有某种功能的程序 程序是运行于操作系统之上的 2 进程 我们编写的代
  • socket编程之服务器端与客户端(代码实例)

    在我们学习的过程中 对TCP IP UDP Socket编程这些词应该有所了解了 随着网络技术的发展 这些词充斥着我们的耳朵 那么我想介绍一下 什么是TCP IP UDP socket在哪里呢 socket通信是什么呢 socket接口函数
  • QT进程间通信 详细介绍

    在QT中 信号和槽的机制取代了这种繁杂的 易崩溃的对象通信机制 信号是当对象状态改变时所发出的 槽是用来接收发射的信号并响应相应事件的类的成员函数 信号和槽的连接是通过connect 函数来实现的 AD 1 QT通信机制 为了更好的实现QT
  • 图解Git

    基本用法 上面的四条命令在工作目录 暂存目录 也叫做索引 和仓库之间复制文件 git add files 把当前文件放入暂存区域 git commit 给暂存区域生成快照并提交 git reset files 用来撤销最后一次git add
  • UDP服务recvfrom函数设置非阻塞

    基本概念 其实UDP的非阻塞也可以理解成和TCP是一样的 都是通过socket的属性去做 方法一 通过fcntl函数将套接字设置为非阻塞模式 方法二 通过套接字选项SO RECVTIMEO设置超时 方法一源码 编译 g udp server

随机推荐

  • 鸿合一体机怎么系统还原

    系统还原方法 先用牙签按住电脑还原按钮不松 然后按一下电源按钮开机 直到电脑进入系统还原画面 就可以松开还原按钮了 系统还原完成后会自动重启 重启完成就可以用了
  • 深入剖析 split locks,i++ 可能导致的灾难

    动手点关注 干货不迷路 Split lock 是 CPU 为了支持跨 cache line 进行原子内存访问而支持的内存总线锁 有些处理器比如 ARM RISC V 不允许未对齐的内存访问 不会产生跨 cache line 的原子访问 所以
  • spring 拦截路径/、/*、/**三者通配符的意义

    拦截固定后缀 代表值拦截一层 代表拦截任意层 即个栗子 如果是一个拦截器的配置 代表拦截 target 下一层的请求 如 http localhost target 123会进入此拦截器 而http localhost target 123
  • 服务器ftp上传失败的原因有什么

    ftp是网站服务器租用用户将修改的数据上传到服务器中的常用方法 然而有时候用户在操作的时候会遇到各种各样的问题 这里我们就针对不同服务器以及不同操作系统版本所共同会出现的问题做一个汇总解答 1 无法上传网页 FTP故障 提示 无法连接服务器
  • 完美解决mysql 8.0高版本兼容性各种问题

    1 下载高版本驱动包 mysql connector java 8 0 15 jar https pan baidu com s 1pRTtD88K7mLR5OMipVn QQ 20 提取码 t27v 2 更换驱动名 以前 com mysq
  • SQL中union(并集)、except(差集)、intersect(交集)用法,然而 mysql 不支持except 和 intersect

    知识点 UNION返回两个结果集的并集 还有一个union all的用法 union没有包含重复列 union all 包含重复列 EXCEPT 返回两个结果集的差 即从左查询中返回右查询没有找到的所有非重复值 第一个表有 第二个表无 IN
  • RabbitMQ可视化页面使用(中文翻译)

    RabbitMQ可视化页面 安装部署 RabbitMQ保姆级安装 Linux Centos8系统
  • 深入理解JVM(二)——揭开HotSpot对象创建的奥秘

    对象的创建过程 当虚拟机遇到一条含有new的指令时 会进行一系列对象创建的操作 检查常量池中是否有即将要创建的这个对象所属的类的符号引用 若常量池中没有这个类的符号引用 说明这个类还没有被定义 抛出ClassNotFoundExceptio
  • 给a标签添加点击事件,用getElementByClassname失败,但是querySelector成功原因

    querySelector与getElementByClassname getElementsByClassName querySelector 使用 getElementsByClassName 方法获取到的是一个 HTMLCollect
  • 微信小程序提现功能

    1 开通微信支付账号 开通 企业付款到零钱 2 上代码 提现功能 public function payOrder openid input openid 用户openid userid input userid d 0 用户uid amo
  • SpringBoot2学习笔记

    信息来源 https www bilibili com video BV19K4y1L7MT p 5 vd source 3969f30b089463e19db0cc5e8fe4583a 作者提供的文档 https www yuque co
  • 微信小程序的socket.io即时通讯开发(基于E聊SDK)

    1 背景 由于微信小程序需要开发轻量 跨平台 开发时间短等特点 许多公司将小程序作为了业务展示的第一个APP E聊客户端核心SDK 通讯部分已适配了微信小程序平台 下面分享一下适配过程中的思路与方法 2 分析 微信小程序接入要求 微信小程序
  • openpcdet环境配置

    版本确定 驱动 cuda cudnn cuda与cudnn 官方 安装文档 https docs nvidia com cuda cuda installation guide linux index html runfile instal
  • 实例分割:Mask RCNN

    Mask RCNN 学习目标 说明Mask RCNN的结构特点 掌握Mask RCNN的RoIAlign方法 掌握Mask RCNN的mask原理 知道Mask RCNN的损失函数 上图是MaskRCNN预测的结果 Mask RCNN流程
  • Shader与ShaderToy开篇

    写在前面 Unity从学习到工作至今已经有三个年头了 开发中每次遇到难点第一件事就是百度搜索 从来没有自己的想法 甚是惭愧 想着不能再这样浑浑噩噩下去了 也决定开个博客 记录一下开发中自己觉得有用的东西 希望日后某一天回顾起来不会觉得日子白
  • 操作系统学习(1)

    1 进程的模式有系统态 管态 和用户态 目态 两种 一般用户编写的程序是在用户态下工作 当程序中有中断或者调用系统函数时 会切换到系统态下运行 2 当CPU处于管态时 可以执行的指令是 计算机系统中的全部指令 分析 管态又叫特权态 系统态或
  • 区块链23问,你想知道的都在这里了

    本文将以一问一答的方式给大家送上一篇关于区块链的科普文 区块链是比特币吗 金融领域为什么要使用区块链技术 所有的区块链都需要挖矿吗 区块链和大数据什么关系 这些问题本文将会一一解答 前方高能 问 什么是区块链 答 区块链 Blockchai
  • Apache 原生 Hadoop 运维命令

    Hadoop 1 检查原生hadoop和压缩库是否可用 hadoop checknative 2 打印hadoop环境的配置路径 hadoop classpath HDFS 1 查看hdfs文件系统的状态 hdfs dfsadmin rep
  • 我的创作纪念日2022

    起因 最初是当作自己的C语言电子笔记本来用的 记录一些做题的时候的理解 后来发现自己的文章可以帮助到一些一起学习的朋友就开始逐步写的通俗易懂 再到后来看到B站稚晖君的一些视频 以及结合自己的专业 开始了对嵌入式的学习 以及分享一些自己学习的
  • 我所不知道的TCP Socket编程(三)-服务器生命周期

    三 服务器生命周期 服务器套接字用于侦听连接而非发起连接 其典型的生命周期如下 1 创建 2 绑定 3 侦听 4 接受 5 关闭 创建已经在第一节中介绍完了 继续其余部分 3 1 服务器绑定 服务器生命周期中的第二步是绑定到监听连接的端口上