c++/linux and net OK!

This commit is contained in:
e0x1a 2024-11-23 11:00:35 +00:00
parent 74206e2982
commit 769ca8df25
33 changed files with 942 additions and 485 deletions

View File

@ -1,23 +1,95 @@
#include<iostream> #include<iostream>
#include<unistd.h> #include<unistd.h> //目录操作
#include<dirent.h> #include<dirent.h> //获取目录列表
using namespace std; using namespace std;
int main() int main()
{ {
char buf[255]; //目录操作
if(getcwd(buf, 255) == NULL)
cout << "error" << endl;
else cout << buf << endl;
DIR *ddir; char *getcwd(char *buf, size_t size); //获取当前工作目录
if((ddir = opendir(buf)) == NULL) // 函数内用malloc()分配内存要注意使用free()释放
cout << "error" << endl;
struct dirent* entry; int chdir(const char *path); //切换工作目录
while((entry = readdir(ddir)) != NULL)
cout << entry->d_name << endl;
closedir(ddir);
int mkdir(const char *path_name, mode_t mode); //创建目录
//mode为权限如0775不可省略0
int rmdir(const char *path); //删除目录
//获取目录列表
//步骤一
DIR *opendir(const char *path_name); //打开文件目录
//步骤二
struct dirent *readdir(DIR *dirp); //返回struct dirent结构体地址,一次只读取一项
//步骤三
int closedir(DIR *dirp); //关闭目录
/*
DIR *
struct dirent {
long d_ino; //inode number
off_t d_off // 在目录文件中的偏移
unsigned short d_reclen; //文件名长度
unsigned char d_type; //文件类型 8-常规文件 4-目录
char d_name[NAME_MAX+1]; //文件名最长255
}
*/
/*
int access(const char *path_name, int mode); //可以用来判断用户有没有对文件和目录的权限
#define R_OK 4 //读
#define W_OK 4 //写
#define X_OK 4 //执行
#define F_OK 4 //存在
*/
// 重命名文件
// int rename(const char *oldpath, const char *newpath)
// 删除文件
// int remove(const char *path_name)
/*
#include <sys/stat.h>
struct stat { //存放文件或目录的信息(不完整)
dev_t st_dev; //设备编号
ino_t st_ino; //i-node
mode_t st_mode; //类型和权限
uid_t st_uid; //所有者uid
gid_t st_gid; //所有组
off_t st_size; //大小
size_t st_blocks; //占用文件系统区块数
time_t st_atime; //最后一次被存取或执行
time_t st_mtime; //最后一次被修改
time_t st_ctime; //最后一次属性被更改
}
S_ISREG(st_mode) //文件为真
S_ISDIR(st_mode) //目录为真
int stat(const char *path, struct stat *buf); //获取信息,存到buf中
*/
/*
DIR *dir;
if( (dir=opendir(argv[1])) == nullptr) return -1;
struct dirent *info=nullptr;
while(1) {
if( (info=readdir(dir)) == nullptr) break;
cout << "d_name" << info->d_name << endl;
cout << "d_type" << (int)info->d_type << endl;
}
closedir(dir);
*/
return 0; return 0;
} }

26
c++/linux/exec.cpp Normal file
View File

@ -0,0 +1,26 @@
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
using namespace std;
int main() {
//第一种方法
// int system(const char *command);
// 创建一个子进程来执行
system("/bin/ls -ls");
//第二种方法
// exec函数族
/*
exec函数
int execl(const char *path, const char *arg, ...);
int execv(const char *path, char *const argv[]); //可以用argv[]来放参数,最后一个是0
*/
execl("/bin/ls", "/bin/ls", "-ls", "/tmp", 0); //最后的0不能省略
//执行完后不返回
//新进程的进程号与原来相同
//新进程取代了原来的代码段,数据段,堆栈
return 0;
}

View File

@ -1,153 +0,0 @@
在Linux系统中`fork` 是一个系统调用,用于创建一个新的进程,这个新进程是调用进程的一个副本。这个新进程被称为子进程,而调用进程被称为父进程。`fork` 调用在父进程中返回子进程的PID进程标识符而在子进程中返回0。
以下是使用 `fork` 函数的基本步骤:
1. **包含头文件**:使用 `fork` 函数之前,需要包含 `<unistd.h>` 头文件。
2. **调用 fork**:在代码中调用 `fork()` 函数。
3. **检查返回值**`fork()` 调用会返回一个整数。如果返回值为正数表示在父进程中返回的值是子进程的PID。如果返回值为0表示在子进程中。如果返回值为-1表示创建进程失败。
4. **父进程和子进程的执行流程**:在 `fork()` 调用之后,根据返回值判断当前是在父进程还是子进程,并执行相应的代码。
下面是一个简单的示例代码,展示了如何使用 `fork`
```c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid = fork(); // 创建子进程
if (pid < 0) {
// fork失败
fprintf(stderr, "Fork failed");
return 1;
} else if (pid == 0) {
// 子进程
printf("I'm the child process with PID: %d\n", getpid());
} else {
// 父进程
printf("I'm the parent process with PID: %d, and my child is %d\n", getpid(), pid);
}
return 0;
}
```
当使用 `fork` 系统调用创建子进程时,子进程会继承父进程的许多资源。以下是父子进程共享的一些主要资源:
1. **文件描述符**:子进程会继承父进程打开的所有文件描述符。这意味着子进程可以访问父进程打开的文件和设备。
2. **环境变量**:子进程继承父进程的环境变量,包括语言设置、路径变量等。
3. **内存空间**:子进程会复制父进程的地址空间,包括代码段、数据段和堆栈。但是,子进程的堆栈是独立的,这意味着局部变量和函数调用栈是分开的。
4. **信号处理器**:子进程继承父进程的信号处理器设置。
5. **挂起信号集**:子进程继承父进程的挂起信号集。
6. **资源限制**子进程继承父进程的资源限制如CPU时间、文件大小限制等。
7. **进程组ID**子进程继承父进程的进程组ID。
8. **用户ID和组ID**子进程继承父进程的用户ID和组ID。
9. **工作目录**:子进程继承父进程的工作目录。
10. **根目录**:子进程继承父进程的根目录。
11. **能力**:子进程继承父进程的文件系统能力。
12. **内核定时器**:如果父进程有设置内核定时器,子进程也会继承。
13. **锁**:子进程继承父进程持有的文件锁。
14. **共享内存段**:如果父进程使用了共享内存,子进程也会继承这些共享内存段。
15. **网络连接**:子进程继承父进程的网络连接。
然而,有一些资源是独立的,例如:
- **进程ID**子进程有自己的唯一进程ID。
- **线程特定数据**:每个线程有自己的线程特定数据,子进程不会继承父进程的线程特定数据。
- **CPU寄存器**除了程序计数器和其他一些寄存器外子进程的CPU寄存器状态是复制自父进程的但子进程可以独立修改它们。
在 `fork` 之后,通常使用 `exec` 系列函数来替换子进程的映像,这样可以避免共享不必要的资源,并且可以运行一个完全不同的程序。此外,使用 `fork` 时需要注意资源的同步和清理,以避免潜在的资源竞争和泄漏问题。
下面是一个详细的示例代码展示了如何在C语言中使用 `fork` 系统调用,并演示了父子进程共享资源的基本概念:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
int main() {
pid_t pid = fork(); // 创建子进程
if (pid < 0) {
// fork失败
exit(EXIT_FAILURE);
} else if (pid == 0) {
// 子进程
// 子进程可以继续使用父进程打开的文件描述符
// 例如,这里我们尝试写入标准输出
printf("Hello from the child process!\n");
// 子进程可以修改父进程传递给它的变量的值,但这些修改不会影响父进程
int child_value = 42;
printf("Child value: %d\n", child_value);
} else {
// 父进程
// 父进程可以等待子进程结束
int status;
wait(&status); // 等待子进程结束
// 检查子进程是否正常退出
if (WIFEXITED(status)) {
printf("Child exited with status %d\n", WEXITSTATUS(status));
}
}
// 父进程和子进程都可以访问这个变量,但它们有自己的副本
// 这里我们演示父进程的值不会影响子进程
int shared_variable = 10;
printf("Parent shared variable: %d\n", shared_variable);
return 0;
}
```
在这个示例中:
- 我们首先调用 `fork()` 来创建一个新的子进程。
- 如果 `fork()` 返回一个负值,表示创建进程失败,我们打印错误消息并退出。
- 如果 `fork()` 返回0表示当前是在子进程中。子进程打印自己的PID和PPID父进程ID并写入标准输出。
- 如果 `fork()` 返回一个正值表示当前是在父进程中。父进程打印自己的PID和PPID并等待子进程结束。
- 使用 `wait()` 函数可以让父进程挂起,直到子进程结束。`wait()` 函数还可以获取子进程的退出状态。
- 我们定义了一个 `shared_variable` 变量,并在父进程和子进程中分别打印它的值。由于子进程的栈是独立的,所以子进程中的修改不会影响父进程中的 `shared_variable`。
在使用 `fork` 系统调用创建子进程时,通常会结合其他一些系统调用或库函数来实现特定的功能。以下是一些与 `fork` 相关的常用函数:
1. **exec 系列函数**
- `execl(const char *path, const char *arg0, ..., NULL)`
- `execv(const char *path, char *const argv[])`
- `execle(const char *path, const char *arg0, ..., NULL, char *const envp[])`
- `execve(const char *path, char *const argv[], char *const envp[])`
- `execlp(const char *file, const char *arg0, ..., NULL)`
- `execvp(const char *file, char *const argv[])`
这些函数用于在子进程中执行一个新的程序,替换当前的进程映像。
2. **wait 和 waitpid 函数**
- `wait(int *status)`
- `waitpid(pid_t pid, int *status, int options)`
这些函数用于父进程等待子进程结束。`wait` 函数等待任何一个子进程结束,而 `waitpid` 可以指定等待特定的子进程。
3. **_exit 和 exit 函数**
- `_exit(int status)`
- `exit(int status)`
这两个函数用于终止进程。`_exit` 立即终止进程,不进行任何清理工作;`exit` 在终止进程前会执行一些清理工作如关闭标准I/O流、刷新缓冲区等。
4. **getpid 和 getppid 函数**
- `pid_t getpid(void)`
- `pid_t getppid(void)`
`getpid` 返回调用进程的PID`getppid` 返回调用进程的父进程PID。
8. **signal 和 sigaction 函数**
- `int signal(int signum, void (*handler)(int))`
- `int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact)`
这些函数用于设置信号处理器,处理进程接收到的信号。
9. **kill 函数**
- `int kill(pid_t pid, int sig)`
`kill` 函数用于向指定的进程发送信号。
10. **setsid 函数**
- `pid_t setsid(void)`
`setsid` 用于创建一个新的会话,并使调用进程成为该会话的领头进程。
这些函数在进程管理、信号处理、资源管理等方面起着重要作用,与 `fork` 结合使用可以实现复杂的进程间操作和通信。

69
c++/linux/fork.cpp Normal file
View File

@ -0,0 +1,69 @@
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
using namespace std;
int main() {
// 进程标识(pid)
// pid_t getpid(void); 当前进程
// pid_t getppid(void); 父进程
// fork() 函数
// pid_t fork(void); 创建一个子进程,父进程返回pid子进程返回0
// 子进程获取父进程 数据空间,堆,栈 的副本,并不是共享
// 若父进程比子进程先退出那么子进程由1号进程托管
// 若子进程先退出,而父进程没处理,则会造成僵尸进程(No!)
pid_t pid;
pid = fork(); //创建一个子进程
if(pid != 0) cout << "是父进程" << getpid() << endl;
else if(pid == 0) cout << "是子进程" << getpid() << endl;
else cout << "进程创建失败" << endl;
// 僵尸进程的避免
// 1.
// signal(SIGCHLD, SIG_IGN); 忽略子进程退出的信息,交由系统处理
//
// 2. 使用wait()/waitpid() 阻塞等待子进程结束
// pid_t wait(int *stat_loc); 返回子进程pid
// pid_t waitpid(pid_t pid, int *stat_loc, int options);
//
// stat_loc是进程终止的信息
// a. 正常终止 WIFEXITED(stat_loc) 返回真 WEXITSTATUS(stat_loc)获取终止信息
// b. 异常终止 WTERMSIG(stat_loc) 获取终止进程的信号
//
// 3. 收到SIGCHLD信号后wait() 相当于非阻塞,不影响父进程
if(pid != 0) {
int status;
pid = wait(&status);
cout << "进程" << pid;
if(WIFEXITED(status)) cout << "正常终止" << endl;
else cout << "" << WTERMSIG(status) << "信号异常终止" << endl;
} else sleep(100);
return 0;
}
// 当使用fork创建子进程时子进程会继承父进程的资源
/*
1. ****访
2. ****
3. ****
4. ****
5. ****
6. ****CPU时间
7. **ID**ID
8. **ID和组ID**ID和组ID
9. ****
10. ****
11. ****
12. ****
13. ****
14. ****使
- **ID**ID
- **线**线线线
- **CPU寄存器**CPU寄存器状态是复制自父进程的
*/

41
c++/linux/keys.cpp Normal file
View File

@ -0,0 +1,41 @@
#include <iostream>
#include <unistd.h>
#include <termio.h>
using namespace std;
int key() {
// struct termios
// {
// tcflag_t c_iflag; /* input mode flags */
// tcflag_t c_oflag; /* output mode flags */
// tcflag_t c_cflag; /* control mode flags */
// tcflag_t c_lflag; /* local mode flags */
// cc_t c_line; /* line discipline */
// cc_t c_cc[NCCS]; /* control characters */
// speed_t c_ispeed; /* input speed */
// speed_t c_ospeed; /* output speed */
// #define _HAVE_STRUCT_TERMIOS_C_ISPEED 1
// #define _HAVE_STRUCT_TERMIOS_C_OSPEED 1
// };
unsigned char in;
struct termios new_settings, old_settings;
tcgetattr(STDIN_FILENO,&old_settings); //获得stdin 输入
new_settings = old_settings;
new_settings.c_lflag &= (~ICANON);
// new_settings.c_cc[VTIME] = 0;
// tcgetattr(STDIN_FILENO,&old_settings); //获得stdin 输入
// new_settings.c_cc[VMIN] = 1;
tcsetattr(STDIN_FILENO,TCSANOW,&new_settings); //
in = getchar();
tcsetattr(STDIN_FILENO,TCSANOW,&old_settings);
return in;
}
int main() {
while(1)
printf(" %d \n", key());
return 0;
}

View File

@ -0,0 +1,37 @@
#include <iostream>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/shm.h>
using namespace std;
int main() {
// int shmget(key_t key, size_t size, int shmflg); 创建/获取 共享内存
// key 共享内存的键值 size 待创建的大小 shmflg 访问权限(同文件权限) IPC_CREAT 若无则创建
// 成功返回共享内存的ID
int shmid;
shmid = shmget(0x5005, 400, 0666|IPC_CREAT);
cout << shmid << endl;
if(shmid == -1) cout << "创建失败" << endl;
// 使用ipcs命令查看系统的共享内存
// ipcrm -m [id] 删除共享内存
// void *shmat(int shmid, const void *shmaddr, int shmflg); 连接到当前进程空间
// shmid shmget()的返回值
// shmaddr 连接位置通常写0让系统决定
// shmflg 标志位 0
// 成功时返回地址
//
// shmdt(const void *shmaddr); 分离共享内存
//
// shmctl(shmid, IPC_RMID, 0); 删除共享内存
int *arr;
arr = (int *)shmat(shmid, 0, 0);
if(arr == (void *)-1) cout << "shmat error" << endl;
cout << arr[0] << endl;
arr[0] = 1234;
shmdt(arr);
return 0;
}

55
c++/linux/signal.cpp Normal file
View File

@ -0,0 +1,55 @@
#include <iostream>
#include <unistd.h>
#include <signal.h>
using namespace std;
void func(int signum) {
printf("接收到一个信号 %d\n",signum);
}
int main() {
// 信号的处理
//sighandler_t signal(int signum, sighandler_t handler):
// 信号编号 处理函数
//
// signal(1, SIG_DFL); 对信号1恢复默认处理方式
// signal(1, SIG_IGN); 对信号1忽略
//
//通过发送0的信号可以检测程序是否存活
signal(1, func); //接受1的信号并使用func()处理 注意! func()不要加()
alarm(5); //闹钟, 5秒后向本程序发送14的信号,只有一次
signal(14, func);
// 信号的发送
//int kill(pid_t pid, int sig);
// pid > 0 发送给进程号pid的进程
// pid == 0 发给相同进程组的所有进程
// pid = -1 广播给系统内所有进程
while(1) sleep(1);
return 0;
}
/*
SIGHUP 1 A
-> SIGINT 2 A C + c
SIGFPE 8 C
-> SIGKILL 9 AEF kill -9
SIGSEGV 11 C
SIGPIPE 13 A
-> SIGALRM 14 A alarm()
-> SIGTERM 15 A kill默认
-> SIGCHLD 17 B
A
B
C core dump
D
E
F
*/

37
c++/linux/time.cpp Normal file
View File

@ -0,0 +1,37 @@
#include <iostream>
#include <time.h> // 时间函数库
#include <unistd.h> //程序睡眠函数库
using namespace std;
int main() {
time_t t1; //存放时间类型的类型 typedef long time_t
// time() 获取当前时间
// 原型 time_t time(time_t *tloc)
t1 = time(0); // == time(&t1);
/*
struct tm {
int tm_year;
int tm_mon;
int tm_mday;
int tm_hour;
int tm_min;
int tm_sec;
int tm_wday;
int tm_yday; 1.1
int tm_isdst;
}
struct tm * localtime(const time_t *time) time_t转换成tm结构体
struct tm * localtime_r(const time_t *time, struct tm *result) 线
time_t mktime(struct tm *tm); tm转换成time_t
*/
// 程序睡眠
unsigned int sleep(unsigned int seconds); //单位s
int usleep(useconds_t usec); //微妙
return 0;
}

View File

@ -0,0 +1,64 @@
// 示例客户端程序
// 发送文件到服务端
#include <iostream>
#include <fstream>
#include "tn.h"
using namespace std;
struct FileStat { //存放文件信息
char name[128]; // 文件名
size_t fsize = 0, read = 0, ssize = 0;
//文件大小 文件已读大小 本次发送大小
};
int pton(char *, const char *);
int file_out(TN &, char *); // 传入一个连接和文件路径
int main(int argc, char *argv[]) {
if(argc != 2) {
cout << "Using: ./cli.exe 文件名" << endl;
return 0;
}
TN test1;
if(test1.client("127.0.0.1","12345")!=0)
return 0;
cout << "连接已成功" << endl;
cout << file_out(test1, argv[1]) << endl;
cout << "连接断开" << endl;
return 0;
}
int pton(char *name, const char *path) {
int ptr = strlen(path);
while(ptr!=0 && path[ptr-1]!='/')
ptr--;
for(int j=0; ptr<=strlen(path); j++,ptr++)
name[j]=path[ptr];
return 0;
}
int file_out(TN &tn, char *path) { // 传入一个连接和文件路径
const unsigned int BSIZE = 1024;
char buffer[BSIZE];
FileStat fs;
fstream fin(path, ios::in|ios::binary);
pton(fs.name, (const char *)path);
fin.seekg(0, ios::end);
fs.fsize = fin.tellg();
fin.seekg(0, ios::beg);
// 发送信息
if(tn.out((FileStat *)&fs, sizeof(fs))!=0) return 0;
if(tn.in((char *)buffer)!=0) return 0; // 接收确认报文
// 正式发送文件
while(fin.good() && fs.fsize>fs.read) {
memset(buffer, 0, sizeof(buffer));
fs.ssize = (fs.fsize-fs.read)>BSIZE? BSIZE:(fs.fsize-fs.read);
fin.read(buffer, fs.ssize);
if(tn.out(buffer, fs.ssize)!=0) return -1;
fs.read += fs.ssize;
}
fin.close();
return 0;
}

View File

@ -0,0 +1,5 @@
main: ser.o cli.o tn.o
g++ -o ser.exe ser.o tn.o
g++ -o cli.exe cli.o tn.o
clear:
rm *.o *.exe

View File

@ -0,0 +1,61 @@
// 示例服务端程序
// 一个可以接收文件的服务端程序
#include <iostream>
#include <fstream>
#include "tn.h"
using namespace std;
struct FileStat { //存放文件信息
char name[128]; // 文件名
size_t fsize = 0, read = 0, ssize = 0;
//文件大小 文件已读大小 本次发送大小
};
int pton(char *, const char *);
int file_in(TN &, char *); // 传入一个连接和文件保存目录
int main(int argc, char *argv[]) {
if(argc != 2 || (argv[1][strlen(argv[1])-1]!='/')) {
cout << "Using: ./ser.exe [PATH]/" << endl;
return 0;
}
TN test1;
test1.server("12345", 10);
cout << "客户端连接成功" << endl;
cout << file_in(test1, argv[1]) << endl;
cout << "客户端连接断开" << endl;
return 0;
}
int pton(char *name, const char *path) {
int ptr = strlen(path);
while(ptr!=0 && path[ptr-1]!='/')
ptr--;
for(int j=0; ptr<=strlen(path); j++,ptr++)
name[j]=path[ptr];
return 0;
}
int file_in(TN &tn, char *path) { // 传入一个连接和文件保存目录
const unsigned int BSIZE = 1024;
char buffer[BSIZE];
FileStat fs;
fstream fout;
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, path);
if(tn.in((FileStat *)&fs, sizeof(fs))!=0) return 0; // 接收文件信息
strcat(buffer, fs.name); // 连接字符串
// strcpy(fs.name, buffer);
fout.open(buffer, ios::out|ios::trunc|ios::binary); // 打开保存文件
if(tn.out((char *)"OK")!=0) return 0; // 发送确认报文
while(fout.good() && fs.fsize>fs.read) {
memset(buffer, 0, sizeof(buffer));
fs.ssize = (fs.fsize-fs.read)>BSIZE? BSIZE:(fs.fsize-fs.read);
if(tn.in(buffer, fs.ssize)!=0) return -2;
fout.write(buffer, fs.ssize);
fs.read += fs.ssize;
}
fout.close();
return 0;
}

View File

@ -0,0 +1,119 @@
#include "tn.h"
using namespace std;
TN::TN() {
iofd = listenfd = 0;
}
TN::~TN() {
close(listenfd); //关闭连接
close(iofd); //关闭连接
}
int TN::server(const char *open_port, int connections) {
// 创建服务端socket
listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd == -1)
return -1;
// 向客户端请求连接
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(atoi(open_port)); //指定连接端口
// 解决端口重用问题
int opt = 1;
setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof opt);
// 绑定服务端IP及端口
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0)
return -1; // 绑定失败
// 把端口设为监听
if(listen(listenfd, connections) != 0) //第二个参数+1为已连接队列(已三次握手但没有accept)
return -1;
return s_accept();
}
int TN::client(const char *ip, const char *port) {
// 创建客户端socket
iofd = socket(AF_INET, SOCK_STREAM, 0);
if(iofd == -1)
return -1;
// 向服务端请求连接
if( (h = gethostbyname(ip)) == 0) // 指定ip地址
return -1;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(port)); //指定连接端口
memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);
if(connect(iofd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) //发起连接请求
return -1; //连接失败
return 0;
}
int TN::s_accept() {
// 受理客户端连接请求, accept()阻塞等待
signal(SIGINT, TN_exit);signal(SIGTERM, TN_exit);
while(true) {
iofd = accept(listenfd, 0, 0);
if(iofd == -1) {
close(iofd); return -1; // 连接失败
}
int pid = fork();
if(pid == 0) { // 创建子进程处理连接
signal(SIGINT, SIG_IGN); signal(SIGTERM, SIG_DFL);
close(listenfd);
break;
}
else if(pid < 0) return -1;
else close(iofd);
}
return 0;
}
int TN::out(char *str) {
if(send(iofd, str, strlen(str), 0) <= 0) // 发送报文
return -1; // 报文发送不成功
return 0;
}
int TN::in(char *str) {
//接收报文, recv()将阻塞等待
memset(str, 0, sizeof(str));
if(recv(iofd, str, sizeof(str), 0) <= 0)
return -1; // 未成功接收报文
return 0;
}
int TN::out(void *str, size_t fsize) {
if(send(iofd, str, fsize, 0) <= 0) // 发送报文
return -1; // 报文发送不成功
return 0;
}
int TN::in(void *str, size_t fsize) {
//接收报文, recv()将阻塞等待
memset(str, 0, fsize);
if(recv(iofd, str, fsize, 0) <= 0)
return -1; // 未成功接收报文
return 0;
}
socklen_t TN::bufsize(size_t buf_send, size_t buf_recv) {
socklen_t optlen = sizeof(buf_send);
// 接收缓冲区大小
getsockopt(iofd, SOL_SOCKET, SO_SNDBUF, &buf_send, &optlen);
// 发送缓冲区大小
getsockopt(iofd, SOL_SOCKET, SO_RCVBUF, &buf_recv, &optlen);
return optlen;
}
int TN::nagle_off() {
int opt = 1;
setsockopt(iofd, IPPROTO_TCP, TCP_NODELAY, &opt, sizeof(opt));
return 0;
}
void TN_exit(int sig) {
signal(SIGTERM, SIG_IGN); signal(SIGINT, SIG_IGN); //避免再次干扰
kill(0, SIGTERM); // 通知所有子进程退出
exit(0);
}

View File

@ -0,0 +1,64 @@
// Copyright (c) 2024 ely. All rights reserved.
// simple_TcpNet
// 宗旨:简单易用,且尽可能的自由
// versions 1.0.2
// 大版本 小版本 修订版本
#ifndef TCPNET
#define TCPNET
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/tcp.h>
class TN { // tcp socker net
private:
int iofd, listenfd;
struct hostent* h;
struct sockaddr_in servaddr;
int s_accept();
public:
TN();
~TN();
int server(const char *, int);
// 服务端的初始化函数
// 传入一个使用的端口号(请尽量用大于1024的值)和最大等待连接数
// 服务端受理并处理连接,使用多进程以连接多个客户端
// 若返回0表示成功与一个客户端建立连接
int client(const char *, const char *);
// 客户端的初始化函数
// 参数为服务端ip和端口
// 若返回0表示成功与一个服务端建立连接
// 网络I/O函数 在连接建立后即可使用此组函数进行通信
int out(char *);
int in(char *);
// 重载的任意类型IO函数第二个参数是类型大小
int out(void *, size_t);
int in(void *, size_t);
// 查看socket发送和接收缓冲区的大小
socklen_t bufsize(size_t buf_send, size_t buf_recv);
// 禁用Nagle算法,可以减少延迟,但是带宽利用不充分
int nagle_off();
};
void TN_exit(int sig);
#endif
/*
HISTORY
1.0.1
1.0.2 bufsize函数查看缓冲区大小 nagle_off开关
PLAN
*/

View File

@ -1,65 +0,0 @@
#include <iostream>
#include <cstring>
//#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
//#include <sys/types.h>
//#include <sys/socket.h>
//#include <arpa/inet.h>
using namespace std;
int net_send(char *argv[], char *buffer) {
if(strlen(buffer) > 1024) {
cout << "字符串长度超出限制" << endl; return -1;
}
// 创建客户端socket
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1) {
cout << "socket创建失败" << endl; return -1;
}
// 向服务端请求连接
struct hostent* h;
if( (h = gethostbyname(argv[1])) == 0) {
cout << "地址不正确" << endl; close(sockfd); return -1;
}
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2])); //指定连接端口
memcpy(&servaddr.sin_addr, h->h_addr, h->h_length);
if(connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) { //发起连接请求
cout << "连接失败" << endl; close(sockfd); return -1;
}
// 客户端通信
if(send(sockfd, buffer, strlen(buffer), 0) <= 0) { //发送请求报文
cout << "请求报文发送不成功" << endl; return -1;
}
//接收服务端回应报文, recv()将阻塞等待
memset(buffer, 0, sizeof(buffer));
if(recv(sockfd, buffer, sizeof(buffer), 0) <= 0) {
cout << "服务器断开--未成功接收回应报文" << endl; return -1;
}
// 回应报文
cout << buffer << endl;
//关闭连接
close(sockfd);
return 0;
}
int main(int argc, char *argv[]) {
if(argc != 3) {
cout << "参数不正确" << endl; return -1;
}
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
cout << "input data : ";
fgets(buffer, sizeof(buffer), stdin);
net_send(argv, buffer);
return 0;
}

View File

@ -1,73 +0,0 @@
#include <iostream>
#include <cstring>
//#include <cstdlib>
#include <unistd.h>
#include <netdb.h>
//#include <sys/types.h>
//#include <sys/socket.h>
//#include <arpa/inet.h>
using namespace std;
int handling(char *buffer) { // 数据处理函数
if(strcmp(buffer, "off\n") == 0) {
cout << "服务端指令关闭服务器" << endl; return -1;
}
cout << "成功接收" << endl << buffer << endl;
return 0;
}
int main(int argc, char *argv[]) {
if(argc != 2) {
cout << "参数不正确" << endl; return -1;
}
// 创建服务端socket
int listenfd = socket(AF_INET, SOCK_STREAM, 0);
if(listenfd == -1) {
cout << "socket创建失败" << endl; return -1;
}
// 向客户端请求连接
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htons(INADDR_ANY);
servaddr.sin_port = htons(atoi(argv[1])); //指定连接端口
// 绑定服务端IP及端口
if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) != 0) {
cout << "端口未成功绑定" << endl; close(listenfd); return -1;
}
// 把端口设为监听
if(listen(listenfd, 5) != 0) {
cout << "端口无法监听" << endl; close(listenfd); return -1;
}
// 受理客户端连接请求, accept()阻塞等待
int clistenfd;
while(true) {
clistenfd = accept(listenfd, 0, 0);
if(clistenfd == -1) {
cout << "未正常受理连接" << endl; close(listenfd); return -1;
}
cout << "客户端已连接" << endl;
//与客户端通信
char buffer[1024];
memset(buffer, 0, sizeof(buffer));
if(recv(clistenfd, buffer, sizeof(buffer), 0) <= 0) { // 接受服务端报文
cout << "客户端连接已断开" << endl; break;
}
if(handling(buffer) == -1) break; //对接受数据进行处理
// 发送回应报文
strcpy(buffer, "OK");
if(send(clistenfd, buffer, strlen(buffer), 0) <= 0) {
cout << "发送回应报文失败" << endl; break;
}
}
//关闭连接
close(clistenfd);
close(listenfd);
return 0;
}

View File

@ -1,5 +0,0 @@
main: 1.cpp 2.cpp
g++ -o 1.out 1.cpp
g++ -o 2.out 2.cpp
clear:
rm *.out

View File

@ -1,112 +0,0 @@
一、输入输出流的概念
在C++中输入输出是同流来完成的。C++的输出操作将一个对象的状态转换成一个字符序列,输出到某个地方。
输入操作也是从某个地方接收到一个字符序列,然后将其转换成一个对象的状态所要求的格式。
这看起来很像数据在流动,于是把接收输出数据的地方叫做目标,把输入数据来自的地方叫做源。
而输入和输出操作可以看成字符序列在源、目标以及对象之间的流动。
二、文件流的概念
在C++里文件操作是通过流来完成的。C++总共有输入文件流、输出文件流和输入输出文件流3种并已将它们标准化。
1、要打开一个输入文件流需要定义一个 ifstream类型的对象。->Input-stream
2、要打开一个输出文件流需要定义一个 ofstream类型的对象。->Ouput-stream
3、如果要打开输入输出文件流则要定义一个 fstream类型的对象。->File-stream
这3种类型都定义在头文件 fstream 里。
一个输出流对象是信息流动的目标ofstream是最重要的输出流。
一个输入流对象是数据流动的源头ifstream是最重要的输入流。
一个iostream对象可以是数据流动的源或目标fstream就是从它派生的。
三、文件操作
可以总结出对文件进行操作的方法如下:
1包含头文件 <fstream>
2创建一个流对象
3将这个流和相应的文件关联起来
#include<iostream>
#include<fstream> //1、包含输入输出流头文件
using namespace std;
void outstream(){
ofstream ofs; //2、打开一个相应的文件流
ofs.open("mytest.txt"); //3、流与文件关联上
};
int main(){
return 0;
}
因为ifstream、ofstream和fstream这3个类都具有自动打开文件的构造函数而这个构造函数就具有 open() 的功能。
因此我们可以在创建流对象的时候就可以关联文件ofstream myStream("myText.txt");
4操作文件流 👇
1、文本文件
1.1、写文件
注意:
我们在写文件的时候如果打开的文件不存在或者路径错误那么会自动生成一个文件!!!
open函数的原型如下
void open(char const *,int filemode,int =filebuf::openprot);
它有3个参数第1个是要打开的文件名第2个是文件的打开方式第3个是文件的保护方式一般都使用默认值。
第2个参数可以取如下所示的值
打开方式 解释
ios::in 打开文件进行读操作,这种方式可避免删除现存文件的内容
ios::out 打开文件进行写操作,这是默认模式
ios::ate 打开一个已有的输入或输出文件并查找到文件尾开始
ios::app 在文件尾追加方式写文件
ios::binary 指定文件以二进制方式打开,默认为文本方式
ios::trunc 如文件存在,将其长度截断为零并清除原有内容,如果文件存在先删除,再创建
除ios_base::app方式之外在其他几种方式下文件刚刚打开是指示当前读写位置的文件指针都定位于文件的开始位置而ios_base::app使文件当前的写指针定位于文件尾。这几种方式也可以通过 “或” 运算符 “|” 同时使用
如果指定文件路径,路径中的“\”号必须使用转义字符表示。
案例:
void outperint() {
ofstream ofs; //打开一个写的文件流
ofs.open("test.txt", ios::out); //把这个流和文件关联起来
ofs << "姓名:张三" << endl;
ofs << "年龄18" << endl;
ofs << "性别:男" << endl;
ofs.close(); //操作完成记得close()关闭
}
1.2、读文件
函 数 功 能
函数 功能
bad() 如果进行非法操作返回true否则返回false
clear() 设置内部错误状态,如果用缺省参量调用则清除所有错误位
eof() 如果提取操作已经到达文件尾则返回true否则返回false
good() 如果没有错误条件和没有设置文件结束标志返回true否则返回false
fail() 与good相反操作失败返回false否则返回true
is_open() 判定流对象是否成功地与文件关联若是返回true否则返回false
void inputfile() {
ifstream ofs;
ofs.open("test.txt", ios::in);
if (ofs.is_open()) {
cout << "已成功和文件关联!!!" << endl;
//两种方式
//第一种
char chr[1024];
while (ofs >> chr) {
cout << chr << endl;
}
//第二种
char buf[1024] = { 0 };
while (ofs.getline(buf, sizeof(buf)));
{
cout << buf << endl;
}
};
if (!ofs.is_open()) { //不为真
cout << "尚未与文件关联!!!" << endl;
}
ofs.close();
随机存取
seekg(pos,ios::);
seekg(pos);
seekp(pos,ios::);
seekp(pos);
tellg(pos,ios::);
tellg(pos);
tellp(pos,ios::);
tellp(pos);

7
c++/universal/argc.cpp Normal file
View File

@ -0,0 +1,7 @@
#include <stdio.h>
int main(int argv, char *argc[]) {
printf("传入了 %d 个参数\n",argv);
for(int i = 0; i < argv; i++)
printf("第%d个参数: %s\n",i+1,argc[i]);
return 0;
}

View File

@ -1,4 +1,3 @@
头函数库
#include<bits/stdc++.h>//万能头,包括大部分头文件。 #include<bits/stdc++.h>//万能头,包括大部分头文件。
#include <ctype.h>//字符处理 #include <ctype.h>//字符处理
#include <cctype> #include <cctype>

106
c++/universal/io.cpp Normal file
View File

@ -0,0 +1,106 @@
#include <iostream>
#include <fstream>
using namespace std;
void c_io(); // c IO
void stream_io(); // c++ 流IO
void stream_fio(); // c++ 流文件IO
int main() {
c_io();
return 0;
}
void c_io() {
int i = 14;
double d = 3.3;
char c = 'e';
const char * str = "Hello";
// scanf & printf
// in
scanf("%d %lf %c %s", &i, &d, &c, &str);
// out
printf("%d---%3d---%x---%o \n", i, i, i, i); //int型
printf("%3.3f \n", d); //double型
printf("%c \n", c); //char
printf("%s \n", str); //str
printf("%p \n", i); //地址
c = getchar(); //读入一个char, 最快
putchar();
fgets();
}
void stream_io() {
// ios::sync_with_stdio(false);cin.tie(0),cout.tie(0); 关闭缓冲加速
int i = 14;
double d = 3.3;
char c = 'e';
const char * str = "Hello";
cin.get(c); //返回一个流引用
c = cin.get(); //返回char略快
cin.get(str, 100, '\n'); //读入字符串
cin.width(10); //设置场宽
}
void stream_fio() {
//文件流的创建 打开 关闭
fstream fin;
fstream fout;
fin.open("in");
fout.open("out");
fin.close();
fout.close();
/*
open函数的原型如下
void open(char const *,int filemode,int =filebuf::openprot);
3123使
2
ios::in
ios::out
ios::ate
ios::app
ios::binary
ios::trunc
ios_base::app方式之外ios_base::app使文件当前的写指针定位于文件尾
bad() truefalse
clear()
eof() truefalse
good() truefalse
fail() good相反falsetrue
is_open() truefalse
*/
// 二进制文件读写
fin.write((char*)&data, sizeof data);
fin.read((char*)&data, sizeof data);
/*
seekg(pos,ios::);
seekg(pos);
seekp(pos,ios::);
seekp(pos);
tellg();
tellp();
ios::beg
ios::cur
ios::end
*/
}

View File

@ -1,51 +1,73 @@
# c风格字符串处理函数 #include <iostream>
#include <cstring>
using namespace std;
strcpy(buf, "hello"); // 用后面的字符串覆盖前面的字符串 void c_char(const char *,const char *);
strncpy(buf, "hello", 5); // 增加指定长度 void c_string(const char *,const char *);
strcat(buf, "hello"); // 连接字符串 int main() {
strncat(buf, "hello", 5); char a[1000],b[1000];
cin >> a >> b; // 流读入
strcmp(buf, "hello"); // 比较字符串,相等返回0 c_char(a, b); //c风格字符串
c_string(a, b); //string
strlen(buf); // 返回长度,不包括'\0' return 0;
}
strstr(buf, "hello"); // 返回第一次出现子串的指针 void c_char(const char *str1,const char *str2) {
char buf1[1000],buf2[1000];
printf("c风格字符串\n\n");
strcpy(buf1, str1); strcpy(buf2, str2);
strtok(buf, " "); // 分割字符串,返回分割过的字符串 strcpy(buf1, "hello"); // 用后面的字符串覆盖前面的字符串
strncpy(buf1, "hello", 5); // 增加指定长度
memset(buf, 0, sizeof(buf));//覆写内存块 strcat(buf1, "hello"); // 连接字符串
strncat(buf1, "hello", 5);
memcpy(buf, "hello", 5); //复制内存块 strcmp(buf1, "hello"); // 比较字符串,相等返回0
memmove(buf + 1, buf, 4); //移动5个字节到前一个位置 strlen(buf1); // 返回长度,不包括'\0'
strstr(buf1, "hello"); // 返回第一次出现子串的指针
# string strtok(buf1, " "); // 分割字符串,返回分割过的字符串
## 构造 memset(buf1, 0, sizeof(buf1));//覆写内存块
memcpy(buf1, "hello", 5); //复制内存块
memmove(buf1 + 1, buf1, 4); //移动5个字节到前一个位置
}
void c_string(const char *str1, const char *str2) {
string buf;
/*
// 构造
string(); // 默认构造,创建一个空的字符串 string(); // 默认构造,创建一个空的字符串
string(const char &str); // c风格字符串初始化 string(const char &str1); // c风格字符串初始化
string(int n,char c); // 用字符填充一个字符串 string(int n,char c); // 用字符填充一个字符串
## 赋值 // 赋值
string& operator=(const char* str); // c风格字符串赋值给当前string类 string& operator=(const char* str1); // c风格字符串赋值给当前string类
string& operator=(const string& str); // 另一个容器复制 string& operator=(const string& buf); // 另一个容器复制
string& operator=(const cahr c); // 字符赋值 string& operator=(const cahr c); // 字符赋值
## 存取 // 存取
char& operator[](int n); // 通过[]获取字符,注意溢出 char& operator[](int n); // 通过[]获取字符,注意溢出
## 拼接 // 拼接
string& operator+=(const string& str); // 追加到末尾 string& operator+=(const string& str); // 追加到末尾
string& operator+=(const char* str); // 追加到末尾 string& operator+=(const char* str); // 追加到末尾
string& operator+=(const char c); // 追加到末尾 string& operator+=(const char c); // 追加到末尾
## 查找 // 查找
int find(const string& str, int pos = 0) const; // 查找str在当前字符串第一次出现的位置,pos为开始查找的位置 int find(const string& str, int pos = 0) const; // 查找str在当前字符串第一次出现的位置,pos为开始查找的位置
int find(const char* str, int pos = 0) const; // 查找str在当前字符串第一次出现的位置 int find(const char* str, int pos = 0) const; // 查找str在当前字符串第一次出现的位置
@ -53,29 +75,29 @@
string::npos -1 size_t的最大值 string::npos -1 size_t的最大值
## 替换 // 替换
string& replace(int pos, int n, const string& str); // 从pos开始替换n个字符 string& replace(int pos, int n, const string& str); // 从pos开始替换n个字符
string& replace(int pos, int n, const char* str); // 从pos开始替换n个字符 string& replace(int pos, int n, const char* str); // 从pos开始替换n个字符
## 比较 // 比较
int compare(const string& str) const; //根据字典序 int compare(const string& str) const; //根据字典序
int compare(const char* str) const; //根据字典序 int compare(const char* str) const; //根据字典序
## 子串 // 子串
string substr(int pos = 0, int n = npos) const; //返回从pos开始,长度为n的子串 string substr(int pos = 0, int n = npos) const; //返回从pos开始,长度为n的子串
## 插入 // 插入
string& insert(int pos, const char* str); //在pos位置插入 string& insert(int pos, const char* str); //在pos位置插入
string& insert(int pos, const string& str); //在pos位置插入 string& insert(int pos, const string& str); //在pos位置插入
string& insert(int pos, int n, char c); //在pos位置插入 string& insert(int pos, int n, char c); //在pos位置插入
## 删除 // 删除
string& erase(int pos, int n = npos); //在pos位置插入 string& erase(int pos, int n = npos); //在pos位置插入
@ -90,3 +112,7 @@
# 神奇转换函数 # 神奇转换函数
string to_ strinf(); //将好多类型转换成string string to_ strinf(); //将好多类型转换成string
*/
}

35
c++/universal/thread.cpp Normal file
View File

@ -0,0 +1,35 @@
#include <iostream>
#include <thread>
using namespace std;
void func(int a) {
cout << a << endl;
}
mutex mtx; // 互斥量
int main() {
// 同一个进程的多个线程共享该进程的全部系统资源
// 但各个线程有自己的调用栈,寄存器,本地存储
// thread类
// 1.
// thread() noexcept;默认构造函数,不执行任何任务
// 2.
// template<class Funtion, class ...Args>
// explicit thread(Function&& fx,Args&&... args);
thread t1(func, 1); //用2方法创建线程
// mtx.lock();
// mtx.unlock();
if(t1.joinable()) // 判断能否调用join
t1.join(); //回收线程t1
// t1.detach(); //分离线程
return 0;
}
// 注g++编译器要加 -pthread -std=c++11选项编译

2
linux/command/nohup.txt Normal file
View File

@ -0,0 +1,2 @@
nohup 命令挂机(退出登陆后依然执行)
nohup [command] &

View File

@ -1,8 +1,3 @@
#1
nohup 命令挂机(退出登陆后依然执行)
nohup [command] &
#2 screen
`screen` 是一个功能强大的命令行工具,主要用于 Unix 和类 Unix 操作系统中,它允许用户开启多个独立的会话(称为"窗口"),在这些会话之间可以自由切换而不会中断已经运行的程序。以下是 `screen` 的一些主要功能和使用方法: `screen` 是一个功能强大的命令行工具,主要用于 Unix 和类 Unix 操作系统中,它允许用户开启多个独立的会话(称为"窗口"),在这些会话之间可以自由切换而不会中断已经运行的程序。以下是 `screen` 的一些主要功能和使用方法:
### 主要功能: ### 主要功能:
1. **多会话管理**:可以同时运行多个独立的 shell 会话。 1. **多会话管理**:可以同时运行多个独立的 shell 会话。
@ -42,30 +37,3 @@ nohup 命令挂机(退出登陆后依然执行)
- 退出所有窗口并结束会话:在 screen 会话中按 `Ctrl-a` 然后按 `\`。 - 退出所有窗口并结束会话:在 screen 会话中按 `Ctrl-a` 然后按 `\`。
10. **锁定当前会话** 10. **锁定当前会话**
在 screen 会话中按 `Ctrl-a` 然后按 `x`。 在 screen 会话中按 `Ctrl-a` 然后按 `x`。
#3 smartctl
查看硬盘状态参数
-a 全部参数
-H 是否正常
#4 perf
性能剖析工具
可分析程序运行期间发生的系统硬件事件
sudo perf record ./a.out
sudo perf report -i perf.data
#5 ulimit
查看和修改进程运行资源限制
-H/S # 设置/显示 软/硬 限制
-a # 显示所有
-t # cpu time
-f # file size
-s # stack size
-c # core file size
-m # memory size
-l # lock memory size
-p # user processes
-n # open file
#ulimit -Ht 3600

View File

@ -0,0 +1,4 @@
#3 smartctl
查看硬盘状态参数
-a 全部参数
-H 是否正常

14
linux/command/ulimit.txt Normal file
View File

@ -0,0 +1,14 @@
#5 ulimit
查看和修改进程运行资源限制
-H/S # 设置/显示 软/硬 限制
-a # 显示所有
-t # cpu time
-f # file size
-s # stack size
-c # core file size
-m # memory size
-l # lock memory size
-p # user processes
-n # open file
#ulimit -Ht 3600

View File

@ -1,5 +1,6 @@
syntax on syntax on
set number "显示行号 set number "显示行号
"set rnu "相对行号
set ts=4 set ts=4
"set expandtab "tab to space "set expandtab "tab to space
set autoindent "自动缩进 set autoindent "自动缩进
@ -14,17 +15,31 @@ set hlsearch "高亮显示搜索结果
set incsearch "搜索模式下,每输入一个字符,就跳到对应结果 set incsearch "搜索模式下,每输入一个字符,就跳到对应结果
set ignorecase "忽略搜索大小写 set ignorecase "忽略搜索大小写
nnoremap <space>b :buffers<cr>:b<space> nnoremap <space>b :buffers<cr>:b<space>
nnoremap <space>e :b#<cr> nnoremap <space>e :b#<cr>
nnoremap <space>n :bnext<cr>
nnoremap <space>s :split<space> nnoremap <space>s :split<space>
nnoremap <space>v :vsp<space>
nnoremap <space>d <c-w>w
nnoremap <space>w :w<cr> nnoremap <space>w :w<cr>
nnoremap qw :wq<cr> nnoremap <space>q :q<cr>
nnoremap qq :q<cr>
nnoremap <space>tt :tabedit<space> nnoremap <space>tt :tabedit<space>
nnoremap <space>to :tabonly<cr> nnoremap <space>to :tabonly<cr>
nnoremap <space>tc :tabclose<cr>
inoremap jf <esc> inoremap jf <esc>
inoremap jq <esc>:wq<cr> inoremap jq <esc>:wq<cr>
inoremap jw <c-x><c-n> inoremap jw <c-x><c-n>
inoremap jl <c-x><c-l> inoremap jl <c-x><c-l>
cnoremap jf <c-c> cnoremap jf <c-c>
augroup numbertoggle 智能切换绝对行号和相对行号
autocmd!
autocmd BufEnter,FocusGained,InsertLeave,WinEnter * if &nu && mode() != "i" | set rnu | endif
autocmd BufLeave,FocusLost,InsertEnter,WinLeave * if &nu | set nornu | endif
augroup END
" vim笔记
" 使用 q[Key] 开始录制宏,再次点击q结束录制
" @[Key] 调用宏
"
" # 键向上查找当前单词

View File

@ -2,6 +2,8 @@ g++ -S test.s test.cpp #编译成汇编文件
g++ -c test.o test.s #目标文件 g++ -c test.o test.s #目标文件
g++ -o test test.o #链接 g++ -o test test.o #链接
g++ -O1/-O2/-O3 // 优化选项
#静态库制作: #静态库制作:
g++ -c -o libtest.a {test.cpp 源代码文件清单} g++ -c -o libtest.a {test.cpp 源代码文件清单}
@ -18,7 +20,7 @@ g++ -o test test.o #链接
2 + 路径放到/etc/ld.so.conf 运行ldconfd 重建/etc/ld.so.cache 2 + 路径放到/etc/ld.so.conf 运行ldconfd 重建/etc/ld.so.cache
# 库使用 # 库使用
g++ -o main -l库名 -L库路径 g++ -o main -l库名 -L库路径 -I头文件路径
// g++ -o main -ltest -L/home/e0x1a/test // g++ -o main -ltest -L/home/e0x1a/test
如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查 如果是动态库,需要指定 LD_LIBRARY_PATH 环境变量 //待查

20
tool/program/gdb.txt Normal file
View File

@ -0,0 +1,20 @@
gdb c/c++ 代码调试工具
使用 g++ -g 生成调试文件,不可以加 -O 选项
set [argc] # 传入参数
l n # 列出源码
r # 开始运行到第一个断点
b n # 在第n行打断点
info break # 查看断点
c # 继续运行到下一个断点
s # 单步执行
n # 单步执行,不进入函数
p # 输出变量或表达式的值
set var [] # 修改变量的值
q # 退出
bt # 查看函数调用栈
使用gdb调试core文件
使用ulimit -c unlimited 使挂掉的程序产生core文件
gdb demo -p [pid] # 调试运行中的程序

12
tool/program/makefile Normal file
View File

@ -0,0 +1,12 @@
INCLUDE = -I/home/e0x2d/include
main: file1.o file2.o
g++ -o $@ file1.o file2.o
file1.o: file1.cpp
g++ -c file1.o file1.cpp
file2.o: file2.cpp
g++ -c file2.o file2.cpp ${INCLUDE}
clean:
rm *.o demo

5
tool/program/perf.txt Normal file
View File

@ -0,0 +1,5 @@
#4 perf
性能剖析工具
可分析程序运行期间发生的系统硬件事件
sudo perf record ./a.out
sudo perf report -i perf.data