diff --git "a/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.md" "b/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.md" new file mode 100644 index 0000000..036564b --- /dev/null +++ "b/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.md" @@ -0,0 +1,39 @@ +## gdb调试入门 +> *使用gdb调试需要在gcc编译时加上-g选项,产生调试信息* +> +> *gdb + <程序名> 进入调试,或 gdb 直接进入调试环境,但需用 file 命令指定调试程序* + +- 命令总览 + + | 命令 | 含义 | + | :-------------------: | :------------------------------------------------: | + | file(fil) | file + 程序名,指定调试程序 | + | run(r) | 运行调试程序 | + | quit(r) | 退出调试程序 | + | break(b) | 设置断点,接\<文件名:行号>,或函数名 | + | list(l) | 接行号或函数名显示周围源代码 | + | continue(n) | 继续执行调试程序 | + | next(n) | 单步执行调试程序(不进入函数内部) | + | step(s) | 单步执行调试程序(进入函数内部) | + | finish(fin) | 执行函数内部剩余部分并返回 | + | print(p) | 接变量名或函数名打印变量值或函数地址,数组支持索引 | + | info breakpoints(i b) | 查看设置了哪些断点 | + | info registers(i r) | 查看寄存器信息 | + | info variables(i va) | 查看全局或全局静态变量 | + | info locals(i lo) | 查看当前局部或局部静态变量 | + | info args(i ar) | 查看当前函数参数 | + | delete(d) | 接序号删除断点,不接删除所有 | + | help(h) | 输入help查询命令用法 | + | kill(k) | 终止调试 | + | watch(wa) | 接变量名,监控变量值变化,监控时变量必须存在 | + | backtrace(bt) | 列出函数调用栈 | + + +- 注 +​ *** 1. 执行语句后显示的语句是接下来要执行的,不是当前已经执行的*** +​ *** 2. 按下enter键可以重复上一次指令*** +​ *** 3. tab可以补全,空行按下两次tab可查询所有命令*** +*** 4. 按上下方向键查询历史命令*** + + + diff --git "a/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.pdf" "b/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.pdf" new file mode 100644 index 0000000..aacb5c3 Binary files /dev/null and "b/gdb\350\260\203\350\257\225/gdb\350\260\203\350\257\225\345\205\245\351\227\250.pdf" differ diff --git "a/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.md" "b/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.md" new file mode 100644 index 0000000..0d1171b --- /dev/null +++ "b/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.md" @@ -0,0 +1,54 @@ +# git的使用 + +[git教学游戏](https://learngitbranching.js.org/?locale=zh_CN) + +- 工作区:本地文件夹 +- 暂存区:暂存文件区 +- git仓库:所有的操作记录 + +*** 命令详解:*** + +- git config --global user.name,用户名 ,这只是本地库使用,和GitHub的用户名和邮箱无关 +- git config --global user.email,邮箱,全局配置,任何一个本地库都是使用相同的用户名和邮箱 +- git status,查看状态 +- git init,初始化本地库 +- git add \<文件名>,将本地文件添加到暂存区 +- git commit -m "提交信息" \<文件名>,将暂存区的文件提交到git仓库 + +- git pull <远程库名> <远程分支>:<本地分支> ,把远程库某一分支中的内容合并到本地分支上,放入工作区中 + +​ 若本地库和远程库历史内容不匹配,即本地库最开始不是克隆远程库得来,则加上 --allow-unrelated-histories + +- git push <远程库名> <本地分支>:<远程分支> ,把本地分支更新到远程分支,结果是远程分支和本地分支一模一样 + +​ 若远程库在本地库拉取之后又提交了,则本地库在push之前应该拉取。git push \<远程库名> \<本地分支> :\<远程分支> + +- git clone \,克隆库,放入工作区 +- git log,查看当前分支历史版本,只包括commit的记录 +- git reflog,查看所有操作记录 +- git remote add \<远程库命名> ,添加一个远程库,git remote -v查看对应的地址 +- git branch \<分支名> \<版本号>,创建版本号的分支,git branch -v查看详细信息 +- git checkout \<分支名>,切换分支,当前工作区也会随之变化 +- git merge \<分支名>,把分支名合并到当前分支,工作区会更新 +- git rebase <分支名>,把当前分支与分支名的共同父级开始的所有当前分支历史版本添加到分支名的当前版本后面 +- git reset --hard "版本号",版本穿梭,可切换到任意版本,工作区会变化,历史记录消失 +- git revert \<版本号>,撤销版本号的提交,回退到版本号的上一个版本,后新加个提交即是前一个版本 +- git cherry-pick \<版本号> -n(不自动提交),把版本号添加到当前版本的后面,可以一次接多个,适用与不同分支之间单笔提交 + + + +***操作流程:*** + +​ ***1.本地库由克隆得来,git clone -> git add -> git commit -> git push*** + +​ ***2.本地库初始化创建,git init -> git remote add -> git pull -> git add -> git commit -> git push*** + + + +***注:*** + +1. 冲突时,文件里的特殊符号含义:<<<<<<< HEAD 当前分支的代码 ======= 合并过来的代码 >>>>>>> +2. 冲突发送的原因是两个分支对同一个文件的同一处有不同的修改 +3. 冲突提交时,不能带文件名,因为无法区分是哪一个文件,是当前分支还是合并的那个分支不确定 +4. push需要GitHub开权限和登录,不是所有人都能push到某一个仓库 +5. 所有操作都能在git reflog操作记录中找到 \ No newline at end of file diff --git "a/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.pdf" "b/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.pdf" new file mode 100644 index 0000000..af2e45f Binary files /dev/null and "b/git\344\275\277\347\224\250/git\347\232\204\344\275\277\347\224\250.pdf" differ diff --git "a/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" "b/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" new file mode 100644 index 0000000..177b751 --- /dev/null +++ "b/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.md" @@ -0,0 +1,84 @@ +# 环形缓冲区 + + + +![image-20221122133322027](C:\Users\郑朔\AppData\Roaming\Typora\typora-user-images\image-20221122133322027.png) + +>环形缓冲区大小为8,最后一格为了区分"空"和"满"而不放入数据 +> +>首先定义全局变量: +> +>```c +>int w = 0,r = 0; +>int data_buff[8] = {0};//环形缓冲区初始化为0 +>``` + + + +- 判断环形缓冲区内是否有数据 + + ```c + //有数据返回0,没有数据返回-1 + int has_data() + { + if(w == r) + return -1; + else + return 0; + } + ``` + +- 判断环形缓冲区是否已满 + + ```c + //未满返回0,已满返回-1 + int has_space() + { + if((w + 1) % 8 == r) + return -1; + else + return 0; + } + ``` + + + + + +- 写数据 + + ```c + //将数据写入到环形缓冲区内,成功返回0,失败返回-1 + int put_data(int *val) + { + //判断是否已满 + if(!has_space()) + { + data_buff[w] = *val; + w = (w + 1) % 8; + return 0; + } + else + return -1; + } + ``` + +- 读数据 + + ```c + //将数据从环形缓冲区读出,成功返回0,失败返回-1 + int get_data(int *val) + { + //判断是否为空 + if(!has_data()) + { + *val = data_buff[r]; + r = (r + 1) % 8; + return 0; + } + else + return -1; + } + ``` + + \ No newline at end of file diff --git "a/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.pdf" "b/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.pdf" new file mode 100644 index 0000000..ac9da53 Binary files /dev/null and "b/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272/\347\216\257\345\275\242\347\274\223\345\206\262\345\214\272.pdf" differ diff --git "a/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.md" "b/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.md" new file mode 100644 index 0000000..27beecf --- /dev/null +++ "b/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.md" @@ -0,0 +1,191 @@ +## TCP + +- 一个进程可以有多个端口,即进程内多个套接字实现不同通信 +- 一个端口可以对应多个进程,比如服务器的多个进程对应一个端口 +- 每个套接字内部有一个缓冲区,套接字是通信的端点,而不是某一个端口或进程,只要套接字不同,即能够作为通信一方 +- Linux内部通过五元组来区分套接字,即:源ip,目的ip,源端口,目的端口,通信协议UDP/TCP +- TCP通信前必须连接,交换控制信息,包括:序号,对方ip,端口等 + +------- + +***服务器与多个客户端收发数据*** + +image-20230204145315773 + +- sever程序需要绑定一个端口,ip可以任意,如果不绑定(bind),端口将随机分配,这样客户端就无法知道服务器端口 +- sever程序调用listen函数时会进入listen状态,accept建立连接时,会另返回一个套接字用于收发数据,最初创建的套接字一直是listen状态用于监听 +- 一个套接字对应一个连接,使用多进程(fork函数)与客户端一一对应,这样简单些 + +*服务器程序:* + +```c +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* socket + * bind + * listen + * accept + * send/recv + */ + +#define SERVER_PORT 8888 +#define BACKLOG 10 + +int main(int argc, char **argv) +{ + int iSocketServer; + int iSocketClient; + struct sockaddr_in tSocketServerAddr; + struct sockaddr_in tSocketClientAddr; + int iRet; + int iAddrLen; + + int iRecvLen; + unsigned char ucRecvBuf[1000]; + + int iClientNum = -1; + + signal(SIGCHLD,SIG_IGN);//解决僵死进程的问题,否则子进程退出后会有僵死进程遗留 + + iSocketServer = socket(AF_INET, SOCK_STREAM, 0);/* AF_INET:ipv4; SOCK_STREAM:TCP传输*/ + if (-1 == iSocketServer) + { + printf("socket error!\n"); + return -1; + } + + tSocketServerAddr.sin_family = AF_INET;/*AF_INET:ipv4*/ + tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ + tSocketServerAddr.sin_addr.s_addr = INADDR_ANY;/*本机上所有ip*/ + memset(tSocketServerAddr.sin_zero, 0, 8); + + iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); + if (-1 == iRet) + { + printf("bind error!\n"); + return -1; + } + + iRet = listen(iSocketServer, BACKLOG);/*BACKLOG:已挂起连接的最大数量,即没accept连接的最大数量*/ + if (-1 == iRet) + { + printf("listen error!\n"); + return -1; + } + + while (1) + { + iAddrLen = sizeof(struct sockaddr); + iSocketClient = accept(iSocketServer, (struct sockaddr *)&tSocketClientAddr, &iAddrLen); + if (-1 != iSocketClient) + { + iClientNum++; + printf("Get connect from client %d : %s\n", iClientNum, inet_ntoa(tSocketClientAddr.sin_addr)); + if (!fork())/*fork创建进程,子进程返回0,父进程返回创建的进程号,子进程代码和父进程完全相同*/ + { + /* 子进程的源码 */ + while (1) + { + /* 接收客户端发来的数据并显示出来 */ + iRecvLen = recv(iSocketClient, ucRecvBuf, 999, 0);/*阻塞等待,但客户端断开返回0*/ + if (iRecvLen <= 0) + { + close(iSocketClient); + return -1; + } + else + { + ucRecvBuf[iRecvLen] = '\0'; + printf("Get Msg From Client %d: %s\n", iClientNum, ucRecvBuf); + } + } + } + } + } + + close(iSocketServer); + return 0; +} + +``` + +*客户端程序:* + +```c +#include +#include +#include +#include +#include +#include +#include +#include + +/* socket + * connect + * send/recv + */ + +#define SERVER_PORT 8888 + +int main(int argc, char **argv) +{ + int iSocketClient; + struct sockaddr_in tSocketServerAddr; + + int iRet; + unsigned char ucSendBuf[1000]; + int iSendLen; + + if (argc != 2) + { + printf("Usage:\n"); + printf("%s \n", argv[0]); + return -1; + } + + iSocketClient = socket(AF_INET, SOCK_STREAM, 0); + + tSocketServerAddr.sin_family = AF_INET; + tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ + //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; + if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) + { + printf("invalid server_ip\n"); + return -1; + } + memset(tSocketServerAddr.sin_zero, 0, 8); + + + iRet = connect(iSocketClient, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); + if (-1 == iRet) + { + printf("connect error!\n"); + return -1; + } + + while (1) + { + if (fgets(ucSendBuf, 999, stdin)) + { + iSendLen = send(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0);/*直接发送,不等待到一个MSS*/ + if (iSendLen <= 0) + { + close(iSocketClient); + return -1; + } + } + } + + return 0; +} +``` + diff --git "a/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.pdf" "b/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.pdf" new file mode 100644 index 0000000..9f48240 Binary files /dev/null and "b/\347\275\221\347\273\234\347\274\226\347\250\213/TCP\347\274\226\347\250\213/TCP.pdf" differ diff --git "a/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.md" "b/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.md" new file mode 100644 index 0000000..8b00721 --- /dev/null +++ "b/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.md" @@ -0,0 +1,159 @@ +## UDP + +- 套接字的目的ip,端口都是任意,因此只有源ip,端口二元组区分不同的套接字 +- 可以接收任何发送方的数据,发送方信息并不保存在套接字中,不影响其他发送者的通信 +- 不需要进行连接 + +--------- + +***服务器与多个客户端收发数据*** + +image-20230204165218196 + +- 服务器和客户端没有区别,只要知道ip和端口就可以直接发数据 +- 通常服务器绑定端口,否则客户端不知道服务器端口号 + +*服务器程序:* + +```c +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +/* socket + * bind + * sendto/recvfrom + */ + +#define SERVER_PORT 8888 + +int main(int argc, char **argv) +{ + int iSocketServer; + struct sockaddr_in tSocketServerAddr; + struct sockaddr_in tSocketClientAddr; + int iRet; + int iAddrLen; + + int iRecvLen; + unsigned char ucRecvBuf[1000]; + + int iClientNum = -1; + + iSocketServer = socket(AF_INET, SOCK_DGRAM, 0);/*SOCK_DGRAM:UDP传输*/ + if (-1 == iSocketServer) + { + printf("socket error!\n"); + return -1; + } + + tSocketServerAddr.sin_family = AF_INET; + tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ + tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; + memset(tSocketServerAddr.sin_zero, 0, 8); + + iRet = bind(iSocketServer, (const struct sockaddr *)&tSocketServerAddr, sizeof(struct sockaddr)); + if (-1 == iRet) + { + printf("bind error!\n"); + return -1; + } + + + while (1) + { + iAddrLen = sizeof(struct sockaddr); + iRecvLen = recvfrom(iSocketServer, ucRecvBuf, 999, 0, (struct sockaddr *)&tSocketClientAddr, &iAddrLen);/*阻塞等待,即使客户端断开仍继续,但收到空数据报返回0*/ + if (iRecvLen > 0) + { + ucRecvBuf[iRecvLen] = '\0'; + printf("Get Msg From %s : %s\n", inet_ntoa(tSocketClientAddr.sin_addr), ucRecvBuf); + } + } + + close(iSocketServer); + return 0; +} + +``` + +*客户端程序:* + +```c +#include +#include +#include +#include +#include +#include +#include +#include + +/* socket + * connect + * sendto/recvfrom + */ + +#define SERVER_PORT 8888 + +int main(int argc, char **argv) +{ + int iSocketClient; + struct sockaddr_in tSocketServerAddr; + + int iRet; + unsigned char ucSendBuf[1000]; + int iSendLen; + int iAddrLen; + + if (argc != 2) + { + printf("Usage:\n"); + printf("%s \n", argv[0]); + return -1; + } + + iSocketClient = socket(AF_INET, SOCK_DGRAM, 0); + + tSocketServerAddr.sin_family = AF_INET; + tSocketServerAddr.sin_port = htons(SERVER_PORT); /* host to net, short */ + //tSocketServerAddr.sin_addr.s_addr = INADDR_ANY; + if (0 == inet_aton(argv[1], &tSocketServerAddr.sin_addr)) + { + printf("invalid server_ip\n"); + return -1; + } + memset(tSocketServerAddr.sin_zero, 0, 8); + + while (1) + { + if (fgets(ucSendBuf, 999, stdin)) + { + + iAddrLen = sizeof(struct sockaddr); + iSendLen = sendto(iSocketClient, ucSendBuf, strlen(ucSendBuf), 0, + (const struct sockaddr *)&tSocketServerAddr, iAddrLen);/*直接发送,不等待到MSS*/ + + if (iSendLen <= 0) + { + close(iSocketClient); + return -1; + } + } + } + + return 0; +} + + +``` + + + diff --git "a/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.pdf" "b/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.pdf" new file mode 100644 index 0000000..413fdd5 Binary files /dev/null and "b/\347\275\221\347\273\234\347\274\226\347\250\213/UDP\347\274\226\347\250\213/UDP.pdf" differ