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

基于C语言的简单HTTP Web服务器实现

1. 概述

本案例使用C语言实现了一个简单的HTTP服务器,能够处理客户端的GET请求,并返回静态文件(如HTML、图片等)。在此案例中案例,我们主要使用的知识点有:

  • Socket编程:基于TCP协议的Socket通信。

  • HTTP协议:HTTP请求和响应的基本格式。

  • 多线程:使用多线程处理客户端请求。

  • 文件操作:读取本地文件并发送给客户端。

  • MIME类型:根据文件扩展名设置正确的Content-Type


2. 主要知识点

2.1 Socket编程

Socket是网络通信的基础,本案例使用Windows下的Socket API(winsock2.h)实现TCP通信。主要函数包括:

  • WSAStartup:初始化Winsock库。

  • socket:创建套接字。

  • bind:绑定套接字到本地地址和端口。

  • listen:监听客户端连接。

  • accept:接受客户端连接。

  • send/recv:发送和接收数据。

  • closesocket:关闭套接字。

2.2 HTTP协议

HTTP是一种无状态的请求-响应协议。本案例实现了HTTP/1.0的基本功能:

  • 请求格式

  • GET /path HTTP/1.0
    Host: 127.0.0.1:8080

    响应格式

  • HTTP/1.0 200 OK
    Content-Type: text/html<html>...</html>

    2.3 多线程

    为了支持多个客户端同时连接,本案例使用Windows的CreateThread函数创建新线程处理每个客户端请求。

2.4 文件操作

服务器需要读取本地文件并发送给客户端。本案例使用fopenfread等函数操作文件。

2.5 MIME类型

根据文件扩展名设置正确的Content-Type,例如:

  • .html -> text/html

  • .jpg -> image/jpeg

  • .png -> image/png

3. 实现思路

3.1 服务器启动流程

  1. 初始化Winsock库:调用WSAStartup初始化网络通信。

  2. 创建套接字:调用socket创建TCP套接字。

  3. 绑定地址和端口:调用bind绑定套接字到本地地址和端口。

  4. 监听连接:调用listen开始监听客户端连接。

  5. 接受连接:调用accept接受客户端连接,并为每个连接创建新线程。

3.2 处理客户端请求

  1. 读取请求行:从客户端读取HTTP请求的第一行,解析请求方法和URL。

  2. 解析URL:根据URL确定请求的文件路径。

  3. 检查文件是否存在:使用stat函数检查文件是否存在。

  4. 发送响应头:根据文件类型设置Content-Type,并发送HTTP响应头。

  5. 发送文件内容:读取文件内容并发送给客户端。

3.3 多线程处理

每个客户端连接由一个独立的线程处理,避免阻塞主线程。

4. 代码细节分析

4.1 初始化网络和创建套接字

int startup(unsigned short* port) {WSADATA wsaData;int ret = WSAStartup(MAKEWORD(1, 1), &wsaData);if (ret) {printf("初始化网络通信失败\n");return -1;}int server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (server_sock == INVALID_SOCKET) {error_die("socket()失败");}// 设置端口复用int opt = 1;setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));// 绑定地址和端口struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(server_addr));server_addr.sin_family = AF_INET;server_addr.sin_port = htons(*port);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);ret = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(server_addr));if (ret == SOCKET_ERROR) {error_die("bind()失败");}// 动态分配端口if (*port == 0) {int len = sizeof(server_addr);getsockname(server_sock, (struct sockaddr*)&server_addr, &len);*port = ntohs(server_addr.sin_port);}// 监听连接ret = listen(server_sock, 5);if (ret == SOCKET_ERROR) {error_die("listen()失败");}return server_sock;
}

4.2 读取HTTP请求

int get_line(int sock, char* buf, int size) {int i = 0;char c = 0;while (i < size - 1 && c != '\n') {int n = recv(sock, &c, 1, 0);if (n <= 0) break;if (c == '\r') {n = recv(sock, &c, 1, MSG_PEEK);if (n > 0 && c == '\n') recv(sock, &c, 1, 0);c = '\n';}buf[i++] = c;}buf[i] = '\0';return i;
}

4.3 处理客户端请求

DWORD WINAPI accept_request(LPVOID arg) {int client = (SOCKET)arg;char buf[1024], method[255], url[255], path[255];int numchars = get_line(client, buf, sizeof(buf));// 解析请求方法和URLsscanf(buf, "%s %s", method, url);// 检查请求方法if (_stricmp(method, "GET") && _stricmp(method, "POST")) {unimplemented(client);return 0;}// 构造文件路径sprintf(path, "htdocs%s", url);if (path[strlen(path) - 1] == '/') strcat(path, "index.html");// 检查文件是否存在struct stat st;if (stat(path, &st) == -1) {while ((numchars > 0) && strcmp("\n", buf))numchars = get_line(client, buf, sizeof(buf));not_found(client);} else {if ((st.st_mode & S_IFMT) == S_IFDIR) strcat(path, "/index.html");server_file(client, path);}closesocket(client);return 0;
}

4.4 发送文件内容

void cat(int client_sock, FILE* resource) {char buf[4096];int count = 0;while (1) {int ret = fread(buf, sizeof(char), sizeof(buf), resource);if (ret <= 0) break;send(client_sock, buf, ret, 0);count += ret;}printf("总共发送了%d字节\n", count);
}

5. 总结

      通过这个案例,我们实现了一个简单的HTTP服务器,支持静态文件的请求和响应。核心知识点包括Socket编程、HTTP协议、多线程和文件操作。这个案例是学习网络编程的入门项目,后续可以扩展支持更多功能,如POST请求、动态内容生成等。

静态资源的访问位置记得改成自己的,这是我存放的静态资源位置。

如果edge浏览器访问不了可以多刷新几次,或者使用谷歌等其他浏览器。

如果通过路径访问的资源不存在,则返回404信息

案例完整代码如下:

#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>
#include <winsock2.h>
#pragma comment(lib, "ws2_32.lib")#include <string.h>
#include <ctype.h>
#include <sys/stat.h> //访问文件的属性#define PRINTF(str) printf("[%s - %d] "#str" = %s\r\n",__func__,__LINE__,str);#define ISspace(x) isspace((int)(x))void error_die(const char* msg) {// 打印错误信息printf("%s\n", msg);// 退出程序exit(1);
}// 初始化网络并创建服务端的套接字
int startup(unsigned short* port) {// 1. 网络通信初始化WSADATA wsaData;int ret = WSAStartup(MAKEWORD(1, 1), &wsaData);if (ret) {printf("初始化网络通信失败\n");return -1;}// 2. 创建服务端的套接字int server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (server_sock == INVALID_SOCKET) {error_die("socket()失败");}// 设置端口号可复用int opt = 1;ret = setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt));if (ret == -1) {error_die("setsockopt()失败");}// 配置服务端套接字地址struct sockaddr_in server_addr;memset(&server_addr, 0, sizeof(struct sockaddr_in)); // 清空结构体server_addr.sin_family = AF_INET; // 地址族,这里是IPv4server_addr.sin_port = htons(*port); // 端口号server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // IP地址,这里是任意IP// 绑定套接字与服务端地址ret = bind(server_sock, (struct sockaddr*)&server_addr, sizeof(struct sockaddr));if (ret == SOCKET_ERROR) {error_die("bind()失败");}// 动态分配一个端口号if (*port == 0) {int len = sizeof(struct sockaddr);getsockname(server_sock, (struct sockaddr*)&server_addr, &len);*port = ntohs(server_addr.sin_port);}// 创建监听队列ret = listen(server_sock, 5);if (ret == SOCKET_ERROR) {error_die("listen()失败");}return server_sock; // 返回server_sock而不是0
}//返回从套接字读取一行信息,并把数据存入buf中
int get_line(int sock, char* buf, int size) {int i = 0;int n;char c = 0;while (i < size - 1 && c != '\n') {n = recv(sock, &c, 1, 0);if (n <= 0) {// 连接关闭或出错,结束循环break;}if (c == '\r') {// 查看下一个字符是否是'\n'char next_char;n = recv(sock, &next_char, 1, MSG_PEEK);if (n > 0 && next_char == '\n') {// 读取并消耗'\n'recv(sock, &next_char, 1, 0);}c = '\n'; // 统一转换为换行符}buf[i++] = c;if (c == '\n') {break; // 换行符结束行读取}}buf[i] = '\0'; // 添加字符串终止符return i; // 返回读取的字符数(不含终止符)
}void unimplemented(int client_sock) {// 发送501响应char buf[1024];strcpy(buf, "HTTP/1.0 501 Method Not Implemented\r\n");send(client_sock, buf, strlen(buf), 0);strcpy(buf, "Server: RockHTTP/0.1 libcurl/7.22.0\r\n");send(client_sock, buf, strlen(buf), 0);strcpy(buf, "Content-Type: text/html\r\n");send(client_sock, buf, strlen(buf), 0);strcpy(buf, "\r\n");send(client_sock, buf, strlen(buf), 0);// 发送501页面char unimplemented_html[] = "<HTML><HEAD><TITLE>Method Not Implemented</TITLE></HEAD><BODY><H1>501 Method Not Implemented</H1></BODY></HTML>";send(client_sock, unimplemented_html, strlen(unimplemented_html), 0);
}void not_found(int client_sock) {// 发送404响应char buf[1024];strcpy(buf, "HTTP/1.0 404 Not Found\r\n");send(client_sock, buf, strlen(buf), 0);strcpy(buf, "Server: RockHTTP/0.1 libcurl/7.22.0\r\n");send(client_sock, buf, strlen(buf), 0);sprintf(buf, "Content-Type: text/html\r\n");send(client_sock, buf, strlen(buf), 0);strcpy(buf, "\r\n");send(client_sock, buf, strlen(buf), 0);// 发送404页面char not_found_html[] = "<HTML><HEAD><TITLE>Not Found</TITLE></HEAD><BODY><H1>404 Not Found</H1></BODY></HTML>";send(client_sock, not_found_html, strlen(not_found_html), 0);
}const char* get_content_type(const char* path) {const char* last_dot = strrchr(path, '.');if (last_dot) {if (strcmp(last_dot, ".html") == 0 || strcmp(last_dot, ".htm") == 0) {return "text/html";}else if (strcmp(last_dot, ".jpg") == 0 || strcmp(last_dot, ".jpeg") == 0) {return "image/jpeg";}else if (strcmp(last_dot, ".png") == 0) {return "image/png";}else if (strcmp(last_dot, ".gif") == 0) {return "image/gif";}else if (strcmp(last_dot, ".css") == 0) {return "text/css";}else if (strcmp(last_dot, ".js") == 0) {return "application/javascript";}}return "text/plain";
}void headers(int client_sock, const char* path) {// 发送HTTP头部                         char buf[1024];strcpy(buf, "HTTP/1.0 200 OK\r\n");send(client_sock, buf, strlen(buf), 0);sprintf(buf, "Content-Type: %s\r\n", get_content_type(path));send(client_sock, buf, strlen(buf), 0);strcpy(buf, "\r\n");send(client_sock, buf, strlen(buf), 0);
}void cat(int client_sock, FILE* resource) {char buf[4096];int count = 0;while (1) {int ret = fread(buf, sizeof(char), sizeof(buf), resource);if (ret <= 0) {break;}send(client_sock, buf, ret, 0);count += ret;}printf("总共发送了%d字节\n", count);
}void server_file(int client_sock, const char* fileName) {char numchars = 1;char buf[1024];// 将请求包剩余数据读完,直到遇到换行符while (numchars > 0 && strcmp(buf, "\n")) {numchars = get_line(client_sock, buf, sizeof(buf));PRINTF(buf);}// 发送文件内容FILE* resource = fopen(fileName, "rb"); // 以二进制模式打开文件if (resource == NULL) {printf("文件打开失败\n");not_found(client_sock);}else {// 返回数据给浏览器headers(client_sock, fileName);// 发送请求的资源cat(client_sock, resource);printf("资源发送完毕\n");}fclose(resource);
}// 处理客户端的连接请求 
DWORD WINAPI accept_request(LPVOID arg) {char buf[1024];int numchars;char method[255];char url[255];char path[255];size_t i, j;struct stat st;int cgi = 0;int client = (SOCKET)arg;// 读取一行信息numchars = get_line(client, buf, sizeof(buf));printf("read %d bytes of data from client\n", numchars);PRINTF(buf);char* query_string = NULL;i = 0; j = 0;while (!ISspace(buf[j]) && (i < sizeof(method) - 1)) {method[i] = buf[j];i++;j++;}method[i] = 0;  // 解析后, method的值:"GET"或者"POST"PRINTF(method);// 判断是否为GET或POST请求if (_stricmp(method, "GET") && _stricmp(method, "POST")) {unimplemented(client);return 0;}// 判断是否为CGI请求if (_stricmp(method, "POST") == 0)cgi = 1;// 解析URL,获得资源路径i = 0;while (ISspace(buf[j]) && (j < sizeof(buf))) // 跳过buff中的空格j++;while (!ISspace(buf[j]) && (i < sizeof(url) - 1) && (j < sizeof(buf))) // 获得资源url 比如 / 或者 /images/head.png{url[i] = buf[j];i++; j++;}url[i] = '\0';PRINTF(url);sprintf(path, "htdocs%s", url);if (path[strlen(path) - 1] == '/')strcat(path, "index.html"); // 如果路径以"/"结尾,则认为是目录,拼接上默认的HTML文件名PRINTF(path);struct stat status;// 检查访问的资源是否存在if (stat(path, &st) == -1) {  // stat获取指定文件的属性信息// 如果不能访问它的属性信息,那么这个文件就不存在// 此时,就需要把这个请求报文,读完!虽然已经没有用了,但是也要把这个报文读完while ((numchars > 0) && strcmp("\n", buf))  /* read & discard headers */numchars = get_line(client, buf, sizeof(buf));not_found(client);}else {// 如果浏览器的地址输入:http://127.0.0.1:8000/movies // 如果movies是目录,就默认访问这个目录下的index.htmlif ((st.st_mode & S_IFMT) == S_IFDIR)strcat(path, "/index.html");server_file(client, path);}closesocket(client);return 0;
}int main() {// httpd默认的端口是80,这里指定了8000端口,也可以使用其它端口unsigned short port = 8080;// 初始化网络,并使用指定端口来创建服务端的套接字int server_sock = startup(&port);printf("httpd running on port %d\n", port);while (1) {// 等待客户端的连接struct sockaddr_in client_addr;int client_len = sizeof(struct sockaddr);// 阻塞式等待客户端的连接int client_sock = accept(server_sock, (struct sockaddr*)&client_addr, &client_len);if (client_sock == -1) {error_die("accept"); // 打印错误信息并结束}// 创建一个线程来处理客户端请求DWORD threadId = 0;HANDLE handleFirst = CreateThread(NULL, 0, accept_request, (void*)client_sock, 0, &threadId);if (handleFirst == NULL) {error_die("CreateThread()失败");}}return 0;
}

相关文章:

基于C语言的简单HTTP Web服务器实现

1. 概述 本案例使用C语言实现了一个简单的HTTP服务器&#xff0c;能够处理客户端的GET请求&#xff0c;并返回静态文件&#xff08;如HTML、图片等&#xff09;。在此案例中案例&#xff0c;我们主要使用的知识点有&#xff1a; Socket编程&#xff1a;基于TCP协议的Socket通信…...

JavaScript语言的区块链隐私

使用JavaScript保护区块链隐私 随着区块链技术的快速发展&#xff0c;隐私保护的重要性日益凸显。区块链技术虽然在透明性和去中心化方面表现优异&#xff0c;但其公开账本特性也使得用户的交易和身份信息容易暴露。因此&#xff0c;如何在区块链应用中实现隐私保护成为了一个…...

ZYNQ初识13(zynq_7020)hdmi和串口板载功能的验证

&#xff08;1&#xff09;另&#xff1a;首先需要确认供电模块&#xff0c;电压转换模块没有问题&#xff0c;测量后上电防止出现短路。通过vivado下载bit流文件检测JTAG下载口是否正常&#xff0c;如可正常检测&#xff0c;才可进行下一步验证。 &#xff08;2&#xff09;以…...

ollama下载的DeepSeek的模型(Model)文件在哪里?(C盘下)

目录 一、下载大模型&#xff08;DeepSeek&#xff09; 2. 安装 Ollama 3. 检查安装是否成功 二、拉取大模型&#xff08;DeepSeek&#xff09; 1. 打开命令行 2. 下载模型 3. 测试下载 4. 等待下载完成 三.模型存放路径 这个位置&#xff01;&#xff01; 在人工智能…...

docker的anythingllm和open-webui压缩包分享(国内镜像拉取,百度云压缩包分享)

文章目录 前言第一部分&#xff1a;镜像获取&#x1f680; 方式一&#xff1a;切换国内下载镜像✅1. 下载anythingllm✅ 2. 下载open-webui &#x1f680;方式二&#xff1a;下载我分享的百度云✅ anythingllm压缩包百度云链接❎ open-webui压缩包 第二部分&#xff1a;下载之后…...

树莓科技(成都)集团:如何铸就第五代产业园标杆

树莓科技&#xff08;成都&#xff09;集团铸就第五代产业园标杆&#xff0c;主要体现在以下几个方面&#xff1a; 精准定位与前瞻布局 树莓科技并非盲目扩张&#xff0c;而是精准锚定数字经济发展方向。以成都为起点&#xff0c;迅速构建起全国性的园区版图&#xff0c;体现…...

父组件中循环生成多个子组件时,有且只有最后一个子组件的watch对象生效问题及解决办法

提示&#xff1a;父组件中循环生成多个子组件时&#xff0c;有且只有最后一个子组件的watch对象生效问题及解决办法 文章目录 [TOC](文章目录) 前言一、问题二、解决方法——使用function函数代替箭头函数()>{}总结 前言 ‌‌‌‌‌问题&#xff1a;子组件用that解决watch无…...

《解锁Flutter:跨平台开发的未来之光》

《解锁Flutter&#xff1a;跨平台开发的未来之光》 Flutter&#xff1a;崭新时代的跨平台框架 在当今数字化浪潮中&#xff0c;移动应用已成为人们生活中不可或缺的一部分。无论是购物、社交、娱乐还是办公&#xff0c;我们都离不开各种手机应用。而在移动应用开发领域&#…...

求递增子序列LIS的两种方法

文章目录 前言一、普通动态规划&#xff08;DP&#xff09;求解LIS1.DP思路2.DP的状态定义与转移方程3.DP的时间与空间复杂度4.DP代码实现5.DP的图文示例 二、贪心 二分查找求解LIS1.思路分析2.贪心 二分的时间与空间复杂度 三. 模板题讲解1.洛谷B3637 最长上升子序列1.dp写法…...

【Linux篇】进程状态(僵尸进程,孤儿进程),优先级与调度机制

&#x1f4cc; 个人主页&#xff1a; 孙同学_ &#x1f527; 文章专栏&#xff1a;Liunx &#x1f4a1; 关注我&#xff0c;分享经验&#xff0c;助你少走弯路&#xff01; 文章目录 1. 前文铺垫理解内核链表 2. 进程状态2.1 进程状态查看2.2 僵尸进程2.3 僵尸进程危害2.4 孤儿…...

SAP-ABAP:CONV(显示类型转换符)关键字详解

SAP ABAP CONV 关键字详解 CONV 是 ABAP 7.40 版本引入的显式类型转换操作符&#xff0c;用于将表达式的结果强制转换为指定的数据类型。它提供了一种清晰且类型安全的方式处理数据转换&#xff0c;避免隐式转换的潜在风险。以下是其核心特性和应用场景的全面解析&#xff1a;…...

AI应用加速落地丨MaxKB正在被政府、公共事业、教育和医疗行业用户广泛采纳

2025年2月至3月上旬&#xff0c;伴随着各个行业接入并使用DeepSeek&#xff0c;MaxKB开源知识库问答系统正在被越来越多的行业用户所采纳&#xff0c;是人工智能行业落地的强应用。目前&#xff0c;MaxKB在政府、公共事业、教育和医疗四大行业已经拥有了众多典型案例&#xff0…...

⚡️Jolt -- 通过JSON配置来处理复杂数据转换的工具

简介&#xff1a;一个能够通过JSON配置&#xff08;特定的语法&#xff09;来处理复杂数据转换的工具。 比如将API响应转换为内部系统所需的格式&#xff0c;或者处理来自不同来源的数据结构差异。例如&#xff0c;将嵌套的JSON结构扁平化&#xff0c;或者重命名字段&#xff0…...

Django系列教程(7)——路由配置URLConf

目录 URLconf是如何工作的? path和re_path方法 更多URL配置示例 URL的命名及reverse()方法 使用命名URL 硬编码URL - 不建议 URL指向基于类的视图(View) 通过URL传递额外的参数 小结 Django的项目文件夹和每个应用(app)目录下都有urls.py文件&#xff0c;它们构成了D…...

TDengine SQL 函数

单行函数 数学函数 ABSACOSASINATANCEILCOSDEGREESEXPFLOORGREATESTLEASTLNLOGMODPIPOWRADIANSRANDROUNDSIGNSINSQRTTANTRUNCATE 字符串函数 ASCIICHARCHAR_LENGTHCONCATCONCAT_WSLENGTHLOWERLTRIMPOSITIONREPEATREPLACERTRIMSUBSTRING/SUBSTRSUBSTRING_INDEXTRIMUPPER 转换函数…...

二维数组基础

在 C 语言中,二维数组是一种数据结构,它可以存储表格形式的数据,或是矩阵形式的数据。二维数组可以被看作是一个包含多个一维数组的数组,因此它有两个维度:行和列。 1. 二维数组的定义与声明 在 C 语言中,二维数组的定义形式如下: data_type array_name[rows][column…...

2024年第十五届蓝桥杯软件C/C++大学A组——五子棋对弈

蓝桥杯原题&#xff1a; 题目描述&#xff1a; “在五子棋的对弈中&#xff0c;友谊的小船说翻就翻&#xff1f; ” 不&#xff01;对小蓝和小桥来说&#xff0c;五子棋不仅是棋盘上的较量&#xff0c;更是心与心之间的沟通。这两位挚友秉承着 “ 友谊第一&#xff0c;比赛第二…...

复试难度解析,西电先进材料与纳米科技学院学院考研录取情况

01、先进材料与纳米科技学院各个方向 02、24先进材料与纳米科技学院近三年复试分数线对比 PS&#xff1a;材料院24年院线学硕方向降低10分&#xff0c;专硕上涨15分&#xff1b;材料院在分数线相对于其他211、985院校对比来看&#xff0c;依然分数偏低&#xff0c;推荐大家关注…...

Deepseek Chatgpt Kimi 推荐的深度学习书单

朋友让推荐一些深度学习的书&#xff0c;让 Deepseek、Chatgpt、Kimi 分别生成了一份书单并做了对比&#xff0c;记录一下以备以后用到。 Chatgpt 推荐的深度学习书 1. chatgpt 推荐的书目截图 1.2 Chatgpt 推荐的深度学习书目文字版 如果你想学习 Deep Learning&#xff0…...

高频面试题(含笔试高频算法整理)基本总结回顾25

干货分享&#xff0c;感谢您的阅读&#xff01; &#xff08;暂存篇---后续会删除&#xff0c;完整版高频面试题基本总结回顾&#xff08;含笔试高频算法整理&#xff09;&#xff09; 备注&#xff1a;引用请标注出处&#xff0c;同时存在的问题请在相关博客留言&#xff0c…...

ClickHouse SQL优化:解锁高性能数据分析的关键

一、引言 1.1 ClickHouse的背景与优势 ClickHouse是一款高性能的列式数据库,专为在线分析处理(OLAP)场景设计。它以其卓越的读写性能、强大的数据压缩能力和灵活的SQL支持而闻名。ClickHouse能够轻松处理PB级数据,并在亚秒级内返回查询结果,这使其成为大数据分析领域的理…...

我与DeepSeek读《大型网站技术架构》(14)- 架构师领导艺术

文章目录 架构师领导艺术以人为本&#xff1a;激发团队潜能开放式协作&#xff1a;打破架构“所有权”壁垒妥协的艺术&#xff1a;聚焦核心目标成就他人&#xff1a;构建持续进化团队高效沟通&#xff1a;建立技术与人性的平衡 架构师领导艺术 本章聚焦架构师如何通过团队协作…...

mac安装mysql之后报错zsh: command not found: mysql !

在Mac上安装MySQL后&#xff0c;如果终端中找不到mysql命令&#xff0c;通常是 因为MySQL的命令行工具&#xff08;如mysql客户端&#xff09;没有被正确地添加到你的环境变量中。 检查 MySQL 是否已安装 ps -ef|grep mysql查看到路径在 /usr/local/mysql/bin 查看 .bash_pro…...

蓝桥杯备考:set容器用法(lower_bound)---营业额统计

如图所示&#xff0c;这道题的暴力解法就是枚举每天的营业额&#xff0c;让该营业额和前面的天的营业额依次相减取最小值这样的话我们的时间复杂度就是N平方&#xff0c;我们是很有可能超时的 所以我们选择用set容器的二分查找功能 我们每次遍历到一个数的时候&#xff0c;前…...

VSCode集成C语言开发环境

下载MinGW https://sourceforge.net/projects/mingw/ 点击download按钮下载exe文件到本地 点击exe文件安装 选择基础包和c编译版 vscode安装部分跳过 安装code runner和c/c插件 **(1) 创建 C 文件** 新建一个测试文件&#xff08;例如 hello.c&#xff09;&#xf…...

Python----数据可视化(pyecharts二:绘图一:条形图,直方图,折线图,散点图,箱图,饼图,热力图)

1、条形图 from pyecharts.charts import Bar from pyecharts.faker import Faker from pyecharts import options as opts # 绘制柱状图 bar (Bar() # 创建柱状图.add_yaxis("商家A", Faker.values(),colorFaker.rand_color()) # 添加数据.add_yaxis("商家B&…...

Training-free Neural Architecture Search for RNNs and Transformers(预览版本)

摘要 神经架构搜索 (NAS) 允许自动创建新的有效神经网络架构&#xff0c;为手动设计复杂架构的繁琐过程提供了替代方案。然而&#xff0c;传统的 NAS 算法速度慢&#xff0c;需要大量的计算能力。最近的研究调查了图像分类架构的无训练 NAS 指标&#xff0c;大大加快了搜索算…...

Linux机器之间排查网络连通问题

网络连通性排查步骤&#xff08;基于五层模型&#xff09; 以下按照网络五层架构&#xff0c;从底层到高层逐层排查&#xff0c;并分别列出Ubuntu和CentOS对应的命令。 1. 物理层 排查点&#xff1a;网线、网卡状态、物理连接。 命令&#xff08;通用&#xff09;&#xff1a…...

计算机考研C语言

C语言程序设计从入门到精通【2025完整版】考研复试 嵌入式 计算机二级 软考 专升本也适用_哔哩哔哩_bilibili 1、第一个C程序 helloC #include <stdio.h>int main(){printf("hehe");return 0;}每个C语言程序不管有多少行代码&#xff0c;都是从main函数开始执…...

【MySQL】(4) 表的操作

一、创建表 语法&#xff1a; 示例&#xff1a; 生成的数据目录下的文件&#xff1a; 二、查看表结构 三、修改表 语法&#xff1a; 另一种改表名语法&#xff1a;rename table old_name1 to new_name1, old_name2 to new_name2; 示例&#xff1a; 四、删除表 语法&#xf…...