阻塞 非阻塞 信号驱动 多路复用
int fcntl( 文件描述符, 命令, 参数 );
int flag = fcntl( fd, F_GETFL, 0 );
flag |= O_NONBLOCK; flag &= ~O_NONBLOCK;
fcntl( fd, F_SETFL, flag );
多路复用:
当一个进程中有多个阻塞IO时,把所有的阻塞都集中到一个位置,在解除阻塞后,进行IO的时,就是一个非阻塞。
select
工作原理:
1. 用户空间创建一张存放描述符的表,表的大小是1024bit,
2. 把想监听的描述符放在表中
3. 调用select函数
4. select会传递表给内核,内核轮询表,查看描述符对应的文件是否可以进行IO操作
5. 如果有描述符可以进行IO操作时,内核会修改表,保留能进行IO的操作的描述符,
并且通过select将表返回给应用程序
6. 在select返回后,应用程序遍历表,对应每一个表中的描述符进行相应的IO操作。
7. 重复2~6
特点:
1. 表需要在userSpace和kernelSpace回来拷贝,效率低
2. 表需要在userSpace和kernelSpace多次轮询,效率低
3. 表的大小是1024bit,最多能监听1024个描述符,范围是0~1023,范围比较小
epoll
工作原理:
1. 通过epoll_create创建epoll句柄//实际上是在内核创建一棵存放描述符的红黑树,并且返回树的编号
2. 通过epoll_ctl将想监听的描述符放在树上,作为树的节点
3. 通过epoll_wait等待文件可以进行IO操作
4. //内核在遍历红黑树,如果有文件可以进行IO操作时,会通过epoll_wait将文件描述符返回
5. 遍历epoll_wait返回的数组,对应每个的文件进行IO操作
6. 重复3~5
特点:
相对select来说,少了表的拷贝,轮询的节点都是有必要的,所以效率高。
epoll可以监听的描述符更多。
服务器模型
目标:
1. 服务器开机后,可以处理多个客户端的请求
2. 尽量让每一个客户端等待时间短点
循环服务器
tcp循环服务器不太常用
udp循环服务器(常用)
创建socket
绑定自己的地址
while(1)
{
通信
}
关闭socket
并发服务器
tcp并发服务器
创建socket,bind,监听
while(1)
{
accept接受连接
创建子进程/子线程,实现通信,通信结束关闭已连接Socket
}
关闭等连接socket
多路复用服务器
tcp多路复用服务器
创建socket,bind,监听
创建表,初始化表
while(1)
{
select/epoll_wait
遍历表,执行IO操作
}
关闭等连接socket
网络超时
让有效时间范围内阻塞,超时,可以不阻塞。
它的设置一定在阻塞之前设置。
1. setsockopt设置socket属性
struct timeval tv = {3, 0};
setsockopt( socketFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv) );
2. select设置阻塞时间
struct timeval tv = {3, 0};
select( maxFd + 1, &readFds, NULL, NULL, &tv );
3. 信号中断阻塞 在处理完信号以后,可以不重启阻塞。
获取当前进程对信号的处理办法
struct sigaction act;
sigaction(SIGALRM, 0, &act);
修改处理办法
act.信号中断服务程序 = 自定义函数;
act.是否重启阻塞 &= ~SA_RESTART;
设置当前进程对信号的处理办法
sigaction( SIGALRM, &act, 0);
alarm(5);//启动定时器
启动阻塞
accept、recv、recvfrom
1. TCP下载
可能出现的问题
a. 发送的长度不对
read( fd, buf, sizeof(buf) );
send( socketID, buf, sizeof(buf), 0 ); //测试图片 bmp,png
send( socketID, buf, strlen(buf), 0 ); //测试图片 bmp,png
解决方案【读多少发多少】:
int len = read( fd, buf, sizeof(buf) );
send( socketID, buf, len, 0 );
b. 源文件和目标文件在相同路径下
tcp_server.c --> tcps --> ./tcps 路径文件名
tcp_client.c --> tcpc -->
解决方案:
将被下载的文件和下载之后的文件放在不同路径下。
例:ls
c. 创建空洞文件
(1). 可以借助/dev/zero来创建空洞文件
(2). 创建并且打开文件,跳转到指定长度,写'\0'。
d. 发送文件长度不对
count=lseek(), fseek+count=ftell, stat, count+=read(fd, buf, 100);
send( socketID, &count, sizeof(count), 0 );
单播
tcp一对一
udp一对一
一个发送同一个局域网中的每台主机都可以接收。
udp发送端流程
创建socket
//绑定自己的地址
设置当前socket可以发送广播消息
设置服务器的port和广播ip地址
发送消息
关闭socket
udp接收端
创建socket
绑定自己的地址port+INADDR_ANY
接收消息
关闭socket
设置当前socket可以发送广播消息
int on = 1;
int setsockopt( socketFd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on) );
缺点:
可能产生广播风暴。
创建表,在表中把数据放进去。
字段(表头)
记录(一般情况下一条记录就是一个实体)
主键:
主键有唯一性。
表里面的关键属性。
用主键可以唯一的确认某一条记录。
ER关系(实体和实体之间的关系 或者 实体和属性之间的关系)
1:1 --> 乘客和车票
在其中一张表中写另外一张表的主键
例:在乘客表中对应写他的车票的编号
例:在车票表中对应写乘客的主键
1:n --> 一节车厢有多个座位 书和书架
m:n --> 学生和选课 书籍分类 管理员和书架
SQL *****
创建表
CREATE TABLE 表名(字段列表[约束]);
例:文件相关的表:文件名,文件大小,文件后缀,文件路径
CREATE TABLE FileTable(id INTEGER PRIMARY KEY, fileName TEXT, fileSize INTEGER, fileExtension TEXT, filePath TEXT );
例: 学生信息的表: 姓名、身份证号、年龄、住址
CREATE TABLE StudentTable(id INTEGER PRIMARY KEY, studentName TEXT NOT NULL, idNum TEXT NOT NULL unique, age INTEGER default 20, place TEXT);
添加记录
INSERT INTO 表名 (字段列表) VALUES (值列表);
例:文件相关的表插入几条记录
INSERT INTO FileTable (id, fileName, fileSize, fileExtension, filePath ) VALUES (1, '1.txt', 23, '.txt', '/home/farsight');
INSERT INTO FileTable VALUES (7, 'jump.jpeg', 2390, '.jpeg', '/home/farsight/picture');
INSERT INTO FileTable (fileName, fileSize, fileExtension, filePath ) VALUES ('1.txt', 23, '.txt', '/home/farsight');
INSERT INTO FileTable (fileName, fileSize, filePath ) VALUES ('a.avi', 400000, '/home/farsight/movie');
修改记录
UPDATE 表名 SET 列=值 列2=值2.. WHERE 条件;
例:修改学生信息表中的idNum
UPDATE StudentTable SET idNum='00001' ;//这样会把所有的记录都改掉,慎用。
例:修改学生名为zhangWu的idNum='90';
UPDATE StudentTable SET idNum='90' WHERE studentName='zhangWu';
例:修改学生名为zhangWu的idNum='1000';
UPDATE StudentTable SET idNum='1000' WHERE studentName='zhangWu' and id > 7 ;
查询记录
SELECT (字段列表) FROM 表名 WHERE 条件 GROUP BY 字段 ORDER BY 字段 LIMIT count,offset ;
例:查询所有文件信息
SELECT * FROM FileTable;
例:查询文件名为空的文件信息
SELECT * FROM FileTable WHERE fileName is null;
例:查询文件编号不为5的文件信息
SELECT * FROM FileTable WHERE id <> 5;
例:查询文件编号不为5或者后缀为'.mp3'的文件信息
SELECT * FROM FileTable WHERE id <> 5 or fileExtension='.mp3';
例:查询id>3的文件信息按路径分类
SELECT * FROM FileTable WHERE id > 3 GROUP BY filePath;
例:查询id>3的文件信息按大小排序
SELECT * FROM FileTable WHERE id > 3 ORDER BY fileSize;
例:查询id>1的文件信息从第5条开始显示,只显示3条
SELECT * FROM FileTable WHERE id > 1 LIMIT 5,3;