当前位置: 首页 > news >正文

Linux网络-Socket套接字_Windows与Linux端双平台基于Udp传输协议进行多线程跨平台的服务器与客户端网络通信的简易聊天室实现

文章目录

  • 一、Socket套接字
  • 二、Udp 常见API
    • 1. int socket(int domain, int type, int protocol);
    • 2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);
      • struct sockaddr
    • 3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address,socklen_t *restrict address_len);
    • 4. ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr,socklen_t dest_len);
    • 5. uint16_t htons(uint16_t hostshort);
      • 网络字节序
    • 6. in_addr_t inet_addr(const char *cp);
  • 三、Server端
    • 1.初始化Socket套接字
    • 2.发送和接收
    • Server端全代码
      • const std::string default_ip = "0.0.0.0";
  • Client端
  • Windows Client端
  • 简易聊天室运行图


一、Socket套接字

在互联网中,我们在网络层采用 IP + 端口号 的方式即可在全网中找到唯一进程,IP标识唯一主机,端口号标识该主机端口号绑定的进程。

这就是Socket套接字。


二、Udp 常见API

1. int socket(int domain, int type, int protocol);

创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)

参数 int domin :指定要在其中创建套接字的通信域。这里我们使用AF_INET采用IPV4通信域。

参数 int type : 指定要创建的套接字类型。 Udp协议是采用面向数据流,所以是用SOCK_DGRAM。

参数 int protocol :指定与套接字一起使用的特定协议。

返回值: 如果成功则返回创建的socket 文件描述符, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == -1){exit(1);}

2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);

绑定端口号 (TCP/UDP, 服务器)
参数 int socket 就是使用socket接口函数所创建的那个socket文件描述符。

struct sockaddr

在这里插入图片描述
由于底层有不同的网络协议,所以它们的地址格式并不相同,所以通常使用struct sockaddr* 作为参数,然后根据前16位地址类型来确定协议内容。

参数 socklen_t address_len, 结构体sockaddr的长度。
typedef unsigned int socklen_t

返回值: 如果绑定成功则返回0, 失败则返回-1.

代码示例

		int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == -1){exit(1);}struct sockaddr_in Server;bzero(&Server, 0);Server.sin_family = AF_INET;Server.sin_addr.s_addr = inet_addr(_ip.c_str()); //?Server.sin_port = htons(_port); //?int n = bind( socket_fd, (const struct sockaddr *)&Server, sizeof(Server));if (n != 0){exit(2);}

3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length, int flags, struct sockaddr *restrict address,socklen_t *restrict address_len);

参数 int socket 就是使用socket接口函数所创建的那个socket文件描述符。
参数 void *restrict buffer为缓冲区,可以用来存放接收的字节数据。
参数 size_t length 为读取的字节长度。
参数 struct sockaddr *restrict address,输出型参数,用于获取发送方的socketaddr。
参数 socklen_t *restrict address_len,输出型参数,用于获取发送方的sockaddr的长度。

示例代码

		char inbuffer[1024];while (true){struct sockaddr_in client;socklen_t len = sizeof(client); // unsigned intbzero(&client, 0);// 服务器接受数据ssize_t n = recvfrom(_socket_fd, inbuffer, sizeof inbuffer - 1, 0, (sockaddr *)&client, &len);if (n > 0){std::string client_ip = inet_ntoa(client.sin_addr);uint16_t client_port = ntohs(client.sin_port);userCheck(client_ip, client);inbuffer[n] = '\0';if(strcmp(inbuffer,"login\0") == 0) continue;std::string info = func(inbuffer, client_ip, client_port);senMessage(info);}}

4. ssize_t sendto(int socket, const void *message, size_t length, int flags, const struct sockaddr *dest_addr,socklen_t dest_len);

参数与 recvfrom类似。不同的是,这里的const struct sockaddr *dest_addr和socklen_t dest_len 变成了输入型参数。 因为你要发送消息,就需要知道对方的socket信息。

5. uint16_t htons(uint16_t hostshort);

这个函数的作用是什么呢? 这就涉及到网络字节序

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

规定网络数据在内存中必须采用大端存储方式!!

如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可

所以这个函数的作用就是将hostshort转换为网络字节序。

6. in_addr_t inet_addr(const char *cp);

由于我们习惯将IP地址 写成这样的格式xxx.xxx.xxx.xxx(例如192.168.0.1),而在网络层面,我们肯定是采用四字节的int来存储IP,所以有这么一个函数将一个xxx.xxx.xxx.xxx的格式的IP转换为四字节int。

三、Server端

1.初始化Socket套接字

代码如下(示例):

		// 申请套接字int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == -1){logMessage(FATAL, "Socket Applied Fault");exit(SOCKET_DENIED);}_socket_fd = socket_fd;logMessage(DEBUG, "Socket Applied Success");// bind套接字struct sockaddr_in Server;bzero(&Server, 0);Server.sin_family = AF_INET;Server.sin_addr.s_addr = inet_addr(_ip.c_str()); // inet_addr可以将ip形式x.x.x.x的字符串转化为大段存储的in_addr_t类型(typedef uint32_t in_addr_t;)Server.sin_port = htons(_port);int n = bind(_socket_fd, (const struct sockaddr *)&Server, sizeof(Server));if (n != 0){logMessage(FATAL, "Bind Fault");exit(BIND_FAULT);}

2.发送和接收

代码如下(示例):

void userCheck(std::string &client_ip, struct sockaddr_in &user){auto it = _user_map.find(client_ip);// std::cout << "开始检测" << std::endl; if (it == _user_map.end()){//没找到std::cout << "新用户[" << client_ip << "]上线..." << std::endl;}_user_map[client_ip] = user;}void senMessage(const std::string& info){for(auto& user:_user_map ){sendto(_socket_fd, info.c_str(), info.size(), 0, (const struct sockaddr *)&(user.second), sizeof(user.second));}}std::string func(const char *res, const std::string& client_ip, const uint16_t client_port){char buffer [1024];snprintf(buffer, sizeof buffer,"[%s:%d]# %s",client_ip.c_str(),client_port,res);std::string mes = buffer;std::cout << mes << std::endl; return mes;}void run(func_t func){char inbuffer[1024];while (true){struct sockaddr_in client;socklen_t len = sizeof(client); // unsigned intbzero(&client, 0);// 服务器接受数据ssize_t n = recvfrom(_socket_fd, inbuffer, sizeof inbuffer - 1, 0, (sockaddr *)&client, &len);if (n > 0){std::string client_ip = inet_ntoa(client.sin_addr);uint16_t client_port = ntohs(client.sin_port);userCheck(client_ip, client);inbuffer[n] = '\0';if(strcmp(inbuffer,"login\0") == 0) continue;std::string info = func(inbuffer, client_ip, client_port);senMessage(info);}}}

Server端全代码

                  //UdpServer.hpp  
#pragma once
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <cstdlib>
#include <unistd.h>
#include "log.hpp"
#include <netinet/in.h>
#include <string.h>
#include <arpa/inet.h>
#include <functional>
#include <unordered_map>
const std::string default_ip = "0.0.0.0"; //?typedef std::function<std::string(const char*, const std::string &, const uint16_t)> func_t;enum
{SOCKET_DENIED = 1,BIND_FAULT
};class UdpServer
{
public:UdpServer(const std::string &ip = default_ip, const uint16_t port = 8080): _socket_fd(0), _ip(ip), _port(port){}void init(){// 申请套接字int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == -1){logMessage(FATAL, "Socket Applied Fault");exit(SOCKET_DENIED);}_socket_fd = socket_fd;logMessage(DEBUG, "Socket Applied Success");// bind套接字struct sockaddr_in Server;bzero(&Server, 0);Server.sin_family = AF_INET;Server.sin_addr.s_addr = inet_addr(_ip.c_str()); // inet_addr可以将ip形式x.x.x.x的字符串转化为大段存储的in_addr_t类型(typedef uint32_t in_addr_t;)Server.sin_port = htons(_port);int n = bind(_socket_fd, (const struct sockaddr *)&Server, sizeof(Server));if (n != 0){logMessage(FATAL, "Bind Fault");exit(BIND_FAULT);}}void userCheck(std::string &client_ip, struct sockaddr_in &user){auto it = _user_map.find(client_ip);// std::cout << "开始检测" << std::endl; // std::cout << (*it).first << std::endl; if (it == _user_map.end()){//没找到std::cout << "新用户[" << client_ip << "]上线..." << std::endl;}_user_map[client_ip] = user;}void senMessage(const std::string& info){for(auto& user:_user_map ){sendto(_socket_fd, info.c_str(), info.size(), 0, (const struct sockaddr *)&(user.second), sizeof(user.second));// std::cout << "已发送数据给" << user.first << std::endl; }}void run(func_t func){char inbuffer[1024];while (true){struct sockaddr_in client;socklen_t len = sizeof(client); // unsigned intbzero(&client, 0);// 服务器接受数据ssize_t n = recvfrom(_socket_fd, inbuffer, sizeof inbuffer - 1, 0, (sockaddr *)&client, &len);if (n > 0){std::string client_ip = inet_ntoa(client.sin_addr);uint16_t client_port = ntohs(client.sin_port);// std::cout <<  client_ip << " : " << client_port <<std::endl;userCheck(client_ip, client);inbuffer[n] = '\0';if(strcmp(inbuffer,"login\0") == 0) continue;// std::cout << "Server get message# " << inbuffer << std::endl;std::string info = func(inbuffer, client_ip, client_port);senMessage(info);// sendto(_socket_fd, info.c_str(), info.size(), 0, (const struct sockaddr *)&client, len);// sendto(_socket_fd, inbuffer, sizeof inbuffer, 0, (const struct sockaddr *)&client, len);}}}~UdpServer(){if (_socket_fd == 0){close(_socket_fd);}}private:int _socket_fd;std::string _ip;uint16_t _port;std::unordered_map<std::string, struct sockaddr_in> _user_map;
};
                            //main.cc
#include "Udpserver.hpp"std::string func(const char *res, const std::string& client_ip, const uint16_t client_port)
{//std::cout << "[" << client_ip << " : " << client_port << "] # " << res << std::endl;char buffer [1024];snprintf(buffer, sizeof buffer,"[%s:%d]# %s",client_ip.c_str(),client_port,res);std::string mes = buffer;std::cout << mes << std::endl; return mes;
}int main()
{UdpServer us;us.init();us.run(func);return 0;
}

const std::string default_ip = “0.0.0.0”;

服务器将ip绑定为0.0.0.0是什么意思呢?
指定ip为本机的任意ip. 尤其适用于本机有多个网卡的情况下,可根据目的地址的默认路由选择合适的网卡建立链路,收发数据。

在这里插入图片描述

Client端

#define terminal "/dev/pts" 
void Usage(std::string proc)
{std::cout << "\n\rUsage: " << proc << " serverip serverport\n"<< std::endl;
}enum
{SOCKET_DENIED = 1,
};struct Thread_Data
{int socket_fd;struct sockaddr_in server;
};void *recv_mes(void *args)
{Thread_Data* data = (Thread_Data*)args;char buffer[1024];bzero(buffer,0);while (true){struct sockaddr_in tmp;socklen_t tmp_len;int n = recvfrom(data->socket_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&tmp, &tmp_len);if (n > 0){buffer[n] = 0;std::cerr <<  buffer << std::endl;}bzero(buffer,0);}
}void *send_mes(void *args)
{Thread_Data* data = (Thread_Data*)args;std::string message = "login";sendto(data->socket_fd, message.c_str(), message.size(), 0, (const struct sockaddr *)&data->server, sizeof(data->server));while (true){std::cout << "Please Enter Message@ ";std::getline(std::cin, message);sendto(data->socket_fd, message.c_str(), message.size(), 0, (const struct sockaddr *)&data->server, sizeof(data->server));}
}int main(int args, char *argv[])
{if (args != 3){Usage("./UdpClient");}int socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == -1){logMessage(FATAL, "Socket Applied Fault");exit(SOCKET_DENIED);}struct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(argv[1]);server.sin_port = htons(std::atoi(argv[2]));pthread_t recv_thread, send_thread;Thread_Data data;data.server = server;data.socket_fd = socket_fd;pthread_create(&send_thread, nullptr, send_mes, (void *)&data);pthread_create(&recv_thread, nullptr, recv_mes, (void *)&data);pthread_join(recv_thread, nullptr);pthread_join(send_thread, nullptr);return 0;
}

采用了多线程的方式, 这里需要知道,因为socket本就支持同时可读可写,我们可以理解为它就是线程安全的。

Windows Client端

#include<iostream>
#include<string>
#include<WinSock2.h>
#include<Windows.h>
#include<thread>
#include<functional>
#pragma comment(lib, "ws2_32.lib") // 链接库文件
#pragma warning(disable:4996)      //防止VS发出4996号警告const int server_port = 8080;
const std::string server_ip = ""; //提前写好服务器IP//warning : 多线程版本仍有一些小问题  
struct Thread_Data
{SOCKET socket_fd;struct sockaddr_in server;
};void recv_mes(const Thread_Data& data)
{char buffer[1024];while (true){memset(buffer, 0, sizeof(buffer));struct sockaddr_in tmp;int tmp_len = sizeof(tmp);int n = recvfrom(data.socket_fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*)&tmp, &tmp_len);if (n > 0){buffer[n] = 0;std::cout << buffer << std::endl;}//std::cout << n << " errno:" << errno << std::endl;}
}void send_mes(const Thread_Data& data)
{std::string message;std::cout << "Send A Message To Start A Chat ";while (true){std::getline(std::cin, message);sendto(data.socket_fd, message.c_str(), (int)message.size(), 0, (const struct sockaddr*)&data.server, sizeof(data.server));}
}
int main()
{//初始化网络环境WSADATA wsd;    WSAStartup(MAKEWORD(2, 2), &wsd);system("chcp 65001");SOCKET socket_fd = socket(AF_INET, SOCK_DGRAM, 0);if (socket_fd == SOCKET_ERROR){perror("Socket Error");exit(1);}struct sockaddr_in server;memset(&server, 0, sizeof server);server.sin_family = AF_INET;server.sin_addr.s_addr = inet_addr(server_ip.c_str());server.sin_port = htons(server_port);std::thread threads[2];Thread_Data data;data.server = server;data.socket_fd = socket_fd;sendto(socket_fd, "login", 5, 0, (const struct sockaddr*)&server, sizeof(server));threads[0] = std::thread(recv_mes, std::ref(data));threads[1] = std::thread(send_mes, std::ref(data));threads[0].join();threads[1].join();closesocket(socket_fd);WSACleanup();   //清理网络环境return 0;}

这里的Windows端也是实现了一个多线程的版本,因为是不同的操作系统,在接口上是有一些差别的,不过大部分都差不多。

简易聊天室运行图

在这里插入图片描述

相关文章:

Linux网络-Socket套接字_Windows与Linux端双平台基于Udp传输协议进行多线程跨平台的服务器与客户端网络通信的简易聊天室实现

文章目录 一、Socket套接字二、Udp 常见API1. int socket(int domain, int type, int protocol);2. int bind(int socket, const struct sockaddr *address, socklen_t address_len);struct sockaddr 3. ssize_t recvfrom(int socket, void *restrict buffer, size_t length, i…...

20分钟快速入门SQL

SQL&#xff08;Structured Query Language&#xff0c;结构化查询语言&#xff09;是一种专门用来管理和操作关系型数据库的编程语言。以下是SQL入门的一些基础概念和教程&#xff1a; 1. SQL基础 数据库&#xff08;Database&#xff09;&#xff1a;存储数据的集合。表&am…...

汇总区间,合并区间

题目一&#xff1a; 代码如下&#xff1a; vector<string> summaryRanges(vector<int>& nums) {vector<string> ret;if (nums.size() 0)return ret;int n nums.size();int i 0;while (i < n){int prev i;i;while (i < n && nums[i] n…...

Web程序设计-实验05 DOM与BOM编程

题目 【实验主题】 影视网站后台影视记录管理页设计 【实验任务】 1、浏览并分析多个网站后台的列表页面、编辑页面&#xff08;详见参考资源&#xff0c;建议自行搜索更多后台页面&#xff09;的主要元素构成和版面设计&#xff0c;借鉴并构思预期效果。 2、新建 index.h…...

Window系统安装Docker

因为docker只适合在liunx系统上运行&#xff0c;如果在window上安装的话&#xff0c;就需要开启window的虚拟化&#xff0c;打开控制面板&#xff0c;点击程序&#xff0c;在程序和功能中可以看到启动和关闭window功能&#xff0c;点开后&#xff0c;找到Hyper-V&#xff0c;Wi…...

RabbitMQ不完整的笔记

同步的不足 1、拓展性差&#xff0c;当要添加功能时&#xff0c;需要在原来的功能代码上做修改&#xff0c;高耦合。 2、性能下降&#xff0c;调用者需要等待服务提供者执行完返回结果后&#xff0c;才能继续向下执行 3、级联失败&#xff0c;由于我们是基于OpenFeign调用交易…...

微软Edge浏览器深度解析:功能、同步、隐私与安全

微软Edge浏览器是微软公司开发的一款网页浏览器,它基于Chromium内核,提供了快速、安全和兼容性良好的网页浏览体验。以下是关于微软Edge浏览器的详细信息和使用指南: 微软Edge浏览器的主要特点: 1. 基于Chromium内核: 渲染引擎:Chromium内核是基于开源项目Blink的,它…...

网络性能测试工具:iperf3介绍

文章目录 前言一、iperf3 的安装和使用下载和安装参数说明 二、iperf3 测试服务端启动客户端启动服务端输出反向测试客户端服务端 前言 新接触的网络环境如何评估网络带宽和吞吐量呢&#xff0c;有的项目没有对业务流量进行合理规划&#xff0c;服务或者中间件出口带宽经常有被…...

scp:Linux系统本地与远程文件传输命令

scp 是Linux系统中用于在本地主机和远程主机之间进行文件传输的命令。 详细说明&#xff1a; scp 命令用于安全地将文件从一个主机传输到另一个主机&#xff0c;所有传输数据都是加密的。语法&#xff1a; scp [参数] [源文件路径] [目标主机:目标路径] 参数说明&#xff1a…...

python基础(习题、资料)

免费提取资料&#xff1a; 练习、资料免费提取。持续更新迅雷云盘https://pan.xunlei.com/s/VNz6kH1EXQtK8j-wwwz_c0k8A1?pwdrj2x# 本文为Python的进阶知识合辑&#xff0c;包括列表&#xff08;List&#xff09;、元组&#xff08;Tuple&#xff09;、字典&#xff08;Dic…...

shell脚本免交互

shell脚本的编写一方面为了减少我们命令的输入&#xff0c;另一方面也可以进行简单的自动化运行&#xff0c;其中为了实现自动化过程&#xff0c;一个很重要的点就是免交互&#xff0c;本篇文章跟大家简单分享两个常用的免交互的方法。 Here Document Here document 通过内联重…...

WPF学习笔记:给文字添加线性渐变效果

<TextBox Text"XXX信息管理系统" VerticalAlignment"Center" Background"Transparent" HorizontalAlignment"Center" FontSize"35" FontWeight"Normal"> <TextBox.Effect> <…...

Fully Convolutional Networks for Semantic Segmentation--论文笔记

论文笔记 资料 1.代码地址 2.论文地址 https://arxiv.org/abs/1411.4038 3.数据集地址 论文摘要的翻译 卷积网络是强大的视觉模型&#xff0c;可以产生特征层次结构。我们表明&#xff0c;卷积网络本身&#xff0c;经过端到端&#xff0c;像素对像素的训练&#xff0c;在…...

Camworks编程怎么样:深度解析其四大特点、五大应用领域、六大优势与七大挑战

Camworks编程怎么样&#xff1a;深度解析其四大特点、五大应用领域、六大优势与七大挑战 Camworks编程&#xff0c;作为计算机辅助制造&#xff08;CAM&#xff09;领域的一款重要软件&#xff0c;近年来在制造业中得到了广泛的应用。那么&#xff0c;Camworks编程究竟怎么样呢…...

【Linux】操作系统之冯诺依曼体系

&#x1f389;博主首页&#xff1a; 有趣的中国人 &#x1f389;专栏首页&#xff1a; Linux &#x1f389;其它专栏&#xff1a; C初阶 | C进阶 | 初阶数据结构 小伙伴们大家好&#xff0c;本片文章将会讲解 操作系统中 冯诺依曼体系 的相关内容。 如果看到最后您觉得这篇文…...

c++ QT 实现QMediaPlayer播放音频显示音频级别指示器

文章目录 效果图概述代码总结 效果图 概述 QMediaPlayer就不介绍了&#xff0c;就提供了一个用于播放音频和视频的媒体播放器 QAudioProbe 它提供了一个探针&#xff0c;用于监控音频流。当音频流被捕获或播放时&#xff0c;QAudioProbe 可以接收到音频数据。这个类在需要访问…...

失之毫厘差之千里之load和loads

起源 最近在读pandas库的一些文档的时候&#xff0c;顺便也会将文档上的一些demo在编辑器中进行运行测试&#xff0c;其中在读到pandas处理Json数据这一节的时候&#xff0c;我还是像往常一样&#xff0c;将文档提供的demo写一遍&#xff0c;结果在运行的时候&#xff0c;直接…...

element ui在移动端的适配问题

element ui在移动端的适配问题 问题1&#xff1a; 给el-table表头添加背景色&#xff0c;使用以下代码 :header-row-style“{ background: ‘linear-gradient(90deg, #0079FA 0%, #00C7DD 100%)’ }” 在安卓手机上显示正常&#xff0c;在ios手机上显示背景色添加到每一个th中…...

堆排序详细理解

目录 一、前备知识 二、建堆 2.2.1 向上调整算法建堆 2.2.2 向下调整算法建堆 三、排序 3.1 常见问题 3.2 思路 3.3 源码 一、前备知识 详细图解请点击&#xff1a;二叉树的顺序实现-堆-CSDN博客 本文只附上向上/向下调整算法的源码 //交换 void Swap(int* p, int* …...

RK3588+FPGA+AI高性能边缘计算盒子,应用于视频分析、图像视觉等

搭载RK3588&#xff08;四核 A76四核 A55&#xff09;&#xff0c;CPU主频高达 2.4GHz &#xff0c;提供1MB L2 Cache 和 3MB L3 &#xff0c;Cache提供更强的 CPU运算能力&#xff0c;具备6T AI算力&#xff0c;可扩展至38T算力。 产品规格 系统主控CPURK3588&#xff0c;四核…...

从‘它怎么又挂了’到‘服务稳如狗’:我是如何用Prometheus+Grafana给自家小项目做监控的

从零搭建轻量级服务监控&#xff1a;PrometheusGrafana实战指南 凌晨三点&#xff0c;手机突然响起刺耳的警报声——这已经是本周第三次被线上服务宕机惊醒。作为独立开发者或小团队&#xff0c;我们往往身兼数职&#xff0c;既要写代码又要维护基础设施。服务崩溃时才发现问题…...

告别传统架构!源网荷储四侧时序数据库选型与落地全解析

新型电力系统应该用什么数据库&#xff1f;源网荷储四侧的时序数据库选型与落地实战 “双碳” 目标的推进正在深刻重构电力系统的运行逻辑。新能源装机占比持续攀升&#xff0c;储能、虚拟电厂、需求响应等新业态快速涌现&#xff0c;源、网、荷、储各侧的角色与互动方式正在被…...

WebGL BIM可视化:浏览器端BIM解决方案的技术实践与行业应用

WebGL BIM可视化&#xff1a;浏览器端BIM解决方案的技术实践与行业应用 【免费下载链接】xeokit-bim-viewer A browser-based BIM viewer, built on the xeokit SDK 项目地址: https://gitcode.com/gh_mirrors/xe/xeokit-bim-viewer 如何解决浏览器端BIM模型加载慢、操…...

别再只盯着KNN了:聊聊Wi-Fi指纹定位中那些被低估的匹配算法与实战选择

超越KNN&#xff1a;Wi-Fi指纹定位中的高阶匹配算法与工程化选型指南 商场里找不到心仪店铺的焦虑、仓库中耗时的手动货品盘点、医院里紧急设备定位的延迟——这些场景背后都指向同一个技术痛点&#xff1a;室内定位精度不足。当大多数开发者习惯性采用KNN算法时&#xff0c;我…...

3个智能化解决方案让科研工作者实现投稿管理效率革命:Elsevier Tracker无缝集成工具

3个智能化解决方案让科研工作者实现投稿管理效率革命&#xff1a;Elsevier Tracker无缝集成工具 【免费下载链接】Elsevier-Tracker 项目地址: https://gitcode.com/gh_mirrors/el/Elsevier-Tracker 行业现状分析 学术出版领域数字化转型过程中&#xff0c;科研工作者…...

如何构建你的第一个Python高频交易模型:完整实战指南

如何构建你的第一个Python高频交易模型&#xff1a;完整实战指南 【免费下载链接】High-Frequency-Trading-Model-with-IB A high-frequency trading model using Interactive Brokers API with pairs and mean-reversion in Python 项目地址: https://gitcode.com/gh_mirror…...

实用扩散模型完整指南:100行代码实现高效图像生成

实用扩散模型完整指南&#xff1a;100行代码实现高效图像生成 【免费下载链接】Diffusion-Models-pytorch Pytorch implementation of Diffusion Models (https://arxiv.org/pdf/2006.11239.pdf) 项目地址: https://gitcode.com/gh_mirrors/di/Diffusion-Models-pytorch …...

深入STM32F407 USART收发机制:用逻辑分析仪解读数据帧与中断处理流程

深入解析STM32F407 USART通信机制&#xff1a;从数据帧捕获到中断优化实战 在工业自动化、智能硬件等高可靠性应用场景中&#xff0c;串口通信的稳定性和效率往往决定着整个系统的性能边界。STM32F407作为ARM Cortex-M4内核的经典代表&#xff0c;其USART模块在异步通信场景下展…...

nli-distilroberta-base惊艳案例:自动识别合同补充协议与主协议的潜在矛盾条款

nli-distilroberta-base惊艳案例&#xff1a;自动识别合同补充协议与主协议的潜在矛盾条款 1. 项目概述 在合同审查工作中&#xff0c;补充协议与主协议之间的条款一致性检查是法律从业者最头疼的问题之一。传统的人工比对方式不仅耗时费力&#xff0c;还容易遗漏关键矛盾点。…...

遇到‘Got minus one from a read call‘别慌!Oracle 12c连接数优化全攻略

深度解析Oracle 12c连接数优化&#xff1a;从"Got minus one from a read call"到高可用架构 当Java应用突然抛出java.sql.SQLRecoverableException: IO Error: Got minus one from a read call异常时&#xff0c;这往往是数据库连接资源耗尽的信号。本文将带您深入O…...