Linux·网络编程套接字(三)

2023-11-10

目录

简单的TCP英译汉服务器

简单回顾

更改handler方法

地址转换函数

字符串IP转整数IP

整数IP转字符串IP

绑定失败问题

TCP协议通讯流程

通讯流程总览

三次握手的过程

数据传输的过程​编辑

四次挥手的过程

TCP和UDP对比


 

简单的TCP英译汉服务器

简单回顾

在上一篇博客网络编程套接字(二)当中实现了简单的TCP服务器,最开始我们实现的是单执行流的TCP服务器,之后通过代码测试发现单执行流的TCP服务器无法同时为多个客户端提供服务,于是又转而实现了多执行流的TCP服务器。

在实现多执行流的TCP服务器时,分别演示了多进程和多线程的实现方式,为了进一步优化基于多线程的TCP服务器,最终还将线程池接入到了TCP服务器当中。此时访问TCP服务器的各个客户端,分别由不同的执行流为其提供服务,因此这些客户端能够同时享受服务器提供的服务。

当时我们说过,如果想要让这里的TCP服务器处理其他任务,只需要修改对应的处理函数即可。对应到最终实现的线程池版本的TCP服务器,我们要修改的其实就只是任务类当中的handler方法。下面我们以实现简单的TCP英译汉服务器为例,看看更改后我们的TCP服务器能否正常为客户端提供英译汉服务。

更改handler方法

英译汉TCP服务器要做的就是,根据客户端发来的英文单词找到其对应的中文意思,然后将该中文意思作为响应数据发给客户端。

之前我们是以回调的方式处理任务的,当线程池当中的线程从任务队列中拿出一个任务后,会调用该任务对应的Run方法处理该任务,而实际在这个Run方法当中会以仿函数的方式调用handler方法,因此我们只需更改Handler类当中对()的重载函数即可,而其他与通信相关的代码我们一律不用更改。

英译汉时需要根据英文单词找到其对应的中文意思,因此我们需要建立一张映射表,其中英文单词作为映射表中的键值key,而中文意思作为与键值相对应的value,这里可以直接使用C++STL容器当中的unordered_map容器。

class Handler
{
public:
    Handler()
    {}
    ~Handler()
    {}
    void operator()(int sock, std::string client_ip, int client_port)
    {
        //only for test
        std::unordered_map<std::string, std::string> dict;
        dict.insert(std::make_pair("dragon", "龙"));
        dict.insert(std::make_pair("blog", "博客"));
        dict.insert(std::make_pair("socket", "套接字"));
        
        char buffer[1024];
        std::string value;
        while (true){
            ssize_t size = read(sock, buffer, sizeof(buffer)-1);
            if (size > 0){ //读取成功
                buffer[size] = '\0';
                std::cout << client_ip << ":" << client_port << "# " << buffer << std::endl;

                std::string key = buffer;
                auto it = dict.find(key);
                if (it != dict.end()){
                    value = it->second;
                }
                else{
                    value = key;
                }
                write(sock, value.c_str(), value.size());
            }
            else if (size == 0){ //对端关闭连接
                std::cout << client_ip << ":" << client_port << " close!" << std::endl;
                break;
            }
            else{ //读取失败
                std::cerr << sock << " read error!" << std::endl;
                break;
            }
        }
        close(sock); //归还文件描述符
        std::cout << client_ip << ":" << client_port << " service done!" << std::endl;
    }
};

说明一下:

  • 这里只是测试更改后的服务器能否为客户端提供英译汉服务,因此直接将这张映射表定义在了()重载函数当中。
  • 初始化这张映射表对应的操作,就是建立单词与其中文意思之间的映射关系,代码中为了测试只简单建立了三组映射关系。此外,初始化映射表的操作应该重新封装出一个初始化函数,否则每次为客户端提供英译汉服务时都会重新建立映射关系。
  • 如果你自己要实现一个英译汉服务器,应该将这张映射表定义为静态,保证全局只有一张映射表,在启动服务器时就可以对这张映射表进行初始化。可以将中英文对照单独写在一个文件当中,在启动服务器时就可以将该文件加载进来,建立对应的映射关系。(这里我们只是做测试的,就不做过多的设计了)
  • 当服务端在为客户端提供英译汉服务时,如果在映射表中不存在对应key值的键值对,则服务端会直接将用户发来的数据响应给客户端。

代码测试
现在这个TCP服务器就能够给客户端提供英译汉的服务了,客户端发来的单词如果能够在映射表当中找到,那么服务端会将该单词对应发中文意思响应给客户端,否则会将客户端发来的单词原封不动的响应给客户端。

 注意: 这里只是想告诉大家,我们可以通过改变这里的handler方法来改变服务器处理任务的逻辑。如果你还想对当前这个英译汉服务器进行完善,可以在网上找一找牛津词典对应的文件,将其中单词和中文的翻译做出kv的映射关系,当服务器启动的时候就可以加载这个文件,建立对应的映射关系,此时就完成了一个网络版的英译汉服务器。

地址转换函数

字符串IP转整数IP

  • inet_ntoa函数

inet_ntoa函数的函数原型如下:

  • int inet_aton(const char *cp, struct in_addr *inp);

参数说明:

  • cp:待转换的字符串IP。
  • inp:转换后的整数IP,这是一个输出型参数。

返回值说明:

  • 如果转换成功则返回一个非零值,如果输入的地址不正确则返回零值。
  • inet_addr函数

inet_addr函数的函数原型如下:

  • in_addr_t inet_addr(const char *cp);

参数说明:

  • cp:待转换的字符串IP。

返回值说明:

  • 如果输入的地址有效,则返回转换后的整数IP;如果输入的地址无效,则返回INADDR_NONE(通常为-1)。

inet_pton函数

inet_pton函数的函数原型如下:

  • int inet_pton(int af, const char *src, void *dst);

参数说明:

  • af:协议家族。
  • src:待转换的字符串IP。
  • dst:转换后的整数IP,这是一个输出型参数。

返回值说明:

  • 如果转换成功,则返回1。
  • 如果输入的字符串IP无效,则返回0。
  • 如果输入的协议家族af无效,则返回-1,并将errno设置为EAFNOSUPPORT。

整数IP转字符串IP

inet_ntoa函数

inet_ntoa函数的函数原型如下:

  • char *inet_ntoa(struct in_addr in);

参数说明:

  • in:待转换的整数IP。

返回值说明:

  • 返回转换后的字符串IP。

inet_ntop函数

inet_ntop函数的函数原型如下:

  • const char *inet_ntop(int af, const void *src, char *dst, socklen_t size);

参数说明:

  • af:协议家族。
  • src:待转换的整数IP。
  • dst:转换后的字符串IP,这是一个输出型参数。
  • size:用于指明dst中可用的字节数。

返回值说明:

  • 如果转换成功,则返回一个指向dst的非空指针;如果转换失败,则返回NULL。

说明一下

  • 我们最常用的两个转换函数是inet_addr和inet_ntoa,因为这两个函数足够简单。这两个函数的参数就是需要转换的字符串IP或整数IP,而这两个函数的返回值就是对应的整数IP和字符串IP。
  • 其中inet_pton和inet_ntop函数不仅可以转换IPv4的in_addr,还可以转换IPv6的in6_addr,因此这两个函数中对应的参数类型是void*。
  • 实际这些转换函数都是为了满足某些打印场景的,除此之外,更多的是用来做某些数据分析,比如网络安全方面的数据分析。

关于inet_ntoa函数
inet_ntoa函数可以将四字节的整数IP转换成字符串IP,其中该函数返回的这个转换后的字符串IP是存储在静态存储区的,不需要调用者手动进行释放,但如果我们多次调用inet_ntoa函数,此时就会出现数据覆盖的问题。

例如,下列代码连续调用了两次inet_ntoa函数。

 由于inet_ntoa函数内部只在静态存储区申请了一块区域,因此inet_ntoa函数第二次转换的结果就会覆盖第一次转换的结果。

 因此,如果需要多次调用inet_ntoa函数,那么就要及时保存inet_ntoa的转换结果。

并发场景下的inet_ntoa函数

inet_ntoa函数内部只在静态存储区申请了一块区域,用于存储转换后的字符串IP,那么在线程场景下这块区域就叫做临界区,多线程在不加锁的情况下同时访问临界区必然会出现异常情况。并且在APUE中,也明确提出inet_ntoa不是线程安全的函数。

下面我们在多线程场景下对inet_ntoa函数进行测试:

#include <iostream>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>

void* Func1(void* arg)
{
    struct sockaddr_in* p = (struct sockaddr_in*)arg;
    while (1){
        char* ptr1 = inet_ntoa(p->sin_addr);
        std::cout << "ptr1: " << ptr1 << std::endl;
        sleep(1);
    }
}
void* Func2(void* arg)
{
    struct sockaddr_in* p = (struct sockaddr_in*)arg;
    while (1){
        char* ptr2 = inet_ntoa(p->sin_addr);
        std::cout << "ptr2: " << ptr2 << std::endl;
        sleep(1);
    }
}
int main()
{
    struct sockaddr_in addr1;
    struct sockaddr_in addr2;
    addr1.sin_addr.s_addr = 0;
    addr2.sin_addr.s_addr = 0xffffffff;
    
    pthread_t tid1 = 0;
    pthread_create(&tid1, nullptr, Func1, &addr1);
    pthread_t tid2 = 0;
    pthread_create(&tid2, nullptr, Func2, &addr2);
    
    pthread_join(tid1, nullptr);
    pthread_join(tid2, nullptr);
    return 0;
}

但是实际在centos7上测试时,在多线程场景下调用inet_ntoa函数并没有出现问题,可能是该函数内部的实现加了互斥锁,这就跟接口本身的设计也是有关系的。

 鉴于此,在多线程环境下更加推荐使用inet_ntop函数进行转换,因为该函数是由调用者自己提供缓冲区保存转换结果的,可以规避线程安全的问题。

绑定失败问题

资源未释放干净

当我们在测试网络代码时,先将服务端绑定8081端口运行,然后运行客户端,并让客户端连接当前服务器。

 此时在有客户端连接服务端的情况下,如果直接将服务端关闭,此时服务端要想再次绑定8081号端口运行,就可能会绑定失败。
绑定失败这个问题涉及TCP通信中双方状态变化的一个细节,这里暂时无法解释清楚,后面博主在讲解TCP协议细节时会详谈。这里想说明的就是,绑定是有可能失败的,这里绑定失败实际是因为服务端退出时没有将资源释放干净。

 端口号已被其他程序绑定

此外,绑定失败还有可能因为当前端口号已经被其他程序绑定了。比如一个程序已经绑定了8081号端口,此时另一个程序也想绑定8081号端口,此时该程序就会绑定失败。

 这实际也就验证了一个端口号只能被一个进程所绑定这样的规则,此时也就确保了端口号到服务之间的映射本身就具备唯一性。

无法绑定的端口号

我们自己编写的服务器代码在绑定端口号时,尽量不要绑定1024以下的端口号。一般云服务器只能绑定1024及其往上的端口号,因为1024以下的端口已经约定俗成被其他一些比较成熟的服务所使用了,如果我们绑定1024以下的端口号,那么会绑定失败。

 因此我们一般只能绑定1024及其往上的端口号,最好绑定8000及其网上的端口号。

说明一下:

  • 我们在云服务器上写代码时,就算代码没有问题也不一定能访问成功,有可能你的云服务器没有开放端口。此时如果想要测试编写的网络代码,就要在你的云服务器上开放安全组。

TCP协议通讯流程

通讯流程总览

下图是基于TCP协议的客户端/服务器程序的一般流程:

 下面我们结合TCP协议的通信流程,来初步认识一下三次握手和四次挥手,以及建立连接和断开连接与各个网络接口之间的对应关系。

三次握手的过程


初始化服务器

 当服务器完成套接字创建、绑定以及监听的初始化动作之后,就可以调用accept函数阻塞等待客户端发起请求连接了。

服务器初始化:

  • 调用socket,创建文件描述符。
  • 调用bind,将当前的文件描述符和IP/PORT绑定在一起,如果这个端口已经被其他进程占用了,就会bind失败。
  • 调用listen,声明当前这个文件描述符作为一个服务器的文件描述符,为后面的accept做好准备。
  • 调用accept,并阻塞,等待客户端连接到来。

建立连接

而客户端在完成套接字创建后,就会在合适的时候通过connect函数向服务器发起连接请求,而客户端在connect的时候本质是通过某种方式向服务器三次握手,因此connect的作用实际就是触发三次握手。

建立连接的过程:

  • 调用socket,创建文件描述符。
  • 调用connect,向服务器发起连接请求。
  • connect会发出SYN段并阻塞等待服务器应答(第一次)。
  • 服务器收到客户端的SYN,会应答一个SYN-ACK段表示“同意建立连接”(第二次)。
  • 客户端收到SYN-ACK后会从connect返回,同时应答一个ACK段(第三次)。

这个建立连接的过程,通常称为三次握手。

需要注意的是,连接并不是立马建立成功的,由于TCP属于传输层协议,因此在建立连接时双方的操作系统会自主进行三次协商,最后连接才会建立成功。

数据传输的过程

 数据交互

连接一旦建立成功并且被accept获取上来后,此时客户端和服务器就可以进行数据交互了。需要注意的是,连接建立和连接被拿到用户层是两码事,accept函数实际不参与三次握手这个过程,因为三次握手本身就是底层TCP所做的工作。accept要做的只是将底层已经建立好的连接拿到用户层,如果底层没有建立好的连接,那么accept函数就会阻塞住直到有建立好的连接。

而双方在进行数据交互时使用的实际就是read和write,其中write就叫做写数据,read就叫做读数据。write的任务就是把用户数据拷贝到操作系统,而拷贝过去的数据何时发以及发多少,就是由TCP决定的。而read的任务就是把数据从内核读到用户。

数据传输的过程:

  • 建立连接后,TCP协议提供全双工的通信服务,所谓全双工的意思是,在同一条连接中,同一时刻,通信双方可以同时写数据,相对的概念叫做半双工,同一条连接在同一时刻,只能由一方来写数据。
  • 服务器从accept返回后立刻调用read,读socket就像读管道一样,如果没有数据到达就阻塞等待。
  • 这时客户端调用write发送请求给服务器,服务器收到后从read返回,对客户端的请求进行处理,在此期间客户端调用read阻塞等待服务器端应答。
  • 服务器调用write将处理的结果发回给客户端,再次调用read阻塞等待下一条请求。
  • 客户端收到后从read返回,发送下一条请求,如此循环下去。

四次挥手的过程


端口连接

 当双方通信结束之后,需要通过四次挥手的方案使双方断开连接,当客户端调用close关闭连接后,服务器最终也会关闭对应的连接。而其中一次close就对应两次挥手,因此一对close最终对应的就是四次挥手。

断开连接的过程:

  • 如果客户端没有更多的请求了,就调用close关闭连接,客户端会向服务器发送FIN段(第一次)。
  • 此时服务器收到FIN后,会回应一个ACK,同时read会返回0(第二次)。
  • read返回之后,服务器就知道客户端关闭了连接,也调用close关闭连接,这个时候服务器会向客户端发送一个FIN(第三次)。
  • 客户端收到FIN,再返回一个ACK给服务器(第四次)。

这个断开连接的过程,通常称为四次挥手。

注意通讯流程与socket API之间的对应关系

在学习socket API时要注意应用程序和TCP协议是如何交互的:

  • 应用程序调用某个socket函数时TCP协议层完成什么动作,比如调用connect会发出SYN段。
  • 应用程序如何知道TCP协议层的状态变化,比如从某个阻塞的socket函数返回就表明TCP协议收到了某些段,再比如read返回0就表明收到了FIN段。

为什么要断开连接?

建立连接本质上是为了保证通信双方都有专属的连接,这样我们就可以加入很多的传输策略,从而保证数据传输的可靠性。但如果双方通信结束后不断开对应的连接,那么系统的资源就会越来越少。

因为服务器是会收到大量连接的,操作系统必须要对这些连接进行管理,在管理连接时我们需要“先描述再组织”。因此当一个连接建立后,在服务端就会为该连接维护对应的数据结构,并且会将这些连接的数据结构组织起来,此时操作系统对连接的管理就变成了对链表的增删查改。

如果一个连接建立后不断开,那么操作系统就需要一直为其维护对应的数据结构,而维护这个数据结构是需要花费时间和空间的,因此当双方通信结束后就应该将这个连接断开,避免系统资源的浪费,这其实就是TCP比UDP更复杂的原因之一,因为TCP需要对连接进行管理。

TCP和UDP对比

  • 可靠传输 vs 不可靠传输
  • 有连接    vs 无连接
  • 字节流    vs 数据报


原文链接:https://blog.csdn.net/chenlong_cxy/article/details/124683721

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

Linux·网络编程套接字(三) 的相关文章

  • 服务器集群是如何提高计算性能的?

    服务器集群是一种将多台服务器连接起来协同工作的技术 通过集群配置 可以提高计算性能 可靠性和可扩展性 以下是服务器集群如何提高计算性能的详细解释 一 并行处理能力 服务器集群的核心优势在于其并行处理能力 通过将多个服务器组成一个集群 可以将
  • 基于成本和服务质量考虑的不确定性下,电动汽车充电网络基础设施需求预测和迭代优化的分层框架研究(Python代码实现)

    欢迎来到本博客 博主优势 博客内容尽量做到思维缜密 逻辑清晰 为了方便读者 座右铭 行百里者 半于九十 本文目录如下 目录 1 概述 2 运行结果 3 参考文献 4 Python代码 数据
  • 使用Hypothesis生成测试数据

    Hypothesis是Python的一个高级测试库 它允许编写 测试用例 时参数化 然后生成使测试失败的简单易懂的测试数据 可以用更少的工作在代码中发现更多的bug 安装 pip install hypothesis 如何设计 测试数据 通
  • 如何利用CHAT做简单的总结体会?

    问CHAT 在测试过程中使用appium python自动化的优点和体会 CHAT回复 使用 Appium 配合 Python 进行自动化测试主要有以下几点优点 1 跨平台性 Appium 支持 iOS 和 Android 平台的应用自动化
  • 线程安全(中)--彻底搞懂synchronized(从偏向锁到重量级锁)

    接触过线程安全的同学想必都使用过synchronized这个关键字 在java同步代码快中 synchronized的使用方式无非有两个 通过对一个对象进行加锁来实现同步 如下面代码 synchronized lockObject 代码 对
  • Linux终端常见用法总结

    熟悉Linux终端的基础用法和常见技巧可以极大提高运维及开发人员的工作效率 笔者结合自身学习实践 总结以下终端用法供同行交流学习 常 见 用 法 1 快捷键 1 1 Alt 在光标位置插入上一次执行命令的最后一个参数 1 2 Ctrl R
  • RF自动化环境安装+自动化实例解析

    RF定义 通用型的 自动测试框架 绝大部分的软件的的自动化系统都可以采用它 特点 测试数据文件 Test Data 对应一个个的测试用例 测试数据文件里面使用的功能小模块叫关键字 由测试库 Test Library Robot Framew
  • messages,CentOS 7不收集日志或不存在 /var/log/messages

    var log message var log secure等都不记录了 并且都是空文件 重启机器 reboot 无效 重启日志 systemctl start rsyslog 无效 怀疑空间不足 删除 var log messages 重
  • 远程控制软件安全吗?一文看懂ToDesk、RayLink、TeamViewer、Splashtop相关安全机制_raylink todesk

    目录 一 前言 二 远程控制中的安全威胁 三 国内外远控软件安全机制 ToDesk RayLink Teamviewer Splashtop 四 安全远控预防 一 前言 近期 远程控制话题再一次引起关注 据相关新闻报道 不少不法分子利用远程
  • 什么是充放电振子理论?

    CHAT回复 充放电振子模型 Charging Reversal Oscillator Model 是一种解释ENSO现象的理论模型 这个模型把ENSO现象比喻成一个 热力学振荡系统 在这个模型中 ENSO现象由三个组成部分 充电 Char
  • 基于java的物业管理系统设计与实现

    基于java的物业管理系统设计与实现 I 引言 A 研究背景和动机 物业管理系统是指对物业进行管理和服务的系统 该系统需要具备对物业信息 人员信息 财务信息等进行管理的能力 基于Java的物业管理系统设计与实现的研究背景和动机主要体现在以下
  • 一台java服务器可以跑多少个线程?

    一台java服务器可以跑多少个线程 一台java服务器能跑多少个线程 这个问题来自一次线上报警如下图 超过了我们的配置阈值 打出jstack文件 通过IBM Thread and Monitor Dump Analyzer for Java
  • tcpdump抓包

    tcpdump抓包 基本概念 1 类型的关键字 host 指明一台主机 如 host 10 1 110 110 net 指明一个网络地址 如 net 10 1 0 0 port 指明端口号 如 port 8090 2 确定方向的关键字 sr
  • Vue 如何使用WebSocket与服务器建立链接 持续保持通信

    WebSocket 浏览器通过JavaScript向服务器发出建立WebSocket链接的请求 链接建立后 客户端和服务器端就可以通过TCP链接直接交互数据 WebSocket链接后可以通过 send 方法来向服务器发送数据 并通过 onn
  • Kubernetes (十二) 存储——Volumes配置管理

    一 卷的概念 官方地址 卷 Kubernetes https v1 24 docs kubernetes io zh cn docs concepts storage volumes 二 卷的类型及使用 emptyDir卷 1 创建编辑文件
  • Kubernetes (十三) 存储——持久卷-动静态分配

    一 简介 二 NFS持久化存储步骤 静态分配 1 集群外主机用上次nfsdata共享目录中创建用来测试的pv 1 3 目录 用来对三个静态pv 2 创建pv的应用文件 vim pv yaml apiVersion v1 kind Persi
  • ssh:connect to host github.com port 22: Connection timed out

    解决流程 1 将github的端口由22改为443 ssh T p 443 git ssh github com 2 接着输入yes进行确认 The authenticity of host ssh github com 443 192 1
  • 静态综合实验

    1 IP地址划分 192 168 1 0 27 用于主干拆分 192 168 1 32 27 用于用户拆分 192 168 1 64 27 用于用户拆分 192 168 1 96 27 用于用户拆分 192 168 1 128 27 用于用
  • ESP10B 锁定连接器

    ESP10B 锁定连接器 ESP10B 电机新增内容包括双极型号标准 NEMA 尺寸 17 23 和 34 的步进电机现在包括输出扭矩范围从 61 盎司英寸到 1291 盎司英寸的双极型号 该电机配有带锁定连接器的尾缆 可轻松连接 每转可步
  • 网络安全行业热门认证证书合集

    网络安全认证证书 就和学历一样是敲门砖 拿到了可以用不到 但不能没有 技术大牛可以没有证书 但普通人不能没有 1 初级入门 就像学历在职场上展示一个人的基本素养一样 网络安全认证证书可以展示一个人在网络安全领域具备的基本知识和技能 它为初学

随机推荐

  • 加法乘法原理、排列组合、线性规划

    排列组合 1 加法原理与乘法原理 加法原理 分类思想 一个事件的发生 分为几类事件的发生 通俗的说是好几种情况的发生 乘法原理 分步思想 一个事件的发生 分为几个子事件分步发生 这里要注意 1 子事件 如何把事件划分为几个子事件呢 子事件是
  • dlopen “no suitable image found ”问题之解决

    做一个练手小项目 基于 react transform boilerplate 的demo 克隆 react transform boilerplate项目 装包 package json中的包 style loader css loade
  • 并发、并行、同步、异步的概念

    并发与并行 假设一个工厂 包含多个车间 一个车间包含多个工人和多个房间 什么是cpu 工厂是时刻在运行的 因此可以理解cpu时刻在运行 什么cpu的核数 假设把一个cpu比作一份电量的话 一份电量又只能满足一个车间运行 那么其他车间就得停止
  • 使用python写一个星球大战游戏.py

    如果要使用 Python 写一个类似于星球大战的游戏 需要用到一些专业的游戏引擎 比如 Pygame 首先 需要安装 Pygame 库 可以使用以下命令进行安装 pipinstall pygame 其次 可以在 Pygame 中使用 pyt
  • 网络安全人才青黄不接、数字化转型迫在眉睫、你还在犹豫吗?

    大专能不能学网络安全呢 大专学网络安全能不能找到工作呢 大专学网络安全有竞争力吗 网络上关于质疑大专学历进入网络安全行业的声音越来越多了 居然有很多人在质疑大专学历从事网络安全没有竞争力 很多人看到某些招聘软件上起薪12K的薪资就望而却步了
  • Linux文件管理

    成功不易 加倍努力 1 文件系统目录结构 1 1文件系统的目录结构 1 2 常见的文件系统目录功能 1 3 应用程序的组成部分 1 4 Linux下的文件类型 2 文件操作命令 2 1 显示当前工作目录 2 2 绝对和相对路径 2 3 更改
  • Nano编辑器安装使用指南

    关于nano Nano编辑器是一个命令行文本编辑器 具有简单易用的界面和一些基本功能 Nano小巧友好 提供许多额外的特性 例如交互式的查找和替换 定位到指定的行列 自动缩进 特性切换 国际化支持 文件名标记完成等 Nano是为了代替闭源的
  • 《Zookeeper-分布式过程系统技术详解》第一部分基础概念笔记学习

    1 Zookeep的客户端API功能强大 其中包括 保障强一致性 有序性和持久性 实现通用的同步原语的能力 在实际分布式系统中 并发往往导致不正确的行为 ZooKeeper提供了一种简单的并发处理机制 2 ZooKeeper不适用的场景 整
  • 重新学javaweb---JSTL标签

    JSTL简介 标准标签库JSTL的全名为 Java Server Pages Standard Tag Library JSTL主要提供了5大类标签库 核心标签库 为日常任务提供通用支持 如显示和设置变量 重复使用一组项目 测试条件以及其他
  • Promise常用API介绍

    Promise中的API PromiseState 实例对象中的一个属性 Promisestate 状态 pending 未决定 resolved fullfilled 成功 rejected 失败 pending 变为resolved p
  • CSDN周赛64期题解(含部分代码)

    计算之魂 主题周赛如期回归 因为差不多每次都是新题 让人多了点期待 相信非编程题无需多言 答案都在书里 翻书翻得快 满分无障碍 当然 如果提前读过此书就更好了 比如原书中把金块切了 2 刀 问题中扩展了一下 变成切 9 刀 如果提前理解过原
  • 【推荐系统】 一、推荐系统简介

    1 推荐系统的作用和意义 在这个时代 无论信息消费者还是信息生产者都面临巨大的挑战 信息消费者 在大量信息中找到自己感兴趣的信息很困难 信息生产者 将自己生产的信息让广大消费者关注很困难 推荐系统将用户与信息联系起来 1 1 用户角度 推荐
  • Mysql语句执行顺序

    1 SQL书写顺序 select distinct 显示字段 from 表名 join 要连接的表名 on 连接查询条件 where 约束条件 group by 分组字段 having 分组过滤条件 order By DESC 降序 或AS
  • NSLog效率低下的原因以及NSLog宏定义

    我是前言 打Log是我们debug时最简单朴素的方法 NSLog 对于objc开发就像 printf 对于c一样重要 但在使用 NSLog 打印大量Log 尤其是在游戏开发时 如每一帧都打印数据 NSLog 会明显的拖慢程序的运行速度 游戏
  • java实现敏感词过滤算法DFA并忽略敏感词中的特殊字符

    参考文章 https blog csdn net chenssy article details 26961957 补充说明 1 具体的DFA介绍参考原文章 此处只是补充了文章中没有介绍的点以及根据实际需求进行了改造 2 最大 小匹配规则
  • Flask学习笔记_BBS论坛搭建(三)

    Flask学习笔记 BBS论坛搭建 三 1 cms管理 1 1 项目模块划分 目录结构搭建 1 2 每个模块注册蓝图 并绑定 1 3 数据库配置 连接 迁移控制 这里本来用了flask script 但migrate的新版不支持他了 所以就
  • CSDN竞赛第41期题解

    CSDN竞赛第41期题解 非编程题部分 第一题 算盘是一种古代中国发明的计算机 原因在于人们在操作算盘时可以充分利用人脑的计算能力 错的 第二题 以下选项中 哪一项不属于计算机的本质特征 C 受电力驱动 电力不是本质特征 第三题 布莱兹 帕
  • ElasticSearch学习:文档的基本操作

    上一个我们基本是围绕索引操作 里面的指定类型 或者文档里面的一些属性 这里是主要关注文档操作 毕竟主要常见的操作就是围绕文档内容来进行的 毕竟主要是做搜索 首先先导入一些数据进去 一 简单的查询操作 put testdoc user 1 n
  • 机器学习 -Statsmodels

    机器学习记录 Statsmodels 用于探索数据 估计模型 并运行统计检验 conda install y statsmodels 线性回归 import numpy as np import pandas as pd import ma
  • Linux·网络编程套接字(三)

    目录 简单的TCP英译汉服务器 简单回顾 更改handler方法 地址转换函数 字符串IP转整数IP 整数IP转字符串IP 绑定失败问题 TCP协议通讯流程 通讯流程总览 三次握手的过程 数据传输的过程 编辑 四次挥手的过程 TCP和UDP