SQL速通

SQL速通-001.001-安装MySQL数据管理系统 下载地址 搜索 mysql community download 跳转到 mysql 的官方网站的社区版下载网页。 版本选择 选择 8.0 版本,选择离线安装版。 安装时注意点 可能是家庭版系统的原因,安装时不能选择 development 模式,只好选择 custom 模式,然后额外选择了 odbc, c++ 之类的。 可能是家庭版系统原因,不能选择安装位置,只能默认安装到 C盘,安装完成大约占用 10G 空间。 安装一路下一步即可。 安装时提示没有 visualstudio 也没有关系,这个 vs 连接 mysql 的驱动可以在官网下载,搜索 mysql for visual studio 即可。 SQL速通-003-小查询里有故事 概述 sql 分为 server 和 client 两大块 使用时我们在 client 中输入命令,client 把命令通过网络传递给 server server 执行命令并通过网络把结果返回给我们 use 在使用 select 等语句前,一定要确认是否选中了需要用到的 库, 如果没有,那么需要使用 use 命令来选择。 大小写是否敏感 在 win 系统默认不敏感,在 linux 系统默认敏感。 具体还要看是否设置了大小写敏感。 query 在一个查询行为中可包含多个查询语句。 一个查询行为只会产生一个查询结果,也就是说查询行为的次数与查询结果的个数是对应的。 一个包含多条查询语句的查询行为会产生一个查询结果,而在这个结果中包含多个表。 SQL速通-004-万变不离其宗 语法 sql 语法其实就是层层嵌套的套娃语法。基本就是对 select 的层层包装。...

<span title='2023-10-03 20:00:00 +0800 CST'>2023-10-03</span>&nbsp;·&nbsp;3 min&nbsp;·&nbsp;448 words&nbsp;·&nbsp;RamLife

P13 select 模型上

电脑承受进程数量 1核2GB 可以大约 100 多进程或线程 普通服务器大概是 10倍性能,即 1000 多进程或线程。 IO 多路复用能力 1个进程或线程可以使用多个 TCP。 单进程 select 可以 1024 单进程 poll 可以数千 单进程 epoll 可以百万 fdset 本质上是 int[32] 组成的 bitmap, 刚好对应 1024 个文件描述符。 参考 IO 多路复用 select 模型上

<span title='2023-09-24 18:05:00 +0800 CST'>2023-09-24</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;36 words&nbsp;·&nbsp;RamLife

P6 万恶的结构体

客户端和服务端字符串转字节为啥不一样? 客户端 struct hostent* h; // 用于存放服务端IP地址(大端序)的结构体的指针。 if ( (h = gethostbyname(argv[1])) == nullptr ) // 把域名/主机名/字符串格式的IP转换成结构体。 { cout << "gethostbyname failed.\n" << endl; close(sockfd); return -1; } memcpy(&servaddr.sin_addr,h->h_addr,h->h_length); // ③指定服务端的IP(大端序)。 服务端 servaddr.sin_addr.s_addr=inet_addr(argv[1]); // ③指定服务端的IP,只能用IP,不能用域名和主机名。 原因 inet_addr 这个只能转换 ip 地址 gethostbyname 可以支持 IP,域名等等。 对于服务端来说,给他 ip 地址就够了。但是对于客户端来说,他需要连接的更多的可能是域名,而不是 IP。 服务端为什么也要设置 IP 如果服务端是运行于多网卡的服务器上面,那么必须要明确当前这个服务端是服务于那一个网段的,通过设置 servaddr.sin_addr.s_addr 就可以确定服务的网段了。 参考 万恶的结构体

<span title='2023-09-24 18:05:00 +0800 CST'>2023-09-24</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;54 words&nbsp;·&nbsp;RamLife

P12 TCP 缓存

getsockopt 作用 可以获取 socket 缓冲区大小。 int bufsize = 0; socklen_t optlen = sizeof(bufsize); getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &bufsize, &optlen); // 获取发送缓冲区的大小。 cout << "send bufsize=" << bufsize << endl; getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &bufsize, &optlen); // 获取接收缓冲区的大小。 cout << "recv bufsize=" << bufsize << endl; send 会阻塞吗? 如果发送太快,接受太慢,send 也会被阻塞。 send 之后,立即关闭,能接收到吗? 可以的,因为 send 是把数据写入到内核中的发送缓冲区,就算立即关闭,也能接收到。 nagle 算法 在发送一个小于 MSS 长度的包之后,必须收到回复,才能发下一个小包。保证了网络中小包数量得到控制。一般 ACK 大概 40ms. 接收延迟:在接受到一个包之后,会等待 40ms,才会发送 ACK, 这样可以尽量和应用层的回复数据合一个包。 在联机游戏,证券交易等应用场景,时效性要求高,一般会禁用 Nagle 算法。开启 TCP_NODELAY 选项。 #include <netinet/tcp....

<span title='2023-09-23 18:05:00 +0800 CST'>2023-09-23</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;82 words&nbsp;·&nbsp;RamLife

P11 三握四挥

netstat 使用 netstat 可以用来查看 socket 状态。 安装 如果系统里面没有,那么 yum install net-tools -y 可以安装。 使用 使用 netstat -a | less 或者 netstat -a | more 来查看。 上半部分的信息是 TCP 相关,下半部分是进程间的 socket 通信。 可以观察右边的 listen, established 等状态。 客户端的 port 是客户端系统随机选择的,不要去太过于关注。 port 使用限制 普通权限只能使用 1024 以上端口 root 可以使用 1024 以下的端口。 close 状态是假想状态,不存在的。 listen 的第二个参数作用 第二个参数 + 1 是 established 队列的大小,超过队列的客户端连接状态为 SYN_RCV. 三次握手 客户端申请向服务端的通道 服务端接受了,并且向客户端申请通道 客户端接受了,并给出回应 这样经过三次握手,双方建立了双向通道 四次挥手 A 请求关闭 B 同意关闭单向通道 B 把剩余的数据全部发送。 B 向 A 发送关闭请求 A 发送回应 主动端开的 A 在最后的回应后有个 TIME_WAIT 状态,时间为 2MSL,一个 MSL 在 30秒到1分钟。 服务端主动关闭 会导致 socket 释放,并且 2MSL 后端口才能重用。否则会有 bind 错误提示,并且在 netstat 中可以看到处于 TIME_WAIT 状态。 可以使用 setsockopt 函数,在 bind 之前,可以防止 bind 错误。 客户端主动关闭 没有危害,因为客户端的端口是随机分配端口号的,并且一般用的不多,够用了。...

<span title='2023-09-22 18:05:00 +0800 CST'>2023-09-22</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;107 words&nbsp;·&nbsp;RamLife

P10 多进程服务端

signal(i, SIG_IGN) 作用 // 忽略全部的信号,不希望被打扰。顺便解决了僵尸进程的问题。 for (int ii=1;ii<=64;ii++) signal(ii,SIG_IGN); kill(0, SIGTERM) 作用 kill(0,SIGTERM); // 向全部的子进程发送15的信号,通知它们退出。 因为在子进程中 SIGTERM 是退出信号。 父进程关掉 clientsocket, 子进程关掉 listensocket int pid=fork(); if (pid==-1) { perror("fork()"); return -1; } // 系统资源不足。 if (pid> 0) { // 父进程。 tcpserver.closeclient(); // 父进程关闭客户端连接的socket。 continue; // 父进程返回到循环开始的位置,继续受理客户端的连接。 } tcpserver.closelisten(); // 子进程关闭监听的socket。 在 /proc/xxx 下面的是进程相关资源,里面的 fd 是根据当前最小可用来递增的。 如果父进程不关 clientsocket, 那么每次 accept 之后,fd 都需要增加一个,然后在后面的 fork 中,这些递增的 fd 也都会被复制到子进程中。对于子进程来说,它不需要其他子进程相关的 =clientsocket=,所以完全是浪费资源。 子进程只需要自己对应的 clientsocket, 不需要 listensocket. listensocket 是专门给父进程用来监听的。 子进程结束需要 return return 0; // 子进程一定要退出,否则又会回到accept()函数的位置。 如果子进程结束没有 return=,让进程退出,那么会在 =while 中重新回到 accept 这个地方,进行了监听,然后 fork 了。...

<span title='2023-09-21 18:05:00 +0800 CST'>2023-09-21</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;88 words&nbsp;·&nbsp;RamLife

P9 文件传输

为什么 TCP 是可靠的通信,服务端每一步都要有回复。 因为服务端可能没有 accept 或者可能忙于其他事情,bug 掉线等等。所以虽然 TCP 本身是可靠的,但是服务器可能是不可靠的。所以为了业务是正常的,就必须在服务端正常应答的情况下,才能继续。 读取文件使用 ifstream 操作 字符串拼接报错? 一般情况都是只有 char * 和 char * 拼接,才会报错。只要语句中有一个 string, 拼接就不会报错。 参考 实现文件传输功能

<span title='2023-09-20 18:05:00 +0800 CST'>2023-09-20</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;24 words&nbsp;·&nbsp;RamLife

P7 封装 socket 客户端

封装时 send 函数为啥使用 const string & buf 作为参数类型 bool send(const string &buffer) // buffer不要用const char * const string & buf 既可以接收 string 也可以接受 char *. 估计是对 char * 进行了隐式转换成了 string. send 函数的参数为啥是 buf.data() 和 buf.size(), 而不是 buf.c_str() 和 buf.length if ((::send(m_clientfd,buffer.data(),buffer.size(),0))<=0) return false; buf.data() 和 buf.c_str() 都指向的是内容的指针,但是语义不一样。 data 表示的就是原始数据,而 c_str 表示的是转化为 char *. buf.size() 的语义是原始内容的大小,而 length 表示的是字符串的长度。 所以都是因为语义不合适。虽然都能用,但是确实不合适。 recv 函数的参数为啥是 & buf[0] 而不是 buf.c_str() 或者 buf.data() int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0); // 直接操作buffer的内存。 因为后面两种返回的都是带有 const, 只有 &buf[0] 才没有 const, 适合对内容进行修改。...

<span title='2023-09-19 18:05:00 +0800 CST'>2023-09-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;125 words&nbsp;·&nbsp;RamLife

课外 电子 01 电阻和 LED

符号 简单介绍相关符号: 电池,电阻,LED。 设备使用 万用表 介绍了电阻,电压,电流档位 介绍了表笔插入位置 可调电源 介绍了如何调节电压 元器件 电阻 电阻的作用 使用万用表测量阻值 LED LED 的伏安特性 使用万用表测 LED 点亮电压 LED 工作电流范围 LED 易损的情况 综合 简单的电阻和 LED 的电路中,电阻阻值如何选择。 U = I * R 万用表测量电流实测和计算结果比较

<span title='2023-04-08 17:32:00 +0800 CST'>2023-04-08</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;33 words&nbsp;·&nbsp;RamLife

html5 黑马 02. 标签学习

排版标签 标题标签 <h1> 标题 </h1> 这样的就是标题标签,只有 1-6 这6级标签,1级最大,6 级最小. vs code 中使用 可以先输入 h1 再使用 tab 进行补完 在标题行上 ctrl c ctrl v 就可以复制粘贴这一行标签了。 如果需要把 h1 标签改为 h6 标签,只需要先选中 1, 然后 ctrl d 就会自动选中本行下一个 1, 这样只需要修改一处,其他选中的也会被一起修改 段落标签 <p> </p> 这个是段落标签。 如果段落太长,在 vs code 中不方便查看,可以 查看 -> 自动换行。 段落之间,有行间隙 换行标签 <br> 水平线标签 <hr> 文本格式化标签 格式化标签有短标签,也有长标签,作用是一样的。但是长标签用于对内容进行强调,方便后期的维护识别。 短 长 作用 b string 加粗 u ins 下划线 i em 倾斜 s del 删除线 媒体标签 图片标签 <img src="" alt="" title="" width="" height=""> 属性 作用 src 图片路径 alt 图片加载失败时,替换用的文本 title 鼠标在图片上悬停时,显示的文字 width 宽 height 高 标签名和属性间有空格,属性间也有空格。...

<span title='2023-04-05 21:07:00 +0800 CST'>2023-04-05</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;161 words&nbsp;·&nbsp;RamLife