c++: websocket 客户端与服务端之间的连接交互

2023-11-08

目录

socket

头文件

延迟时间

通信协议地址

TCP/IP

服务端

客户端

编程步骤

服务端

客户端

编程步骤

1. 初始化 WSAStartup

2. 创建 socket

2.1 协议族

2.2 socket 类型

2.3 协议

3. 绑定 bind (服务端)

4. 监听 listen(服务端)

5. 请求连接 connect(客户端)

6. 接收请求 accept(服务端)

7. 发送数据 send(客户端)

8. 接收数据 recv(服务端)

9. 关闭 closesocket

10. 停止使用 WSACleanup

实例

服务端

客户端

异常


socket

    用于描述地址和端口,是一个通信链句柄。

    套接字编程有三种:

  1. 流式套接字(SOCK_STREAM):面向连接,准确无误,但效率慢,要求数据正确性。

  2. 数据报套接字(SOCK_DGRAM):无连接,只传输,无数据校验、效率高。

头文件

#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")

延迟时间

struct timeval {
        long    tv_sec;         /* seconds */
        long    tv_usec;        /* microseconds */
};
  • tv_sec : 毫秒;

  • tx_usec : 微妙。

通信协议地址

#include <netinet/in.h>

// ipv4
struct sockaddr_in
{
    sa_family_t sin_family; // 地址族(Address Family)
    uint16_t sin_port; // 16位TCP/UDP端口号
    struct in_addr sin_addr; // 32位 IP地址
    char sin_zero[8]; // 不使用
}

struct in_addr
{
    In_addr_t s_addr; // 32位 IPv4地址
}
  • sin_port、sin_addr : 必须是网络字节序(NBO);

  • 一般可视化数字 : 主机字节序(HBO);

  • 该结构体解决了 sockaddr(sin_family、sa_data[14]) 的缺陷:把目标地址和端口信息混合在一起;

  • sockaddr_in 是 internet 环境下套接字的地址形式;

补充如下:

// ipv6
struct sockaddr_in6 { 
    sa_family_t     sin6_family;   /* AF_INET6 */ 
    in_port_t       sin6_port;     /* port number */ 
    uint32_t        sin6_flowinfo; /* IPv6 flow information */ 
    struct in6_addr sin6_addr;     /* IPv6 address */ 
    uint32_t        sin6_scope_id; /* Scope ID (new in 2.4) */ 
};
struct in6_addr { 
    unsigned char   s6_addr[16];   /* IPv6 address */

TCP/IP

    客户端向服务器发出请求,服务器接收请求后,提供相应的服务。

服务端

    建立 socket,声明自身的端口号和地址并绑定到 socket,使用 listen 打开监听,然后不断用 accept 去查看是否有连接,有就捕获 socket,并通过 recv 获取消息的内容,通信完成后调用 closeSocket 关闭这个对应 accept 到的 socket ,如果不再需要等待则 closeSocket 关闭自身 socket。

客户端

    建立 socket,通过端口号和地址确定目标服务器,使用 Connect 连接到服务器,send 发送消息,等待处理,通信完成后调用 closeSocket 关闭 socket。

编程步骤

服务端

1、加载套接字库,创建套接字(WSAStartup() / socket() );

2、绑定套接字到一个 IP 地址和一个端口上( bind() );

3、将套接字设置为监听模式等待连接请求( listen() );

4、请求到后,接收连接请求,返回一个新的对应于此连接的套接字( accept() );

5、用返回的套接字和客户端进行通信(send() / recv());

6、返回,等待另一个连接请求;

7、关闭套接字,关闭加载的库(closeSocket() / WSACleanup())。

客户端

1、加载套接字库,创建套接字(WSAStartup() / socket());

2、向服务器发出连接请求(connect());

3、和服务器进行通信(send() / recv());

4、关闭套接字,关闭加载的套接字库(closesocket() / WSACleanup());

编程步骤

1. 初始化 WSAStartup

    WSAStartup 必须是第一个 Windows 套接字函数。它允许指定 Windows 套接字版本,并检索特定 Windows 套接字实现的详细信息。

int WSAAPI WSAStartup(
  [in]  WORD      wVersionRequested, // 版本2.2 —— 0x0202 —— MAKEWORD(2,2)
  [out] LPWSADATA lpWSAData
);
  • [in] wVersionRequested

    调用方可以使用的最高版本的 Windows 套接字规范。 高顺序字节指定次要版本号;低顺序字节指定主版本号。

  • [out] lpWSAData

    指向 WSADATA 数据结构的指针,该结构用于接收 Windows 套接字实现的详细信息。

    如果 WSADATA 结构的 wVersion 成员对调用方不可接受的,则应用程序或 DLL 应调用 WSACleanup 来释放 Winsock DLL 资源,并且无法初始化 Winsock 应用程序。

2. 创建 socket

    创建的 socket 默认是一个主动类型的。

SOCKET socket(
    int domain, // 协议族
    int type, // socket 类型
    int protocol // 协议类型
);

2.1 协议族

    domain,指明通信域,决定了 socket 的地址类型。

名称 含义 名称 含义
PF_UNIX, PF_LOCAL 本地通信 PF_X25 ITU-T X25 / ISO-8208协议
AF_INET, PF_INET IPv4 Internet协议 PF_AX25 Amateur radio AX.25
PF_INET6 IPv6 Internet协议 PF_ATMPVC 原始ATM PVC访问
PF_IPX IPX-Novell协议 PF_APPLETALK Appletalk
PF_NETLINK 内核用户界面设备 PF_PACKET 底层包访问

2.2 socket 类型

    type,指定通信类型,常用的有 SOCK_STREAM、SOCK_DGRAM。

名称 含义
SOCK_STREAM TCP 连接,提供序列化的、可靠的、双向连接的字节流。支持带外数据传输
SOCK_DGRAM 支持 UDP 连接(无连接状态的消息)
SOCK_SEQPACKET 序列化包,提供一个序列化的、可靠的、双向的基本连接的数据传输通道,数据长度定常。每次调用读系统调用时数据需要将全部数据读出
SOCK_RAW RAW 类型,提供原始网络协议访问
SOCK_RDM 提供可靠的数据报文,可能数据会有乱序
SOCK_PACKET 一个专用类型,不能在通用程序中使用

2.3 协议

    protocol,指定协议,对于 TCP 可指定为 IPPROTO_TCP,UDP 可为 IPPROTO_UDP。 

协议 名称
IPPROTO_TCP TCP 传输协议
IPPROTO_TCP UDP 传输协议
IPPROTO_SCTP STCP 传输协议
IPPROTO_TIPC TIPC 传输协议
0 默认对应 type 的协议

3. 绑定 bind (服务端)

int bind(
    SOCKET sockfd, // 创建的 socket
    const struct sockaddr_in *addr, // 通信协议地址
    socklen_t addrlen // 对应协议地址的长度
);

4. 监听 listen(服务端)

    将 socket 变为被动类型的,等待客户端的连接请求。

int listen(
    SOCKET sockfd, // 监听的 socket 描述字
    int backlog // 相应 socket 可排队的最大连接个数
);

5. 请求连接 connect(客户端)

int connect(
    SOCKET sockfd, // 连接的 socket 描述字
    const struct sockaddr_in *addr, // 通信协议地址 
    socklen_t addrlen // socket 地址长度
);

    通信协议地址赋值:

  • 赋值地址:

    • inet_pton(AF_INET, “127.0.0.1”, &addr.sin_addr);

    • addr.sin_addr.S_un.S_addr = inet_addr(“127.0.0.1”);

  • 赋值端口:

    • addr.sin_port = htons(8008);

6. 接收请求 accept(服务端)

SOCKET accept(
    SOCKET sockfd, // 服务器的 socket 描述字,监听 socket 描述字
    struct sockaddr_in *addr, // 通信协议地址
    socklen_t *addrlen // 协议地址的长度
);
  • 返回值是一个由内核自动生成的全新 socket 描述字,代表与返回客户端的 TCP 连接。

7. 发送数据 send(客户端)

int WSAAPI send(
  [in] SOCKET     sockfd, // 连接的 socket 描述字
  [in] const char *sendbuf, // 发送的多字节数据缓冲区
  [in] int        buflen, // 发送多字节长度
  [in] int        flags // 指定进行调用的方式
);

// Linux
// read()
  • buflen :

    • 大于发送缓冲区的长度,返回 SOCKET_ERROR;

    • 小于或等于时,send 先检查协议是否在发送 socket 数据,是则等待发送完,否则就进行比较 socket 发送缓冲区的剩余空间:

      • 大于剩余空间大小,则一直等待 socket 发送完;

      • 小于剩余空间大小,则将 sendbuf 数据 copy 到剩余空间中。

  • flags :

MSG_DONTROUTE 指定不应对数据进行路由。Windows 套接字服务提供商可以选择忽略此标志。
MSG_OOB 发送 OOB 数据(流样式套接字,例如仅SOCK_STREAM)。

8. 接收数据 recv(服务端)

int WSAAPI recv(
  [in] SOCKET     sockfd, // 标识连接的 socket 描述字
  [in] const char *recvbuf, // 接收的多字节数据缓冲区
  [in] int        buflen, // 接收的多字节长度
  [in] int        flags // 指定进行调用的方式
);

// Linux
// read()
  • recvbuf : 接收数据之前,必须 memset 进行清空,接收的数据不一定填满空间;

  • 返回值:

    • 未发生错误,则将返回接收到的字符数,recvbuf 指向的缓冲区将包含接收的数据;

    • 如果连接已正常关闭,则返回 0;

    • 否则返回 SOCKET_ERROR ,通过调用 WSAGetLastError 来检索特定的错误代码。

错误代码:recv 函数 (winsock2.h) - Win32 apps | Microsoft Learn

9. 关闭 closesocket

int closesocket(
  [in] SOCKET s
);
  • 返回:

    • 无异常,返回 0 ;

    • 否则将返回一个 SOCKET_ERROR 值:

      错误代码 意义
      WSANOTINITIALISED 未初始化调用 WSAStartup
      WSAENETDOWN 网络子系统出现故障
      WSAENOTSOCK 描述符不是套接字
      WSAEINPROGRESS 阻止 Windows 套接字 1.1 调用正在进行中,或者服务提供商仍在处理回调函数。
      WSAEINTR (阻止)Windows Socket 1.1 调用已通过 WSACancelBlockingCall 取消。
      WSAEWOULDBLOCK 套接字标记为非阻塞,但延迟结构的 l_onoff 成员设置为非零,l_linger 成员的延迟结构设置为非零超时值。

补充:close 标记 TCP socket 为已关闭,不可作为读写数据的第一个参数:

// Linux
#include <unistd.h>
int close(int fd);

注意:close 只是使 socket 描述字的引用计数 -1,当引用计数为 0 才会触发 TCP 客户端向服务器发送终止连接请求。

10. 停止使用 WSACleanup

int WSACleanup();
  • 返回值:

    • 无异常返回 0;

    • 否则,返回 SOCKET_ERROR 值,调用  WSAGetLastError 来检索特定的错误代码。

      错误代码 意义
      WSANOTINITIALISED* 未初始化调用 WSAStartup
      WSAENETDOWN 网络子系统出现故障
      WSAEINPROGRESS 阻止 Windows 套接字 1.1 调用正在进行中,或者服务提供商仍在处理回调函数。

实例

服务端

#include <stdio.h>  
#include <winsock2.h>  

#pragma comment(lib,"ws2_32.lib")  

int main(int argc, char* argv[])  
{  
    //初始化WSA  
    WORD sockVersion = MAKEWORD(2,2);  
    WSADATA wsaData;  
    if(WSAStartup(sockVersion, &wsaData)!=0)  
    {  
        return 0;  
    }  

    //创建套接字  
    SOCKET slisten = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);  
    if(slisten == INVALID_SOCKET)  
    {  
        printf("socket error !");  
        return 0;  
    }  

    //绑定IP和端口  
    sockaddr_in sin;  
    sin.sin_family = AF_INET;  
    sin.sin_port = htons(8888);  
    sin.sin_addr.S_un.S_addr = INADDR_ANY;   
    if(bind(slisten, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR)  
    {  
        printf("bind error !");  
    }  

    //开始监听  
    if(listen(slisten, 5) == SOCKET_ERROR)  
    {  
        printf("listen error !");  
        return 0;  
    }  

    //循环接收数据  
    SOCKET sClient;  
    sockaddr_in remoteAddr;  
    int nAddrlen = sizeof(remoteAddr);  
    char revData[255];   
    while (true)  
    {  
        printf("等待连接...\n");  
        sClient = accept(slisten, (SOCKADDR *)&remoteAddr, &nAddrlen);  
        if(sClient == INVALID_SOCKET)  
        {  
            printf("accept error !");  
            continue;  
        }  
        printf("接受到一个连接:%s \r\n", inet_ntoa(remoteAddr.sin_addr));  

        //接收数据  
        int ret = recv(sClient, revData, 255, 0);         
        if(ret > 0)  
        {  
            revData[ret] = 0x00;  
            printf(revData);  
        }  

        //发送数据  
        const char * sendData = "你好,TCP客户端!\n";  
        send(sClient, sendData, strlen(sendData), 0);  
        closesocket(sClient);  
    }  

    closesocket(slisten);  
    WSACleanup();  
    return 0;  
} 

客户端

#include<WINSOCK2.H>
#include<STDIO.H>
#include<iostream>
#include<cstring>
using namespace std;
#pragma comment(lib, "ws2_32.lib")

int main()
{
    WORD sockVersion = MAKEWORD(2, 2);
    WSADATA data;
    if(WSAStartup(sockVersion, &data)!=0)
    {
        return 0;
    }
    while(true){
        SOCKET sclient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
        if(sclient == INVALID_SOCKET)
        {
            printf("invalid socket!");
            return 0;
        }

        sockaddr_in serAddr;
        serAddr.sin_family = AF_INET;
        serAddr.sin_port = htons(8888);
        serAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        if(connect(sclient, (sockaddr *)&serAddr, sizeof(serAddr)) == SOCKET_ERROR)
        {  //连接失败 
            printf("connect error !");
            closesocket(sclient);
            return 0;
        }

        string data;
        cin>>data;
        const char * sendData;
        sendData = data.c_str();   //string转const char* 
        //char * sendData = "你好,TCP服务端,我是客户端\n";
        send(sclient, sendData, strlen(sendData), 0);
        //send()用来将数据由指定的socket传给对方主机
        //int send(int s, const void * msg, int len, unsigned int flags)
        //s为已建立好连接的socket,msg指向数据内容,len则为数据长度,参数flags一般设0
        //成功则返回实际传送出去的字符数,失败返回-1,错误原因存于error 

        char recData[255];
        int ret = recv(sclient, recData, 255, 0);
        if(ret>0){
            recData[ret] = 0x00;
            printf(recData);
        } 
        closesocket(sclient);
    }

    WSACleanup();
    return 0;    
} 

异常

  • undefined reference to '_imp_WSAStartup‘

    解决方案:vs 属性工具 -> 编译选项 -> 链接器命令行 -> 命令添加 -lwsock32

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

c++: websocket 客户端与服务端之间的连接交互 的相关文章

  • 每个托管线程是否都有自己对应的本机线程?

    我想知道是否在 Net 中创建托管线程 通过调用Thread Start 导致在后台创建一个本机线程 那么托管线程是否有对应的本机线程呢 如果是 当托管线程等待或睡眠时 是否意味着相应的本机线程也在等待或睡眠 是的 NET 线程映射到所有当
  • 未提供参数时如何指定 C# System.Commandline 行为?

    在我的控制台应用程序中 当未提供控制台参数时 将执行我指定列表 在本例中为参数 3 的任何处理程序 调用该处理程序时 布尔参数设置为 false 但对我来说 根本不调用它更有意义 如何防止这种情况发生并显示帮助文本 using System
  • 在 C 中匹配二进制模式

    我目前正在开发一个 C 程序 需要解析一些定制的数据结构 幸运的是我知道它们是如何构造的 但是我不确定如何在 C 中实现我的解析器 每个结构的长度都是 32 位 并且每个结构都可以通过其二进制签名来识别 举个例子 有两个我感兴趣的特定结构
  • 使用 LINQ2SQL 在 ASP.NET MVC 中的各种模型存储库之间共享数据上下文

    我的应用程序中有 2 个存储库 每个存储库都有自己的数据上下文对象 最终结果是我尝试将从一个存储库检索到的对象附加到从另一个存储库检索到的对象 这会导致异常 Use 构造函数注入将 DataContext 注入每个存储库 public cl
  • 使用接口有什么好处?

    使用接口有什么用 我听说它用来代替多重继承 并且还可以用它来完成数据隐藏 还有其他优点吗 哪些地方使用了接口 程序员如何识别需要该接口 有什么区别explicit interface implementation and implicit
  • qdbusxml2cpp 未知类型

    在使用 qdbusxml2cpp 程序将以下 xml 转换为 Qt 类时 我收到此错误 qdbusxml2cpp c ObjectManager a ObjectManager ObjectManager cpp xml object ma
  • 是否有实用的理由使用“if (0 == p)”而不是“if (!p)”?

    我倾向于使用逻辑非运算符来编写 if 语句 if p some code 我周围的一些人倾向于使用显式比较 因此代码如下所示 if FOO p some code 其中 FOO 是其中之一false FALSE 0 0 0 NULL etc
  • 我可以使用 moq Mock 来模拟类而不是接口吗?

    正在经历https github com Moq moq4 wiki Quickstart https github com Moq moq4 wiki Quickstart 我看到它 Mock 一个接口 我的遗留代码中有一个没有接口的类
  • 如何检测表单的任何控件的变化?

    如何检测 C 中表单的任何控件的更改 由于我在一个表单上有许多控件 并且如果表单中的任何控件值发生更改 我需要禁用按钮 我正在寻找一些内置函数 事件处理程序 属性 并且不想为此创建自定义函数 不 我不知道任何时候都会触发任何事件any控制表
  • Azure 辅助角色“请求输入之一超出范围”的内部异常。

    我在辅助角色中调用 CloudTableClient CreateTableIfNotExist 方法 但收到一个异常 其中包含 请求输入之一超出范围 的内部异常 我做了一些研究 发现这是由于将表命名为非法表名引起的 但是 我尝试为我的表命
  • 外键与独立关系 - Entity Framework 5 有改进吗?

    我读过了several http www ladislavmrnka com 2011 05 foreign key vs independent associations in ef 4 文章和问题 https stackoverflow
  • 如何设置 log4net 每天将我的文件记录到不同的文件夹中?

    我想将每天的所有日志保存在名为 YYYYMMdd 的文件夹中 log4net 应该根据系统日期时间处理创建新文件夹 我如何设置它 我想将一天中的所有日志保存到 n 个 1MB 的文件中 我不想重写旧文件 但想真正拥有一天中的所有日志 我该如
  • C++ 函数重载类似转换

    我收到一个错误 指出两个重载具有相似的转换 我尝试了太多的事情 但没有任何帮助 这是那段代码 CString GetInput int numberOfInput BOOL clearBuffer FALSE UINT timeout IN
  • 不同类型指针之间的减法[重复]

    这个问题在这里已经有答案了 我试图找到两个变量之间的内存距离 具体来说 我需要找到 char 数组和 int 之间的距离 char data 5 int a 0 printf p n p n data 5 a long int distan
  • C++ 条件编译

    我有以下代码片段 ifdef DO LOG define log p record p else define log p endif void record char data 现在如果我打电话log hello world 在我的代码中
  • 无法接收 UDP Windows RT

    我正在为 Windows 8 RT 编写一个 Windows Store Metro Modern RT 应用程序 需要在端口 49030 上接收 UDP 数据包 但我似乎无法接收任何数据包 我已按照使用教程进行操作DatagramSock
  • 如何从 ODBC 连接获取可用表的列表?

    在 Excel 中 我可以转到 数据 gt 导入外部数据 gt 导入数据 然后选择要使用的数据源 然后在提供登录信息后 它会给我一个表格列表 我想知道如何使用 C 以编程方式获取该列表 您正在查询什么类型的数据源 SQL 服务器 使用权 看
  • 当从finally中抛出异常时,Catch块不会被评估

    出现这个问题的原因是之前在 NET 4 0 中运行的代码在 NET 4 5 中因未处理的异常而失败 部分原因是 try finallys 如果您想了解详细信息 请阅读更多内容微软连接 https connect microsoft com
  • 如何将 PostgreSql 与 EntityFramework 6.0.2 集成? [复制]

    这个问题在这里已经有答案了 我收到以下错误 实体框架提供程序类型的 实例 成员 Npgsql NpgsqlServices Npgsql 版本 2 0 14 2 文化 中性 PublicKeyToken 5d8b90d52f46fda7 没
  • 当我使用 OpenSSL1.1.0g 根据固定的 p 和 g 值创建 Diffie Hellman 密钥协议密钥时,应该执行哪些检查?

    您好 我尝试通过这段代码使用修复 p 和 g 参数来制作 Diffie Hellman Keysanswer https stackoverflow com a 54538811 4706711 include

随机推荐

  • OC_YYModel字典转模型的几种详细用法

    OC YYModel字典转模型的几种详细用法 目录 JSON转字符串 普通字典转模型 模型属性有自定义的模型YYUSer 属性有数组 数组里自定义模型 还有字典和集合 字典里的key与模型里的属性名不一致 常用的几个方法 json转模型 i
  • 以太坊分片Sharding FAQ

    简介 目前 在所有的区块链协议中每个节点存储所有的状态 账户余额 合约代码和存储等等 并且处理所有的交易 这提供了大量的安全性 但极大的限制了可扩展性 区块链不能处理比一个单节点更多的交易 很大程度上因为这个原因 比特币被限制在每秒3 7笔
  • 【Linux篇】第八篇——Linux下的进程控制(进程创建+进程终止+进程等待+进程程序替换+简易shell的实现)

    这篇博客就要开始聊一聊进程控制相关的内容了 这部分的内容十分的丰富且十分的重要 学好这一块内容是非常有必要的 目录 进程创建 fork函数 写时拷贝 进程终止 进程退出的三种场景 进程常见的退出方法 进程等待 进程等待的方法 wait方法
  • Unity 实用小技巧合集

    Unity小技巧介绍 一 Unity小技巧介绍 二 Unity小技巧介绍 三 Unity小技巧介绍 四
  • 用canvas绘制微信小程序海报页面并保存相册-适用微信原生

    微信小程序绘制海报并保存相册 tip 代码中使用的是uni的api 如果使用原生微信小程序开发 可以把uni更换成wx使用 文章目录 微信小程序绘制海报并保存相册 前言 一 分析需求 二 准备数据 三 编码开始 html部分 解析 js部分
  • Python中使用xpath获取select option的每一行的text和value

    原数据内容如下
  • 设计模式--适配器模式

    适配器模式属于结构型模式 基本原理 根据不同的需求 使用一个适配器去寻找应对的方法 主要流程 1 创建解决方法的类 2 创建一个适配器 根据不同需求对应相应的解决方法 3 使用一个类去分配适配器 注意 适配器不是在详细设计时添加的 而是解决
  • C语言本身是用什么语言写的?

    先说结论 C语言由B语言编写 B语言是由A语言编写 A B C 好了 不开玩笑了 既然你能提出这个级别的问题 说明你应该学过C 既然你能提出这个级别的问题 说明你没学过编译原理 或者全还给老师了 容我不厚道一下下 你所谓的 C语言 准确来说
  • 基于 Flink CDC 高效构建入湖通道

    本文整理自阿里云 Flink 数据通道负责人 Flink CDC 开源社区负责人 Apache Flink PMC Member Committer 徐榜江 雪尽 在 Streaming Lakehouse Meetup 的分享 内容主要分
  • 免费虚拟局域网(VLAN)组建教程

    虚拟局域网 VLAN 是一组逻辑上的设备和用户 这些设备和用户并不受物理位置的限制 可以根据功能 部门及应用等因素将它们组织起来 相互之间的通信就好像它们在同一个网段中一样 由此得名虚拟局域网 虚拟局域网在日常的工作生活中 起着非常大的作用
  • superset的docker安装配置和汉化

    1 docker拉去superset镜像 docker pull amancevice superset 2 启动容器 1 启动容器 docker run d p 8188 8088 name superset v opt docker s
  • 【Latex排版】使用Latex 排版过程中的那些一二三问题汇总

    排版错误问题总结 1 在 maketitle 位置处报错 Missing inserted 2 添加参考文献 编译后显示错误 并且pdf中引用文献处为问号 持续更新问题 近期用Latex整理期刊论文时遇到了不少问题 现把遇到的问题及最终解决
  • 【华为OD统一考试A卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • React 深度学习:Fiber-ReactFiberLazyComponent

    ReactLazyComponent 包 packages shared ReactLazyComponent js Copyright c Facebook Inc and its affiliates This source code
  • 深入理解线程与并发

    文章目录 计算机硬件与并发 线程与Thread类 线程的特点 线程的优先级 线程控制 总结 个人主页 程序员 小侯 CSDN新晋作者 欢迎 点赞 评论 收藏 收录专栏 Java知识介绍 适用于 Java初学者 希望作者的文章能对你有所帮助
  • go 语言学习笔记 0001 --> iota

    go语言中预置了一个预定义常量 iota 这个东西有个很奇怪的特性 会根据 const 关键字改变值 默认的 iota在const出现的时候会初始化为0 而后不断递加1 直到出现第二个const关键字 const countagn1 2 l
  • java持久层框架mybatis如何防止sql注入

    sql注入大家都不陌生 是一种常见的攻击方式 攻击者在界面的表单信息或url上输入一些奇怪的sql片段 例如 or 1 1 这样的语句 有可能入侵参数校验不足的应用程序 所以在我们的应用中需要做一些工作 来防备这样的攻击方式 在一些安全性很
  • Ubuntu18.04+Docker+Hadoop+Spark分布式集群搭建

    题前记 因为课程需求 下面将搭建过程用学术论文的格式写 其实我并不想写的 没办法 学习作业嘛QAQ 我的联系方式 630056108 文章目录 Docker上的Hadoop大数据平台搭建与测试 1 简介与原理 1 1 Docker介绍 1
  • 电脑安装双系统

    1 准备工具 我们需要安装两个系统 win10和deepin 准备2个u盘 1个u盘使用优启通制作pe 支持uefi启动 1个u盘使用deepin官网上的启动盘制作工具制作启动盘 2 基础知识 2 1 磁盘格式 磁盘格式分为mbr和guid
  • c++: websocket 客户端与服务端之间的连接交互

    目录 socket 头文件 延迟时间 通信协议地址 TCP IP 服务端 客户端 编程步骤 服务端 客户端 编程步骤 1 初始化 WSAStartup 2 创建 socket 2 1 协议族 2 2 socket 类型 2 3 协议 3 绑