Linux网络编程常用函数总结
- 文件操作相关函数
- 时间编程相关函数
- 目录操作相关函数
- 多进程初步相关函数
- 信号相关函数
- 管道相关函数
- 进程间通讯(IPC)相关函数
- 多线程编程相关函数
- 多线程的同步和互斥相关函数
- 网络编程
- 多路io复用
- 数据库
文件操作相关函数
一、文件的概念
存储在外部的存储介质上的数据的集合。
Linux中所有内容都是以文件的形式保存和管理,即:一切皆文件。
二、文件的分类
在linux系统之下 文件共分为7类
1. 普通文件: -
使用 ls -l 命令后,第一列第一个字符为 “-” 的文件为普通文件,如上图所示,普通文件一般为灰色字体,绿色字体的是可执行文件,红色字体的是压缩文件。
文件的权限:
以普通文件为例,使用 ls -l 命令,可以看到结果的第一列是 -rwxrwxrwx 的形式,其中第一个字符 “-” 表示这个文件为普通文件,它也可以是其他的字符,不同的字符代表不同类型的文件。其后的一串字符表明了该文件的权限,其中:
1)r 表明该文件具有可读权限,若该位置为 “-” ,则表明文件不可读;
2)w 表明该文件具有写权限,若该位置为 “-” ,则表明文件不可写;
3)x 表明该文件具有可执行权限,若该位置为 “-” ,则表明文件不具有可执行权限;
4)第一个 rwx 表示该文件的所有者对该文件的权限;第二个 rwx 表示该文件所属组对该文件的权限;第三个 rwx 表示其他用户对该文件的权限。
创建一个普通文件:可以使用 touch 命令来创建一个文件:touch newfile
2. 目录文件: d
Linux 中的目录也是文件,目录文件中保存着该目录下其他文件的 inode 号 和文件名等信息,目录文件中的每个数据项都是指向某个文件 inode 号的链接,删除文件名就等于删除与之对应的链接。目录文件的字体颜色是蓝色,使用 ls -l 命令查看,第一个字符为"d"(directory)。
目录文件的权限:
1)r 表明该目录文件具有可读权限,即可以使用 ls 命令查看该目录的存储情况;
2)w 表明该目录文件具有写权限,即可以往该目录下添加、修改、删除文件;
3)x 表明该目录文件具有可执行文件,即可以使用 cd 命令进入到该目录下。
创建一个目录:
可以使用 mkdir 命令来创建一个目录文件:mkdir directory
3. 链接文件: l
链接文件一般指的是一个文件的软连接(或符号链接),使用 ls -l 命令查看,第一个符号为 “l”,文件名为浅蓝色,
可以使用 ln 命令来创建一个文件的链接文件:
软链接
软链接(又称符号链接),使用 ln -s file file_softlink 命令可以创建一个文件的软链接文件:
ln -s test.txt test_softlink
软链接相当于给原文件创建了一个快捷方式,如果删除原文件,则对应的软链接文件也会消失。
硬链接
硬链接,相当于给原文件取了个别名,其实两者是同一个文件,删除二者中任何一个,另一个不会消失;对其中任何一个进行更改,另一个的内容也会随之改变,因为这两个本质上是同一个文件,只是名字不同。使用 ls -i 命令查看,可以发现硬链接的两个文件的 inode 号是一样的。
同样的,使用 ln 命令可以创建一个文件的硬链接:ln test.txt test_hardlink
4. 管道文件: p
管道文件主要用于进程间通信,使用 ls -l 命令查看,第一个字符为 “p”(pipe)。可以使用 mkfifo 命令来创建一个管道文件:mkfifo fifo_file
在 FIFO 中可以很好地解决在无关进程间数据交换的要求,FIFO 的通信方式类似于在进程中使用文件来传输数据,只不过 FIFO 类型的文件同时具有管道的特性,在读取数据时,FIFO 管道中同时清除数据。
5. 字符设备文件: c
字符设备文件以字节流的方式进行访问,由字符设备驱动程序来实现这种特性,这通常要用到 open、close、read、write 等系统调用。字符终端、串口和键盘等就是字符设备。另外,由于字符设备文件是以文件流的方式进行访问的,因此可以顺序读取,但通常不支持随机存取。使用 ls -l 命令查看,字符设备文件的第一个字符是 “c”(char)。
6. 块设备文件: b
块设备文件支持以块(block)为单位的访问方式。在 EXT4 文件系统中,一个 block 通常为 4KB 的大小,也就是说每次可以存取 4096(或其整数倍) 个字节的数据。应用程序可以随机访问块设备文件的数据,程序可以自行确定数据的位置,硬盘、软盘等都是块设备。使用 ls -l 命令查看,块设备文件的第一个字符是 “b”(block)。
7. 套接字文件: s
套接字文件主要用于通信,特别是在网络上。使用 ls -l 命令查看,第一个字符为 "s
三、标准的文件描述符
每个程序在启动的时候,会默认的打开三个文件
0:stdin 标准输入 系统默认分配的是键盘
1:stdout 标准输出 系统默认分配的是显示器
2:stderr 标准错误 系统默认分配的是显示器
如有不懂请参考:文件描述符详解
四、缓冲区文件操作相关函数
什么是缓冲区?
缓冲区,就是一段存储空间。当进程要向外部设备中写数据,并不是直接将数据写入到外部设备,而是会先将待读写的数据写到缓冲区,当缓冲区的数据积累到一定量时,再集中将缓冲区中的数据写到外部设备,这样就可以提高IO效率,进程从外部设备中读数据时,同样也存在一段输入缓冲区。
1.文件的打开(fopen)
函数功能:
缓冲区打开文件
函数头文件:
#include <stdio.h>
函数原型:
函数参数:
const char *pathname: 要打开的文件的名字
const char *mode: 打开的方式
r:只读的方式打开,流指针指向文件头,文件必须存在
r+:读写的方式打开文件,流指针指向文件头,文件必须存在
w:假如文件存在,则清空内容,假如文件不存在则创建,流指针指向文件头
w+:以读写的方式打开文件,文件存在则清空,不存在则创建,流指针指向文件头
a:追加的方式写,文件存在则追加,文件不存在则创建,流指针指向文件尾
a+:读或者以追加的方式写,当接下来的动作为读的时候流指针在文件头,当接下来的动作为写的时候流指针在文件尾
函数返回值:
成功返回: 文件流指针
失败返回: NULL
代码示例
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE* fp=fopen("./a.text","w+");
if(NULL == fp)
{
perror("fopen");
return -1;
}
fputc('A',fp);
fseek(fp, -1, 1);
char b;
b=fgetc(fp);
printf("b=%c\n",b);
return 0;
}
运行结果:
2.文件的关闭(fclose)
函数功能:
关闭文件
函数头文件:
#include <stdio.h>
函数原型:
函数参数:
FILE *stream:要关闭文件的文件流指针
函数返回值:
成功返回 : 0
失败返回 : 非零
代码示例:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE* fp=fopen("./a.text","w+");
if(NULL == fp)
{
perror("fopen");
return -1;
}
fputc('A',fp);
fseek(fp, -1, 1);
char b;
b=fgetc(fp);
printf("b=%c\n",b);
fclose(fp);//关闭文件
return 0;
3.单字符的读取(fgetc,fputc)
函数功能:
fgetc: 从流里读取一个字符
fputc: 向流里写入一个字符
函数头文件:
#include <stdio.h>
函数原型:
函数参数:
fgetc: FILE *stream 文件流指针
fputc: int c 要写入的字符,FILE *stream 文件流指针
函数返回值:
成功:以无符号char强制转换为int的形式返回读取的字符,
失败:如果到达文件末尾或出现读错,则返回EOF
4.字符串的读取(fgets,fputs)
char *fgets(char *s, int size, FILE *stream);
从流里读取一个字符串
s:读取到的串存放的位置
size:要读取的大小
stream:文件流指针
int fputs(const char *s, FILE *stream);
向流里写入一个字符串
s:要写入的内容存放的位置
stream:文件流指针
代码示例:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp=fopen("./t.text","w+");
if(NULL==fp)
{
perror("fopen");
return -1;
}
fputs("hello world",fp);
rewind(fp);//将光标移动到文件首
char buf[64]={0};
fgets(buf,64,fp);
printf("buf=%s\n",buf);
fclose(fp);
return 0;
}
5.块读写(fread,fwrite)
函数功能:
按块读写
函数头文件:
#include <stdio.h>
函数原型:
函数参数:
ptr:读取到/要写入的内容存放的位置
size:要每次读/写的字节数
nmemb:要读/写的次数
stream:流指针
函数返回值:
成功返回: 成功读/写的次数
失败返回 : 0
代码示例:
#include <stdio.h>
int main(int argc, char *argv[])
{
FILE *fp = fopen("./t.text", "w+");
if (NULL == fp)
{
perror("fopen");
return -1;
}
fwrite("hello",6,1, fp);
rewind(fp); //将光标移动到文件首
char buf[64] = {0};
fread(buf,6,1,fp);
printf("buf=%s\n", buf);
fclose(fp);
return 0;
}
5.格式化读写(fscanf,fprintf)
int fscanf(FILE *stream, const char *format, …);
从流里格式化的获取内容
int fprintf(FILE *stream, const char *format, …);
向流里格式化的输入内容
int sprintf(char *str, const char *format, …);
向str里格式化的输入内容
代码示例:
6.文件指针定位(rewind,fseek,ftell,feof)
函数的功能:
将文件流指针偏移到开头的位置
函数的头文件:
#include<stdio.h>
函数的原型:
函数的参数:
FILE *stream:文件流指针
函数的返回值:
无
函数的功能:
将流指针偏移到指定的位置
函数的头文件:
#include<stdio.h>
函数的原型:
函数的参数:
FILE *stream: 流指针
long offset: 偏移量
int whence: 参考位置
SEEK_SET 文件头
SEEK_CUR 当前位置
SEEK_END 文件尾
函数的返回值:
成功返回 0
失败返回 -1
函数的功能:
获取文件流指针距离文件开头的偏移量
函数的头文件:
#include<stdio.h>
函数的原型:
函数的参数;
FILE *stream:流
函数的返回值:
成功返回: 流指针距离文件头的偏移量
失败返回: -1
函数的功能:
判断文件流指针是否在文件尾部
函数的头文件:
#include<stdio.h>
函数的原型:
函数的参数:
FILE *stream:文件流指针
函数的返回值:
假如到文件尾则返回 : 非零
未到文件文件尾部则返回: 零
五、非缓冲区文件操作相关函数
1.文件的打开(open)
函数的功能:
打开文件
函数的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
函数的原型:
函数的参数:
const char *pathname:要打开文件的名字
int flags: 打开的方式
O_RDONLY 只读
O_WRONLY 只写
O_RDWR 读写
O_CREAT 假如文件不存在则创建
O_TRUNC 假如文件存在则清空
mode_t mode 权限 八进制的数 0664
函数的返回值:
成功返回: 文件描述符
失败返回: -1
当已确认文件是存在的时候,就可以用两个参数的open
假如文件不存在 必须要用三个参数的open
2.文件的关闭(close)
函数的功能:
关闭文件
函数的头文件:
#include<unistd.h>
函数的原型:
函数的参数:
int fd:文件描述符
函数的返回值:
成功返回 0
失败返回 -1
3.文件的读(read)
函数的功能:
从文件里读内容
函数的头文件:
#include<unistd.h>
函数的原型:
函数的参数:
int fd: 文件描述符
void *buf: 读到的内容存放的位置
size_t count: 要读取的长度
函数的返回值:
成功返回: 成功读取的字节数
失败返回: -1
4.文件的写(write)
函数的功能:
向文件里写入内容
函数的头文件:
#include<unistd.h>
函数的原型:
函数的参数:
int fd: 文件描述符
const void *buf:要写入的内容存放位置
size_t count: 要写入的长度
函数的返回值:
成功返回 成功写入的字节数
失败返回 -1
5.文件指针定位(lseek)
函数的功能:
将文件的读写指针偏移到指定的位置
函数的头文件:
#include <sys/types.h>
#include <unistd.h>
函数的原型:
函数的参数:
int fd: 文件描述符
off_t offset: 偏移量
int whence:参考位置
SEEK_SET(0) 文件头
SEEK_CUR(1) 当前位置
SEEK_END(2) 文件尾
函数的返回值:
成功返回: 当前读写指针距离文件头的偏移量
失败返回: -1
代码示例:使用函数实现CP功能
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int in, out, count;
char buf[1024] = {0};
int main(int argc, char *argv[])
{
if (argc != 3)
{
printf("请输入正确的参数\n");
return -1;
}
in = open(argv[1], O_RDONLY);
if (in < 0)
{
printf("源文件打开失败\n");
return -1;
}
out = open(argv[2], O_WRONLY | O_CREAT, 0644);
if (out < 0)
{
perror("open");
return -1;
}
while ((count = read(in, buf, 1024)) > 0)
{
if (write(out, buf, count) < 0)
{
perror("write");
return -1;
}
}
close(in);
close(out);
return 0;
}
时间编程相关函数
一、时间的表示方法
世界标准时间:
UTC 格林威治时间 0时区时间
日历时间:
从1970年1月1日0时0分0秒到现在所经历的秒数
本地时间:
对我们来说一般指的是北京时间
二、时间相关的shell指令
date: 查看本地时间
date -u: 查看格林威治时间
cal: 看日历
cal 月 年:查看指定的某一年的某一月的日历
三、时间获取函数
1.获取日历时间(time)
函数的功能:
获取日历时间
函数的头文件:
#include <time.h>
函数的原型:
函数的参数:
time_t *tloc:用来存放获取到的日历时间
函数的返回值:
成功返回: 日历时间
失败返回: -1
代码示例:
2.将日历时间转换为本地时间(localtime)
函数的功能:
将日历时间转换成本地时间
函数的头文件:
#include <time.h>
函数的原型:
函数的参数:
const time_t *timep:日历时间
函数的返回值:
成功返回: 本地时间的结构体指针
失败返回 : NULL
本地时间的结构体:
代码示例:
3.将日历时间转换为格林威治时间(gmtime)
函数的功能:
将日历时间转换成格林威治时间
函数的头文件:
#include<time.h>
函数的原型:
函数的参数:
const time_t *timep :日历时间
函数的返回值:
成功返回 格林威治时间的结构体
失败返回 NULL
代码示例:
4.将日历时间转换为本地时间的字符串(ctime)
函数的功能:
将日历时间转换成本地时间的字符串
函数的头文件:
#include<time.h>
函数的原型:
函数的参数:
const time_t *timep:日历时间
函数的返回值:
成功返回:本地时间的字符串
失败返回: NULL
代码示例:
目录操作相关函数
一、文件属性获取相关函数
1.获取文件属性(stat)
函数的功能:
获取文件的属性
函数的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数的原型:
函数的参数:
const char *pathname:文件名
struct stat *statbuf:用来存放文件属性的结构体
函数的返回值:
成功返回: 0
失败返回: -1
文件属性的结构体:
struct stat {
dev_t st_dev; 假如是设备文件 则表示设备号
ino_t st_ino; 节点号
mode_t st_mode; 文件的类型和权限
nlink_t st_nlink; 硬链接数
uid_t st_uid; 所有者id
gid_t st_gid; 组id
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; 文件大小 字节
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
struct timespec st_atim; 最后一次访问时间
struct timespec st_mtim; 最后一次修改时间
struct timespec st_ctim; 最后一次状态改变事件
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
mode_t st_mode; 文件的类型和权限
代码示例:
2.获取文件属性(fstat)
函数的功能:
获取文件的属性
函数的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数的原型:
函数的参数:
int fd: 文件描述符
struct stat *statbuf: 获取到的文件的属性存放的结构体
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
3.获取文件属性(lstat)
函数的功能:
获取文件的属性
函数的头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
函数的原型: 函数的参数:
const char *pathname: 文件名
struct stat *statbuf: 获取到的文件的属性存放的位置
函数的返回值:
成功返回: 0
失败返回: -1
4.三种获取文件属性的接口的区别
1) lstat、stat、fstat都是获取文件的属性的
2) fstat需要打开文件才能获取文件的属性
lstat、stat不需要打开文件即可获取文件的属性
3) 当获取属性的对象为链接文件的时候
lstat获取的是链接文件的本身的文件的属性
stat获取的是链接文件指向的文件的属性
5.权限的审查(access)
函数的功能:
审查文件的权限
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
const char *pathname: 文件的名字
int mode:要审查的权限
R_OK 可读
W_OK 可写
X_OK 可执行
F_OK 文件是否存在
要审查多个权限则用 |
R_OK|W_OK 审查有没有读写权限
函数的返回值:
当审查的权限全部都满足的时候 返回: 0
当审查的权限里任意一种权限不满足的时候 返回: -1
代码示例:
二、目录操作相关函数
1.打开目录(opendir)
函数的功能:
打开一个目录
函数的头文件:
#include <sys/types.h>
#include <dirent.h>
函数的原型:
函数的参数:
const char *name:要打开的目录的名字
函数的返回值:
成功返回: 目录流指针
失败返回: NULL
代码示例:
2.关闭目录(closedir)
函数的功能:
关闭目录
函数的头文件:
#include <sys/types.h>
#include <dirent.h>
函数的原型:
函数的参数:
DIR *dirp:目录流指针
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
3.读取目录(readdir)
函数的功能:
读取目录流
函数的头文件:
#include <dirent.h>
函数的原型:
函数的参数:
DIR *dirp:目录流指针
函数的返回值:
成功返回: 读取到的文件的属性的结构体
失败返回 : NULL
文件属性的结构体:
struct dirent {
ino_t d_ino; 节点号
off_t d_off; 偏移量
unsigned short d_reclen; 文件名字的长度
unsigned char d_type;
char d_name[256]; 文件名
};
代码示例:
4.目录读写指针偏移(rewinddir)
函数的功能:
将目录流的读写指针偏移到头的位置
函数的头文件:
#include <sys/types.h>
#include <dirent.h>
函数的原型:
函数的参数:
DIR *dirp:目录流指针
函数的返回值:
无
5.获取目录读写指针偏移量(telldir)
函数的功能:
获取偏移量
函数的头文件:
#include <sys/types.h>
#include <dirent.h>
函数的原型:
函数的参数:
DIR *dirp:目录流
函数的返回值:
成功返回: 偏移量
失败返回 : -1
6. 重新定位目录流读写指针(seekdir)
函数的功能:
将目录流指针偏移到指定的位置
函数的头文件:
#include <dirent.h>
函数的原型:
函数的参数:
DIR *dirp: 目录流
long loc: 偏移量
函数的返回值:
无
7. 创建目录(mkdir)
函数的功能:
创建一个空目录
函数的头文件:
#include <sys/stat.h>
#include <sys/types.h>
函数的原型:
函数的参数:
const char *pathname: 目录名
mode_t mode: 权限
函数的返回值:
成功返回: 0
失败返回: -1
8. 删除目录(rmdir)
函数的功能:
删除一个空目录
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
const char *pathname:要删除的目录的名字
函数的返回值:
成功返回: 0
失败返回: -1
9. 获取当前目录(getcwd)
函数的功能:
获取当前所在的目录
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
char *buf: 用来存放获取的当前的目录的缓冲区
size_t size: 字符串的大小 最大是255
函数的返回值:
成功返回: 目录的字符串
失败返回: NULL
10. 更改文件权限(chmod)
函数的功能:
修改文件的权限
函数的头文件:
#include <sys/stat.h>
函数的原型:
函数的参数:
const char *pathname:文件名
mode_t mode:要修改成的权限
函数的返回值:
成功返回: 0
失败返回: -1
11.切换目录(chdir)
函数的功能:
切换目录(程序的执行的路径)
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
const char *path:要切换到的目录
函数的返回值:
成功返回: 0
失败返回: -1
多进程初步相关函数
一、进程的定义
进程是一个运行着的程序,它包含了程序在运行时的各个资源,进程是操作系统进行调度的基本单位,也是一个程序运行的基本单位。进程是一个程序一次执行的过程,是操作系统动态执行的基本单元。进程的概念主要
有两点:第一,进程是一个实体。每个进程都有自己的虚拟地址空间,这些地址空间包括代码区、数据区、和堆栈区。文本区域存储处理器执行的代码;数据区存储变量和动态分配的内存;堆栈区存储活动进程动态申请的内存和局部变量及函数调用时的返回值。第二,进程是一个“执行中的程序”,它和程序有本质区别。程序是静态的,它是一些保存在磁盘上的指令的有序集合(文件);而进程是一个动态的概念,它是一个运行着的程序,包含了进程的动态创建、调度和消亡的过程,是 Linux 的基本调度单位。只有当处理器赋予程序生命时,它才能成为一个活动的实体,称之为进程, 只是程序在内存,并能够得到执行的时候。
二、进程的状态
进程是程序的执行过程,根据它的生命周期可以划分成 3 种状态。
执行态: 该进程正在运行,即进程正在占用 CPU, 任何时候都只有一个进程。
就绪态: 进程已经具备执行的一切条件,正在等待分配 CPU 的处理时间片。
等待态: 进程正在等待某些事件,当前不能分配时间片, 进程不能使用 CPU,若等待事件发生(等待的资源分配到)则可将其唤醒,变成就绪态。
三、进程的特点
1.动态性: 进程的实质是进程实体的一次执行过程,因此,动态性是进程最基本的特征。
2.并发性: 指多个进程实体同存于内存中,且在一段时间内同时运行。并发性是进程的重要特征,同时也成为操作系统的重要特征。
3.异步性: 指进程按各自独立的、不可预知的速度向前推进,或者说实体按异步方式运行
4.独立性: 进程实体是一个独立运行、独立分配资源和独立接受调度的基本单位。
四、进程相关的函数
1.进程号的获取(getpid,getppid)
函数的功能:
获取自己/父进程的id
函数的头文件:
#include <sys/types.h>
#include <unistd.h>
函数的原型:
函数的参数:
无
函数的返回值:
返回值: 进程的id /父进程的id
代码示例:
2.创建进程(fork)
函数的功能:
创建进程
函数的头文件:
#include <sys/types.h>
#include <unistd.h>
函数的原型:
![]()
函数的参数:
无
函数的返回值:
失败返回: -1
在父进程里返回: 子进程的id号
在子进程里返回 : 0
注意:
当调用fork函数来创建子进程的时候,子进程会拷贝父进程的资源,
子进程会从fork函数往下执行,父进程和子进程的资源是相互独立的。
子进程和父进程的执行的先后顺序是不确定的,由CPU调度算法决定。
代码示例:
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wait.h>
#include <stdlib.h>
pid_t z;
pid_t f;
int main(int argc, char *argv[])
{
f=getppid();
z=getpid();
printf("当前进程号:%d\n",z);
printf("当前终端进程号:%d\n",f);
pid_t t=fork();
if(t==0)
{
printf("我是子进程\n");
printf("getppid:%d\n",getppid());
printf("getpid:%d\n",getpid());
}
if(t>0)
{
waitpid(t,NULL,WNOHANG);
printf("我是父进程\n");
printf("getppid:%d\n",getppid());
printf("getpid:%d\n",getpid());
}
return 0;
}
3.创建进程(vfork)
函数的功能:
创建进程
函数的头文件:
#include <sys/types.h>
#include <unistd.h>
函数的原型:
函数的参数:
无
函数的返回值:
失败返回 -1
在子进程返回 0.
在父进程返回 子进程的id
注意:
当调用vfork创建进程的时候,子进程会优先执行,子进程会共用父进程
的资源,子进程结束的时候必须要调用exit函数。
代码示例:
4.进程等待函数(wait,waitpid)
函数的功能:
等待子进程的退出 并且做清理动作
函数的头文件:
#include <sys/types.h>
#include <sys/wait.h>
函数的原型:
函数的参数:
int *wstatus:进程退出的状态
一般填NULL : 表示等待所有的状态的退出
函数的返回值:
成功返回: 等待的子进程的id
失败返回: -1
函数的功能:
等待子进程的退出 并且做清理动作
函数的头文件:
#include <sys/types.h>
#include <sys/wait.h>
函数的原型:
函数的参数:
pid_t pid, >0 表示等待指定的子进程的退出
-1 等待任意的子进程的退出
int *wstatus, 等待进程的退出的状态 NULL
int options 0 阻塞 WNOHANG 不阻塞
函数的返回值:
成功返回 等待的子进程的id
失败返回 -1
代码示例:
5.进程退出相关函数(exit,_exit)
函数的功能:
退出函数的执行
函数的头文件:
#include <stdlib.h>
函数的原型:
函数的参数:
int status:退出的状态 一般写0表示正常退出
函数的返回值:
无
函数的功能:
退出进程的执行
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
int status:进程的退出状态 一般写0
函数的返回值:
无
区别与共同点:
共同点:
都是终止进程
不同点:
exit会刷新所有的缓冲区
_exit不会刷新缓冲区
代码示例:
6.钩子函数(atexit)
函数的功能:
在退出进程的时候 做其他的动作
函数的头文件:
#include <stdlib.h>
函数的原型:
函数的参数:
void (*function)(void):退出清理函数的回调函数
函数的返回值:
成功返回: 0
失败返回: 非零
代码示例:
7.execl函数族(execl,execlp)
函数的功能:
当某个进程认为自己无法为系统做出贡献的时候,就可以调用execl对
进程进行重生
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
pathname:可执行程序的名字 要加上路径
file:可执行程序的名字 不用加上路径
const char *arg:后边跟的参数
参数必须以NULL结尾
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
8.可执行程序执行函数(system)
函数的功能:
执行可执行程序
函数的头文件:
#include <stdlib.h>
函数的原型:
函数的参数:
const char *command:要执行的命令
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
信号相关函数
1.进程向进程发送信号(kill)
函数的功能:
一个进程向另外一个进程发送一个信号
函数的头文件:
#include <sys/types.h>
#include <signal.h>
函数的原型:
函数的参数:
pid_t pid, :进程号
int sig:要发送的信号
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
2.进程向自己发送信号(raise)
函数的功能:
向自己发送一个信号
函数的头文件:
#include <signal.h>
函数的原型:
函数的参数:
int sig:要发送的信号
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
3.时钟信号函数(alarm)
函数的功能:
当时钟到了之后给自己发送一个时钟信号
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
unsigned int seconds:倒计时的秒数
函数的返回值:
成功返回: 0
假如上方还有时钟,并且上方的时钟时间还未到
则返回 上个时钟剩余的时间
代码示例:
4.暂停进程函数(pause)
函数的功能:
暂停进程
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
无
函数返回值:
成功返回:-1
失败返回:error
5.设置信号处理方式函数(signal)
函数的功能:
设置信号的处理方式
函数的头文件:
#include <signal.h>
函数的原型:
函数的参数:
int signum: 信号
sighandler_t handler: 处理信号的方式
SIG_DFL:默认处理方式
SIG_IGN:忽略信号
typedef void (*sighandler_t)(int);
收到这个信号之后 调用回调函数
函数的返回值:
成功返回: 回调函数的函数指针
失败返回: NULL
代码示例:
管道相关函数
一、管道相关概念
1.管道的特点
单向导通
管道里得数据读取完成之后,数据就不存在了
是一种特殊得文件类型
有固定的读端和写端
2.管道的分类
有名管道
无名管道
3.无名管道的特点
无名管道不会产生真实的管道文件
只能用于具有亲缘关系的两个进程间的通讯
使用无名管道时的注意事项:
1)创建无名管道要在创建进程之前
2)读取管道的内容的时候,假如管道里没有内容,则阻塞
3)在写管道的时候,当管道满了之后,则阻塞
4)在父子进程通讯的时候最好把不用的那一端关掉
4.有名管道的特点
会产生一个真实的管道文件
可以用在任意的两个进程间进行通讯
有名管道和普通文件的区别:
1)管道里的内容读取完成之后内容就不存在了,普通文件里的内容还存在
2)要读管道必须以只读的方式打开管道文件
3)要写管道必须以只写的方式打开管道
二、管道相关函数
1.无名管道的创建(pipe)
函数的功能:
创建无名管道
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
2.有名管道的创建(mkfifo)
函数的功能:
创建一个有名管道
函数的头文件:
#include <sys/types.h>
#include <sys/stat.h>
函数的原型:
函数的参数:
const char *pathname: 文件名
mode_t mode:权限
函数的返回值:
成功返回: 0
失败返回: -1
代码示例:
3.文件的删除(unlink)
函数的功能:
删除一个文件
函数的头文件:
#include <unistd.h>
函数的原型:
函数的参数:
const char *pathname:要删除的文件名
函数的返回值:
成功返回: 0
失败返回: -1
进程间通讯(IPC)相关函数
一、进程间通讯(IPC)基础
1.IPC介绍
进程间通信(IPC,InterProcess Communication)是指在不同进程之间传播或交换信息。
IPC的方式通常有管道(包括无名管道和命名管道)、消息队列、信号量、共享存储、Socket、Streams等。其中 Socket和Streams支持不同主机上的两个进程IPC。
以Linux中的C语言编程为例。
2.用于多个进程间进行通讯的手段
共享内存
信号量
消息队列
3.IPC通讯的唯一性
在操作系统里可能同时存在多个IPC
要想保证我们多个进程进行通讯的时候访问的是同一个IPC
就需要有一个能够唯一识别IPC的东西
这个东西就叫做键值
二、键值的创建函数(ftok)
参考ftok()函数深度解析
函数的功能:
创建键值
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
函数的原型:
函数的参数:
const char *pathname:参考的文件路径 一般写绝对路径
int proj_i: 参考id: 0-255
函数的返回值:
成功返回: 键值
失败返回: -1
三、共享内存
1.共享内存的相关概念
查看系统里的共享内存的信息:ipcs -m
共享内存可以理解成是一个加强版的全局变量
他是存在于操作系统的内存空间的
怎样理解加强:
生命周期:只要不删除共享内存,共享内存就一直存在
作用域:共享内存的作用域 是整个操作系统
全局变量的作用域是整个工程
2.进程启动的时候要做的事情
1)每个进程在启动的时候会默认的打开三个标准的文件描述符
标准输入 0
标准输出 1
标准错误 2
2)每个进程在启动的时候系统都会给进程虚拟出来一块4G大小的内存空间
用户空间 内核空间
3.共享内存的创建函数(shmget)
函数的功能:
创建共享内存
函数的头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
函数的原型:
函数的参数:
key_t key: 键值
size_t size: 大小
int shmflg: IPC_CREAT|0664
函数的返回值:
成功返回: 共享内存的id
失败返回: -1
4.共享内存的映射(shmat)
函数的功能:
映射共享内存
函数的头文件:
#include <sys/types.h>
#include <sys/shm.h>
函数的原型:
函数的参数:
int shmid: 共享内存的id
const void *shmaddr: 要映射的位置 一般写NULL由系统分配
int shmflg: 写 0 表示可读可写
函数的返回值:
成功返回: 映射后的空间的地址
失败返回: NULL
5.解除共享内存的映射(shmdt)
函数的功能:
解除共享内存的映射
函数的头文件:
#include <sys/types.h>
#include <sys/shm.h>
函数的原型:
函数的参数:
const void *shmaddr:映射后的地址空间
函数的返回值:
成功返回: 0
失败返回: -1
6.删除共享内存(shmctl)
函数的功能:
删除共享内存
函数的头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
函数的原型:
函数的参数:
int shmid: 共享内存的id
int cmd: 要执行的指令:IPC_RMID
struct shmid_ds *buf:NULL
函数的返回值:
成功返回 0
失败返回 -1
7.代码示例
四、信号量
1.信号量相关基础知识
信号量本质是一个计数器(不设置全局变量是因为进程间是相互独立的,而这不一定能看到,看到也不能保证++引用计数为原子操作),用于多进程对共享数据对象的读取,它和管道有所不同,它不以传送数据为主要目的,它主要是用来保护共享资源(信号量也属于临界资源),使得资源在一个时刻只有一个进程独享。
信号量本质上就是一个数字
这个数字表示的就是临界资源信息
信号量就是用来保护临界资源的
这个数字可以进行加 也可以进行减
加的时候就表示有进程释放资源
减的时候就表示有进程正在消耗资源
当这个数字减到0的时候
表示资源被消耗完毕,没有资源可以被消耗
进程就会阻塞
查看信号量的命令
ipcs -s
2.信号量的创建或打开(semget)
函数的功能:
创建或者是打开信号量
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数的原型:
函数的参数:
key_t key: 键值
int nsems: 信号量的数量 一般写1
int semflg IPC_CREAT|0664
函数的返回值:
成功返回: 信号量的id
失败返回: -1
3.设置信号量的值或删除信号量(semctl)
函数的功能:
设置/删除信号量
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数的原型:
函数的参数:
int semid: 信号量的id
int semnum: 数组的下标 一般写0
int cmd: 要执行的命令
IPC_RMID 删除信号量
SETVAL :设置信号量的值
…
函数的返回值:
成功返回 0
失败返回 -1
4.信号量的消耗或释放(semop)
函数的功能:
消耗/释放信号量
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
函数的原型:
函数的参数:
int semid:信号量的id
struct sembuf *sops: 信号量的操作结构体
size_t nsops: 要操作信号量的个数 一般写1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
struct sembuf
{
unsigned short sem_num: 数组的下标 0
short sem_op: 要进行的操作
+1 释放资源
-1 消耗资源
short sem_flg: 0 申请不到资源则阻塞
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
函数的返回值:
成功返回: 0
失败返回: -1
5.代码示例
五、消息队列
1.消息队列相关基础知识
用来存放消息的队列
先进先出
消息队列里的消息是可以进行分类的
要想使用消息队列进行通讯,必须要保证消息的类别一致
查看消息队列相关的指令:ipcs -q
2.创建消息队列(msgget)
函数的功能:
创建消息队列
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数的原型:
函数的参数:
key_t key: 键值
int msgflg: 权限 IPC_CREAT|0664
函数的返回值:
成功返回: 消息队列的id
失败返回: -1
3.向消息队列发送信息(msgsnd)
函数的功能:
向消息队列里发送一条消息
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数的原型:
函数的参数:
int msqid: 消息队列的id
const void *msgp: 消息的结构体
size_t msgsz: 要发送消息的大小 不包含消息的类型
int msgflg: 0 阻塞的发
函数的返回值:
成功返回: 0
失败返回: -1
4.从消息队列读取信息(msgrcv)
函数的功能:
从消息队列读取一条消息
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数的原型:
函数的参数:
int msqid: 消息队列的id
void *msgp: 接收消息的结构体指针
size_t msgsz: 消息的大小
long msgtyp: 消息的类型
int msgflg: 0 阻塞的读 读取不到则阻塞
函数的返回值:
成功返回: 0
失败返回: -1
5.消息队列的删除(msgctl)
函数的功能:
删除消息队列
函数的头文件:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
函数的原型:
函数的参数:
int msqid: 消息队列的id
int cmd: IPC_RMID
struct msqid_ds *buf :NULL
函数的返回值:
成功返回: 0
失败返回: -1
6.代码示例
多线程编程相关函数
一、线程基础概念
1.线程的定义
线程(Thread):轻量级进程,是操作系统进行调度的最小单位。一个线程是一个任务(一个程序段)的一次执行过程。线程不占有内存空间,它包括在进程的内存空间中。在同一个进程内,多个线程共享进程的资源。一个进程至少有一个线程。
2.线程和进程的区别
进程与线程的区别总结:
本质区别: 进程是操作系统资源分配的基本单位,而线程是处理器任务调度和执行的基本单位。
包含关系: 一个进程至少有一个线程,线程是进程的一部分,所以线程也被称为轻权进程或者轻量级进程。
资源开销: 每个进程都有独立的地址空间,进程之间的切换会有较大的开销;线程可以看做轻量级的进程,同一个进程内的线程共享进程的地址空间,每个线程都有自己独立的运行栈和程序计数器,线程之间切换的开销小。
影响关系: 一个进程崩溃后,在保护模式下其他进程不会被影响,但是一个线程崩溃可能导致整个进程被操作系统杀掉,所以多进程要比多线程健壮。
3.线程的特点
a.一个线程是一个任务(一个程序段)的一次执行过程。
b.线程不占有内存空间,它包括在进程的内存空间中。
c.线程比进程开销小,更加轻量。
d.在同一进程内,多个线程可以并发执行。
e.在同一进程内,多个线程共享进程的资源。
4.线程和进程如何选择
1) 需要频繁的创建和销毁的优先使用线程
2) 涉及大量的数据运算的时候优先使用线程
3) 强相关用线程 弱相关 用进程
4) 假如哪个都可以 优先选择自己熟悉的
二、线程相关函数
1.线程的创建(pthread_create)
函数的功能:
创建一个线程
函数的头文件:
#include <pthread.h>
函数的原型:
函数的参数:
pthread_t *thread: 用来存放线程的id
const pthread_attr_t *attr: 线程的属性 NULL
void *(*start_routine) (void *): 线程的回调函数
void *arg: 传给回调函数的参数
函数的返回值:
成功返回: 0
失败返回: -1
2.获取自己的线程号(pthread_self)
函数的功能:
获取线程号
函数的头文件:
#include <pthread.h>
函数的原型:
pthread_t pthread_self(void);
函数的参数:
无
函数的返回值:
成功返回: 线程的id
失败返回: -1
3.退出一个线程(pthread_exit)
函数的功能:
退出线程的执行
函数的头文件:
#include <pthread.h>
函数的原型:
void pthread_exit(void *retval);
函数的参数:
void *retval:退出的状态 一般写NULL
函数的返回值:
无
4.等待一个线程的退出(pthread_join)类似wait和waitpid函数
函数的功能:
等待线程的退出
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_join(pthread_t thread, void **retval);
函数的参数:
pthread_t thread: 等待的线程号
void **retval: 退出的状态 一般填NULL
函数的返回值:
成功返回: 0
失败返回: 错误码
5.一个线程取消另一个线程(pthread_cancel)
函数的功能:
一个线程取消另外一个线程
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_cancel(pthread_t thread);
函数的参数:
pthread_t thread:要取消的线程号
函数的返回值:
成功返回: 0
失败返回: 非零
6.退出线程清理函数
函数的功能:
退出清理
函数的头文件:
#include <pthread.h>
函数的原型:
void pthread_cleanup_push(void (*routine)(void *),void *arg);
void pthread_cleanup_pop(int execute);
函数的参数:
void (*routine)(void *): 回调函数
void *arg: 传给回调函数参数
int execute : 0 表示退出函数不执行
1 表示退出函数执行
函数的返回值:
无
==========================================================
注意:
1) pop和push要配对使用
2) pop和push中间尽量不要有大括号
3) 当push和pop中间有退出的动作的时候
无论pop的参数是0还是1 退出清理动作都会执行
7.代码示例
多线程的同步和互斥相关函数
一、线程的同步和互斥的相关基础知识
Linux线程的同步和互斥详解
多线程的同步与互斥的作用:保护资源
线程间同步与互斥的手段:
互斥锁
条件变量
信号灯
二、互斥锁相关函数
1.互斥锁基本概念
互斥锁是虚拟出来的一种锁
他的本质就是一个结构体
锁的操作:
开锁
上锁
互斥锁的使用流程:
初始化锁
加锁
解锁
消耗锁
2.初始化互斥锁(pthread_mutex_init)
静态初始化:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
动态初始化:
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_mutex_init( pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
函数的参数:
pthread_mutex_t *restrict mutex: 互斥锁的核心结构体指针
const pthread_mutexattr_t *restrict attr: 锁的类型
NULL 快速互斥锁
函数的返回值:
成功返回: 0
失败返回: 错误码
3.互斥锁加锁(pthread_mutex_lock)
函数的功能:
互斥锁加锁
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_mutex_lock(pthread_mutex_t *mutex);
阻塞的申请一个互斥锁,如果能申请到则马上返回,
如果申请不到,则阻塞
int pthread_mutex_trylock(pthread_mutex_t *mutex);
非阻塞的申请一个互斥锁,无论能不能申请到
都马上返回
函数的参数:
pthread_mutex_t *mutex:互斥锁的核心结构体指针
函数的返回值:
成功返回: 0
失败返回: 错误码
4.互斥锁的解锁(pthread_mutex_unlock)
函数的功能:
互斥锁的解锁
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_mutex_unlock(pthread_mutex_t *mutex);
函数的参数:
pthread_mutex_t *mutex:互斥锁的核心结构体
函数的返回值:
成功返回: 0
失败返回: 错误码
5.互斥锁的销毁(pthread_mutex_destroy)
函数的功能:
销毁一个互斥锁
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_mutex_destroy(pthread_mutex_t *mutex);
函数的参数:
pthread_mutex_t *mutex:锁的核心结构体
函数的返回值:
成功返回: 0
失败返回: 错误码
互斥锁使用注意事项:
1) 锁使用完成之后要及时的释放锁
2) 锁要约束所有的要使用资源的线程
6.代码示例
三、条件变量相关函数
1.条件变量的创建(pthread_cond_init)
静态创建:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
动态创建:
函数的功能:
创建一个条件变量
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
函数的参数:
pthread_cond_t *restrict cond: 条件变量的核心结构体
const pthread_condattr_t *restrict attr: 类型
NULL
函数的返回值:
成功返回: 0
失败返回: 非零
2.堵塞线程(pthread_cond_wait)
函数的功能:
阻塞线程
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
函数的参数:
pthread_cond_t *restrict cond: 条件变量的结构体
pthread_mutex_t *restrict mutex: 互斥锁的结构体
函数的返回值:
成功返回: 0
失败返回: 非零
3.解除线程堵塞(pthrad_cond_signal)
函数的功能:
解除线程的阻塞
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_cond_signal(pthread_cond_t *cond);
函数的参数:
pthread_cond_t *cond:条件变量的核心结构体
函数的返回值:
成功返回: 0
失败返回: 非零
4.销毁条件变量(pthread_cond_destroy)
函数的功能:
销毁条件变量
函数的头文件:
#include <pthread.h>
函数的原型:
int pthread_cond_destroy(pthread_cond_t *cond);
函数的参数:
pthread_cond_t *cond:条件变量的核心结构体
函数的返回值:
成功返回: 0
失败返回: 非零
5.代码示例
四、信号灯相关函数
1.信号灯基础概念
信号灯与其他进程间通信方式不大相同,它主要提供对进程间共享资源访问控制机制。相当于内存中的标志,进程可以根据它判定是否能够访问某些共享资源,同时,进程也可以修改该标志。除了用于访问控制外,还可用于进程同步。信号灯有以下两种类型:
二值信号灯:最简单的信号灯形式,信号灯的值只能取0或1,类似于互斥锁。
注:二值信号灯能够实现互斥锁的功能,但两者的关注内容不同。信号灯强调共享资源,只要共享资源可用,其他进程同样可以修改信号灯的值;互斥锁更强调进程,占用资源的进程使用完资源后,必须由进程本身来解锁。
计算信号灯:信号灯的值可以取任意非负值(当然受内核本身的约束)
信号灯就类似于进程里的信号量
信号灯的本质也是一个数字
也可以进行加或者减
加的时候 释放资源
减的时候消耗资源
减到0的时候表示没有资源可用
2.初始化一个信号灯(sem_init)
函数的功能:
初始化一个信号灯
函数的头文件:
#include <semaphore.h>
函数的原型:
int sem_init(sem_t *sem, int pshared, unsigned int value);
函数的参数:
sem_t *sem: 信号灯的结构体
int pshared: 0
unsigned int value: 信号灯的值
函数的返回值:
成功返回: 0
失败返回: -1
3.消耗一个信号灯(sem_wait)
函数的功能:
消耗一个信号灯
函数的头文件:
#include <semaphore.h>
函数的原型:
int sem_wait(sem_t *sem);阻塞的申请一个信号灯,假如能够申请到则马上返回,如果申请不到则阻塞
int sem_trywait(sem_t *sem);非阻塞的申请一个信号灯,无论能否申请成功都返回
函数的参数:
sem_t *sem:信号灯的核心结构体
函数的返回值:
成功返回 0
失败返回 -1
4.释放一个信号灯(sem_post)
函数的功能:
释放一个信号灯
函数的头文件:
#include <semaphore.h>
函数的原型:
int sem_post(sem_t *sem);
函数的参数:
sem_t *sem:信号灯的结构体
函数的返回值:
成功返回: 0
失败返回: -1
5.销毁一个信号灯(sem_destory)
函数的功能:
销毁信号灯
函数的头文件:
#include <semaphore.h>
函数的原型:
int sem_destroy(sem_t *sem);
函数的参数:
sem_t *sem:信号灯的核心结构体
函数的返回值:
成功返回: 0
失败返回: -1
6.代码示例:
五、线程间的通讯
1.全局变量
2.pthread_kill函数
函数的功能:
一个线程跟另外一个线程发送一个信号
函数的头文件:
#include <signal.h>
函数的原型:
int pthread_kill(pthread_t thread, int sig);
函数的参数:
pthread_t thread: 线程号
int sig:信号
函数的返回值:
成功返回: 0
失败返回: 非零
代码示例:
网络编程
一、网络相关基础知识
1.局域网和广域网的概念
1.局域网:小型的网络,一般指的是一个路由器下的所有的设备组成的网络
局域网(Local Area Network,LAN),又称为局部区域网,是目前网络技术发展最快的领域之一。一般用微型计算机通过高速通信线路相连,覆盖范围为几百米到几千米,通常用于连接一个实验室、一幢或几幢大楼。局域网的规模相对于城域网和广域网而言较小。在局域网内数据传输速率较高,目前局域网最快速率可达到10Gbit/s;传输可靠性好,误码率低(在10-7~10-12之间);网络结构简单,配置灵活,容易实现。
2.城域网:所覆盖的地域范围介于局域网和广域网之间
城域网(Metropolitan Area Network,MAN)所覆盖的地域范围介于局域网和广域网之间,一般从几十千米到几百千米的范围。城域网通常是使用高速的光纤网络,在一个特定的范围内(例如校园、社区或城市)将不同的局域网连接起来,构成一个覆盖该区域的网络,其传输速率比局域网高。
3.广域网:将一个个的小型的局域网连接在一起组成的一个大型的网络
广域网(Wide Area Network,WAN)又称为远程网。广域网的作用范围通常为几十千米到几千千米,覆盖一个地区、国家甚至横跨全球,形成国际性的网络。广域网的通信子网主要使用分组交换技术,它可以使用公用分组交换网、卫星通信网和无线分组网,可以适应大容量、突发性的通信需求。广域网常常借用传统的公共传输网(如电话网)进行通信,可以实现较大范围内的资源共享,但同时广域网的数据传输率比局域网系统慢,传输错误率也较高。随着新的光纤标准和能够提供更宽和更快传输率的全球光纤通信网络的引入,广域网的数据传输率也将大大提高。
2.链接一个服务器的流程
在浏览器(客户端)输入域名地址
后台会通过DNS服务器将域名转换成ip
ARP协议可以将IP地址转换成MAC地址
请参考:
DNS域名详细解析过程
3.ip地址的分类
IPv4 IPv6
IPv4 共有4个字节 32位 总共能产生的2^32 14.3亿
IPv4 在2015年左右就已经分配完了
IPv6 共有16个字节 128位
IPv4地址的划分
A类: 第一个字节是固定的,后三个字节可变的
1.0.0.0-127.255.255.255
共有A类地址 127个
一个A类地址能接 256256256
B类: 前两个字节是固定的,后两个字节是可变的
128.0.0.0-191.255.255.255
B类地址 (192-128)256
一个B类地址能接 256256个设备
C类: 前三个字节是固定的,最后一个字节是可变的
192.0.0.0-223.255.255.255
C类地址 (224-192)256256
一个C类地址最多接 256个设备
D类: 组播地址
224.0.0.0-239.255.255.255
E类: 保留地址
240.0.0.0-255.255.255.255
请参考:
ip地址分类、使用的详解
4.端口号
用来区分不同的进程的
端口号是一个16位的无符号的整型数:0-65535
0-1023 系统占用
1024-65535
请参考:
端口号是什么?
5.网络字节序
在整个编程阶段,我们可以接触到的字节序,共有两种
大端:
数据的高位,存放在地址的低位
数据的低位,存放在地址的高位
小端:
数据的高位,存放在地址的高位
数据的低位,存放在地址的低位
在网络通讯的时候 主要使用的是大端模式
在x86主机上 使用的是小端模式
请参考:
网络字节序详解
6.客户端链接服务端的方式
TCP:提供面向链接的可靠的传输
UDP:提供面向非连接的不可靠的传输
请参考:
TCP和UDP的详解和区别
7.TCP的三次握手
8.TCP的服务端模型
套接字:文件的一种,特殊的文件描述符,可以绑定ip端口,可以用于跨主机的进程间通讯
二、TCP服务端模型建立的相关函数
1.套接字的创建(socket)
函数的功能:
创建套接字
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int socket(int domain, int type, int protocol);
函数的参数:
int domain: IP的类型
AF_INET: IPv4
AF_INET6: IPv6
int type:
SOCK_STREAM: 流式套接字 tcp
SOCK_DGRAM: 数据报 udp
int protocol: 0
函数的返回值:
成功返回: 套接字
失败返回: -1
请参考:
socket函数详解
2.绑定端口和IP信息(bind)
函数的功能:
绑定ip地址和端口
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数的参数:
int sockfd: 套接字
const struct sockaddr *addr: IP地址端口结构体
socklen_t addrlen:结构体的长度
函数的返回值:
成功返回: 0
失败返回: -1
++++++++++++++++++++++++++++++++++++++++++++++++++
struct sockaddr
{
sa_family_t sa_family:IP地址的类型,AF_INET
char sa_data[14]:ip地址和端口号,拼接在一起的一个串
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
struct sockaddr_in
{
sa_family_t sin_family:AF_INET
in_port_t sin_port:端口号
struct in_addr sin_addr:ip地址
};
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
3.将小端的端口号转换成大端(htons)
函数的功能:
将小端的端口转换成大端
函数的头文件:
#include <arpa/inet.h>
函数的原型:
uint16_t htons(uint16_t hostshort);
函数的参数:
uint16_t hostshort:端口号
函数的返回值:
成功返回: 大端模式的端口号
4.将小端的ip地址转换成大端的ip地址(inet_addr)
函数的功能:
将小端模式的ip地址转换成大端模式
函数的头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数的原型:
in_addr_t inet_addr(const char *cp);
函数的参数:
const char *cp:小端模式的ip地址的字符串
函数的返回值:
大端模式的ip地址
5.将大端地址转换小端的字符串形式的ip地址(inet_ntoa)
函数的功能:
将大端模式的ip转换成小端
函数的头文件:
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函数的原型:
char *inet_ntoa(struct in_addr in);
函数的参数:
struct in_addr in:存放ip地址的结构体
函数的返回值:
成功返回: 小端模式的ip地址的字符串
失败返回: NULL
6.监听网络(listen)
函数的功能:
监听网络
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int listen(int sockfd, int backlog);
函数的参数:
int sockfd: 服务端的套接字
int backlog: 最大的客户端的链接的数目 最大是128
函数的返回值:
成功返回: 0
失败返回: -1
请参考:
深入了解listen函数工作原理
7.接受客户端的链接(accept)
函数的功能:
接受客户端的链接请求
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
函数的参数:
int sockfd: 服务端的套接字
struct sockaddr *addr: 存放客户端的ip端口信息
socklen_t *addrlen: 结构体的长度
函数的返回值:
成功返回: 新的套接字 专门用来跟客户端通讯
请参考:
accept函数详解
8.收发信息函数(recv,send)
函数的功能:
收发消息
函数的头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数的原型:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
函数的参数:
int sockfd: 通讯套接字
void *buf: 收到/要发送的内容存放的位置
size_t len: 要收/发的长度
int flags: 0 阻塞
函数的返回值:
成功返回: 成功收/发的字节数
失败返回: -1
9.代码示例
三、TCP客户端模型建立的相关函数
1.套接字的创建(socket)
函数的功能:
创建套接字
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int socket(int domain, int type, int protocol);
函数的参数:
int domain: IP的类型
AF_INET: IPv4
AF_INET6: IPv6
int type:
SOCK_STREAM: 流式套接字 tcp
SOCK_DGRAM: 数据报 udp
int protocol: 0
函数的返回值:
成功返回: 套接字
失败返回: -1
请参考:
socket函数详解
2.链接服务器(connect)
函数的功能:
链接服务器
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数的参数:
int sockfd: 套接字
const struct sockaddr *addr: 服务器的ip端口
socklen_t addrlen: 结构体的大小
函数的返回值:
成功返回: 0
失败返回: -1
3.收发信息函数(recv,send)
函数的功能:
收发消息
函数的头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数的原型:
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
函数的参数:
int sockfd: 通讯套接字
void *buf: 收到/要发送的内容存放的位置
size_t len: 要收/发的长度
int flags: 0 阻塞
函数的返回值:
成功返回: 成功收/发的字节数
失败返回: -1
4.代码示例
四、UDP通讯流程相关函数
1.套接字的创建(socket)
函数的功能:
创建套接字
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int socket(int domain, int type, int protocol);
函数的参数:
int domain: IP的类型
AF_INET: IPv4
AF_INET6: IPv6
int type:
SOCK_STREAM: 流式套接字 tcp
SOCK_DGRAM: 数据报 udp
int protocol: 0
函数的返回值:
成功返回: 套接字
失败返回: -1
请参考:
socket函数详解
2.绑定IP和端口号(bind)
函数的功能:
绑定ip地址和端口
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
函数的参数:
int sockfd: 套接字
const struct sockaddr *addr: IP地址端口结构体
socklen_t addrlen:结构体的长度
函数的返回值:
成功返回: 0
失败返回: -1
++++++++++++++++++++++++++++++++++++++++++++++++++
struct sockaddr
{
sa_family_t sa_family:IP地址的类型,AF_INET
char sa_data[14]:ip地址和端口号,拼接在一起的一个串
}
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
struct sockaddr_in
{
sa_family_t sin_family:AF_INET
in_port_t sin_port:端口号
struct in_addr sin_addr:ip地址
};
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
3.收消息(recvfrom)
函数的功能:
收消息
函数的头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数的原型:
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
函数的参数:
int sockfd: 套接字
void *buf: 接受到的内容存放的位置
size_t len: 要接受的长度
int flags: 0 阻塞的接收
struct sockaddr *src_addr: 对方的ip端口结构体
socklen_t *addrlen: 对方的ip端口结构体的大小
必须赋值成 sizeof(struct sockaddr)
函数的返回值:
成功返回: 成功读取的字节数
失败返回: -1
4.发消息(sendto)
函数的功能:
发消息
函数的头文件:
#include <sys/types.h>
#include <sys/socket.h>
函数的原型:
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
函数的参数:
int sockfd: 套接字
const void *buf: 要发送的消息存放的位置
size_t len: 要发送的消息的长度
int flags: 0 阻塞的发
const struct sockaddr *dest_addr: 对方的ip端口信息
socklen_t addrlen: 结构体的长度
函数的返回值:
成功返回: 成功发送的字节数
失败返回: -1
5.代码示例
先收后发(服务端):
先发后收(客户端):
五、UDP的组播
1.创建套接字(socket)
函数的功能:
创建套接字
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int socket(int domain, int type, int protocol);
函数的参数:
int domain: IP的类型
AF_INET: IPv4
AF_INET6: IPv6
int type:
SOCK_STREAM: 流式套接字 tcp
SOCK_DGRAM: 数据报 udp
int protocol: 0
函数的返回值:
成功返回: 套接字
失败返回: -1
请参考:
socket函数详解
2.设置套接字的属性(setsockopt)
函数的功能:
设置套接字的属性
函数的头文件:
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
函数的原型:
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
函数的参数:
int sockfd: 套接字
int level:网络层
ip层: IPPROTO_IP,主要是用来设置组播的
socket层:SOL_SOCKET ,主要是用来设置地址的复用和广播
int optname: 要设置的属性
IP_ADD_MEMBERSHIP: 加入组播
IP_MULTICAST_IF: 创建组播
SO_BROADCAST:开启广播
SO_REUSEPORT:端口复用
SO_REUSEADDR:ip地址的复用
const void *optval: 根据前边的选项的不同 , 这个参数也不同
socklen_t optlen: 参数的大小
函数的返回值:
成功返回: 0
失败返回: -1
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
假如要创建或者是加入多播组,第四个参数就是:
struct ip_mreqn
{
struct in_addr imr_multiaddr: 组播的ip
struct in_addr imr_address: 本地ip
int imr_ifindex: 网卡的索引号
};
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
3.代码示例
多路io复用
一、多路io复用的基础知识
多路io复用详细讲解
1.什么是多路io复用?
IO 多路复用是一种同步 IO 模型,实现一个线程可以监视多个文件句柄。一旦某个文件句柄就绪,就能够通知应用程序进行相应的读写操作;没有文件句柄就绪时会阻塞应用程序,交出 cpu。IO 是指网络 IO,多路指多个TCP连接(即 socket 或者 channel),复用指复用一个或几个线程。意思说一个或一组线程处理多个 TCP 连接。最大优势是减少系统开销小,不必创建过多的进程/线程,也不必维护这些进程/线程。IO 多路复用的三种实现方式:select、poll、epoll。
二、SELECT机制相关的函数
1.select基础知识
多路io复用的一种手段
他是用来监测文件描述符的异动(可读、可写、出错)的
select是将所有要监测的文件描述符放入到一张表里
当产生异动的时候再去调用对应的函数即可
当某个文件描述符产生异动之后,会将没有产生异动的文件描述符清空
2.select函数
函数的功能:
多路io复用
函数的头文件:
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
函数的原型:
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
函数的参数:
int nfds: 最大的文件描述符 +1
fd_set *readfds: 要监测的可读的表
fd_set *writefds: 要检测的可写的表 NULL
fd_set *exceptfds: 要检测的错误的表 NULL
struct timeval *timeout:超时时间 NULL 表示永久等待
函数的返回值:
超时返回: 0
失败返回: -1
产生异动返回: 产生异动的文件描述符的个数
相关宏定义:
void FD_CLR(int fd, fd_set *set): 从表里删除一个文件描述符
int FD_ISSET(int fd, fd_set *set): 判断某个文件描述符是否还在表里
void FD_SET(int fd, fd_set *set): 添加一个文件描述符到表里
void FD_ZERO(fd_set *set): 清空文件描述符
3.代码示例
三、poll机制相关的函数
请参考:
poll函数详解
1.poll基础知识
select() 和 poll() 系统调用的本质一样,poll() 的机制与 select() 类似,与 select() 在本质上没有多大差别,管理多个描述符也是进行轮询,根据描述符的状态进行处理,但是 poll() 没有最大文件描述符数量的限制(但是数量过大后性能也是会下降)。poll() 和 select() 同样存在一个缺点就是,包含大量文件描述符的数组被整体复制于用户态和内核的地址空间之间,而不论这些文件描述符是否就绪,它的开销随着文件描述符数量的增加而线性增大。
2.poll函数
函数的功能:
多路io复用
函数的头文件:
#include <poll.h>
函数的原型:
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
函数的参数:
struct pollfd *fds: 要监测的文件描述符的结构体(数组)
nfds_t nfds: 要监测的文件描述符的个数
int timeout: 超时时间 -1 表示永久等待
函数的返回值:
失败返回: -1
超时返回: 0
成功返回: 产生异动的文件描述符的个数
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
struct pollfd
{
int fd:要监测的文件描述符
short events: 要监测的事件类型
POLLIN 可读
POLLOUT 可写
POLLERR 出错
short revents;
};
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
3.代码示例
四、epoll机制相关的函数
1.epoll基础知识
epoll 是一种典型的 IO 多路复用技术,epoll 最大的特点是支持高并发。传统 IO 多路复用技术 select、poll 由于操作系统的一些限制,在并发量上千级别的时候性能就会明显下降。
epoll 和 kqueue(freebsd)都是支持高并发的 IO 多路复用技术。epoll 是 Linux 内核 2.6 版本才引入的,更早的内核版本是不支持 epoll 技术的。使用 epoll 技术,单独一台机器能支持少则数万多则数十万百万并发连接。高并发总是伴随着一定的系统资源消耗,比如需要内存去保存这个连接,因此并发量也总是有限的。
假如现在 epoll 有十万个连接,同一时刻有几十个客户端发送数据,epoll 只会检查这几十个客户端发送的数据,如果使用 poll 或者 select,它们会检查所有的连接是否有发送数据,就是挨个连接询问是否有发数据过来,相比之下 epoll 的性能优势显而易见。
很多服务器使用多进程或者多线程去支持高并发,但是创建进程或者线程切换都是比较消耗资源的,epoll 采用事件驱动机制,在单独的进程/线程中运行去收集、处理事件,没有创建进程或者线程切换的开销,因此更加高效。
2.epoll相关函数
1.创建epoll文件描述符(epoll_create)
函数的功能:
创建epoll的文件描述符
函数的头文件:
#include <sys/epoll.h>
函数的原型:
int epoll_create(int size);
函数的参数:
int size:给一个大于0的整数
函数的返回值:
成功返回: epoll的文件描述符
失败返回: -1
2.管理文件描述符(epoll_ctl)
函数的功能:
管理要监测的文件描述符
函数的头文件:
#include <sys/epoll.h>
函数的原型:
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
函数的参数:
int epfd: epoll的文件描述符
int op: 操作
EPOLL_CTL_ADD 添加
EPOLL_CTL_DEL 删除
int fd; 要操作的文件描述符
struct epoll_event *event: 事件结构体
函数的返回值:
成功返回: 0
失败返回: -1
+++++++++++++++++++++++++++++++++++++++++++++++++
struct epoll_event
{
uint32_t events: 要监测的事件
EPOLLIN: 可读
EPOLLOUT: 可写
EPOLLERR: 出错
epoll_data_t data: 当时添加的时候 这个共用体要指定fd
};
+++++++++++++++++++++++++++++++++++++++++++++++++
3.轮询epoll里的文件描述符(epoll_wait)
函数的功能:
轮询epoll
函数的头文件:
#include <sys/epoll.h>
函数的原型:
int epoll_wait(int epfd, struct epoll_event *events,int maxevents, int timeout);
函数的参数:
int epfd: epoll的文件描述符
struct epoll_event *events: 事件结构体
int maxevents: 最大监测的文件描述符的个数
int timeout: -1 永久等待
函数的返回值:
失败返回: -1
超时返回: 0
成功返回: 产生的异动的文件描述符的个数
3.代码示例
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <sys/epoll.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int serid = 0;
int ret = 0;
int count = 0;
int clid = 0;
int i = 0;
struct sockaddr_in seraddr;
struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);
int main(int argc, char *argv[])
{
serid = socket(AF_INET, SOCK_STREAM, 0);
if (serid < 0)
{
perror("socket");
return -1;
}
seraddr.sin_family = AF_INET;
seraddr.sin_port = htons(8888);
seraddr.sin_addr.s_addr = inet_addr("192.168.0.107");
ret = bind(serid, (struct sockaddr *)&seraddr, sizeof(seraddr));
if (ret < 0)
{
perror("bind");
return -1;
}
ret = listen(serid, 10);
int ep = 0;
ep = epoll_create(10);
if (ep < 0)
{
perror("epoll_create");
return -1;
}
struct epoll_event ev;
ev.events = POLLIN;
ev.data.fd = serid;
epoll_ctl(ep, EPOLL_CTL_ADD, serid, &ev);
struct epoll_event myep[10] = {0};
while (1)
{
count = epoll_wait(ep, myep, 10, -1); //事件异动的个数
if (count < 0)
{
perror("epoll_wait");
return -1;
}
for (i = 0; i < count; i++)
{
if (myep[i].events == POLLIN)
{
if (myep[i].data.fd == serid)
{
clid = accept(serid, (struct sockaddr *)&seraddr, &len);
if (clid < 0)
{
perror("accept");
return -1;
}
ev.data.fd = clid;
ev.events = POLLIN;
epoll_ctl(ep, EPOLL_CTL_ADD, clid, &ev);
printf("客户端%d号上线!\n", clid);
}
else
{
char buf[64] = {0};
ret = recv(clid, buf, 64, 0);
if (ret < 0)
{
perror("recv");
continue;
}
if (ret == 0)
{
printf("客户端%d号下线!\n", myep[i].data.fd);
epoll_ctl(ep, EPOLL_CTL_DEL, myep[i].data.fd, NULL);
}
if (ret > 0)
{
printf("buf=%s\n", buf);
}
}
}
}
}
return 0;
}
数据库
一、数据库的基本操作
1.mysql的进入和退出
mysql的进入,在终端执行命令:mysql -u root -p
mysql的退出:quit
2.mysql的数据类型
请参考:
mysql数据类型详解
bool: 布尔类型,0或者1
CHAR: 单字节字符
CHAR(n): 多字符
VCHAR(n): 可变长度字符
TINYINT: 单字节整型
SMALLINT: 双字节整型
MEDIUMINT: 三字节整型
INT: 四字节整型
BIGINT: 八字节整型
FLOAT: 单精度浮点型
DOUBLE: 双精度浮点型
DATE: 日期格式
YYYY-MM-DD
TIME: 时间格式
HH:MM:SS
DATE TIME:
YYYY-MM-DD HH:MM:SS
3.mysql常用词汇
databases :数据库
table:表
row:行
column:列
from:来自于
select:选择
*:所有
show:显示
insert:插入
update:更新
drop:删除
delete:删除
change:更改
where:条件
4.mysql的显示
显示数据库: show databases;
使用某个数据库: use + 数据库的名字;
显示表: show tables;
显示列: show columns from 表名;
5.mysql的查找
查找某个表里的所有的数据:
select * from 表名;
查找表里的某两列的内容:
select 列名1,列名2 from 表名;
查找表里满足某个条件的数据:
select * from 表名 where 条件
select * from pet_9202 where 姓名=“张三” and 年龄=1;
6.mysql表的插入和创建
数据库的创建:
create database+数据库的名字;
创建表:
create table mytest(name char(64),age int,bith date);
create table 表名(列名 列的类型,列名 列的类型。。。。。。。。)
向表里插入数据:
顺序插入:
insert into 表名 values(列1值,列2值,列3值);
insert into mytest values(“张三”,1,“2022-09-26”);
乱序插入:
insert into 表名 (列名1,列名2,列名3)values(列1值,列2值,列3值);
insert into mytest (bith,name,age) values(“2022-09-26”,“王五”,1);
7.mysql的修改
修改表的名字:
alter table 旧的表名 rename 新的表名
修改列的名字:
alter table 表的名字 change 旧的列名 新的列名 新的列类型
alter table mypet change name 姓名 char(64);
新增列:
alter table 表的名字 add 要新增的列名 列的类型
删除列:
alter table 表名 drop 要删除的列名
8.mysql的更新
更新数据:
update 表名 set 要更新的列=要更新成的值 where 查询的条件
update mypet set age=2 where 姓名=“张三”;
9.mysql的删除
删除数据库:
drop database 数据库的名字;
drop database pet_209;
删除表:
drop table 要删除表的名字
drop table mypet;
删除数据:
delete from 表名 where 条件
delete from mypet where age=2;
10.mysql的排序
select * from 表名 order by 列名;
默认的排序方式 升序,也可以加上 ASC
要想降序,加上DESC
二、C语言操作数据库相关函数
1.初始化数据库核心结构体
函数的功能:
初始化数据库的核心结构体
函数的头文件:
mysql/mysql.h
函数的原型:
MYSQL * mysql_init(MYSQL *mysql)
函数的参数:
MYSQL *mysql:数据库的结构体
函数的返回值:
成功返回: mysql数据库的结构体指针
失败返回: NULL
2.链接数据库
函数的功能:
链接数据库
函数的头文件:
mysql/mysql.h
函数的原型:
MYSQL *mysql_real_connect(MYSQL *mysql, const char *host, const char *user, const char *passwd, const char *db, unsigned int port, const char *unix_socket, unsigned long client_flag)
函数的参数:
MYSQL *mysql: mysql的结构体指针
const char *host: 主机名 localhost
const char *user: 用户名 root
const char *passwd: 密码 1
const char *db: 要连接的数据库
unsigned int port: 端口 0
const char *unix_socket: NULL
unsigned long client_flag: 0
函数的返回值:
成功返回: mysql的结构体指针
失败返回: NULL
3.执行mysql语句
函数的功能:
执行sql语句
函数的头文件:
mysql/mysql.h
函数的原型:
int mysql_query(MYSQL *mysql, const char *query)
函数的参数:
MYSQL *mysql: mysql的结构体指针
const char *query: 要执行的sql语句
函数的返回值:
成功返回: 0
失败返回: -1
4.存储mysql语句执行结果
函数的功能:
将mysql的执行结果放入一个结构体里
函数的头文件:
mysql/mysql.h
函数的原型:
MYSQL_RES *mysql_store_result(MYSQL *mysql)
函数的参数:
MYSQL *mysql:数据库的结构体指针
函数的返回值:
成功返回: 数据库的结果集合结构体指针
失败返回: NULL
++++++++++++++++++++++++++++++++++++++++++++++++
typedef struct st_mysql_res
{
my_ulonglong row_count; // 结果集的行数
unsigned int field_count, current_field; // 结果集的列数,当前列
MYSQL_FIELD *fields; // 结果集的列信息
MYSQL_DATA *data; // 结果集的数据
MYSQL_ROWS *data_cursor; // 结果集的光标
MEM_ROOT field_alloc; // 内存结构
MYSQL_ROW row; // 非缓冲的时候用到
MYSQL_ROW current_row; //mysql_store_result时会用到。当前行
unsigned long *lengths; //每列的长度
MYSQL *handle; // mysql_use_result会用。
my_bool eof; //是否为行尾
} MYSQL_RES;
++++++++++++++++++++++++++++++++++++++++++++++++
5.对mysql结果集合的操作函数
unsigned int mysql_num_fields(MYSQL_RES* res)
获取结果集合里列的个数
my_ulonglong mysql_num_rows(MYSQL_RES *result)
获取结果集合里行的个数
MYSQL_ROW mysql_fetch_row(MYSQL_RES *result)
获取一行内容
MYSQL_FIELD *mysql_fetch_field(MYSQL_RES *result)
获取列的信息
6.释放mysql的查询的结果集合结构体
函数的功能:
释放mysql的查询的结构体集合结构体
函数的头文件:
mysql/mysql.h
函数的原型:
void mysql_free_result(MYSQL_RES *result)
函数的参数:
MYSQL_RES *result:mysql数据库的结果集合结构体指针
函数的返回值:
无
7.关闭数据库
函数的功能:
关闭数据库
函数的头文件:
mysql/mysql.h
函数的原型:
void mysql_close(MYSQL *mysql)
函数的参数:
MYSQL *mysql:数据库的结构体
函数的返回值:
无
8.示例代码
#include <stdio.h>
#include <mysql/mysql.h>
MYSQL student;
MYSQL* ret=NULL;
int main(int argc, char *argv[])
{
//1.初始化数据库核心结构体
ret=mysql_init(&student);
if(NULL == ret)
{
perror("mysql_init");
return -1;
}
//链接数据库
ret=mysql_real_connect(ret,"localhost","root","1","mytest",3306,0,0);
if(NULL ==ret)
{
perror("mysql_real_connect");
return -1;
}
//执行mysql语句
mysql_query(ret,"select * from student;");
//存储mysql语句执行结构
MYSQL_RES* res=NULL;
res=mysql_store_result(ret);
if(NULL==res)
{
printf("表格为空!\n");
return -1;
}
int row,line,i,j;
row=mysql_num_rows(res);
line=mysql_num_fields(res);
printf("student表是%d行%d列的\n",row,line);
MYSQL_FIELD* line_msg=NULL;
printf("-------------------------------------------------------\n");
for(i=0;i<line;i++)
{
line_msg=mysql_fetch_field(res);
printf("%s ",line_msg->name);
}
printf("\n");
printf("-------------------------------------------------------\n");
MYSQL_ROW row_msg;
for(i=0;i<row;i++)
{
row_msg=mysql_fetch_row(res);
for(j=0;j<line;j++)
{
printf("%s ",row_msg[j]);
}
printf("\n");
}
printf("-------------------------------------------------------\n");
//5.释放数据库结果集合结构体
mysql_free_result(res);
//6.关闭数据库
mysql_close(ret);
return 0;
}