Next 10 TCP并发,数据库
作业:
server 服务端 epoll #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <netinet/in.h> #include <netinet/ip.h> #include <arpa/inet.h> #include <time.h> #include <sys/epoll.h> typedef struct sockaddr *(SA); int add_fd(int epfd, int fd) { struct epoll_event ev = {0}; ev.events = EPOLLIN; ev.data.fd = fd; int ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev); if (-1 == ret) { perror("add_fd"); return ret; } return 0; } int main(int argc, char **argv) { // 1. internet , udp, 默认协议 int udpfd = socket(AF_INET, SOCK_DGRAM, 0); if (-1 == udpfd) { perror("socket"); return 1; } // 2. 给套接字 绑定ip ,端口号 // man 7 ip 查询 ipv4 的地址结构体 struct sockaddr_in ser, cli; // 服务器的地址结构体, 客户端的地址结构体 bzero(&ser, sizeof(ser)); bzero(&cli, sizeof(cli)); ser.sin_family = AF_INET; // ipv4 ser.sin_port = htons(50000); // host to net short 小端转大端 ser.sin_addr.s_addr = INADDR_ANY; int ret = bind(udpfd, (SA)&ser, sizeof(ser)); if (-1 == ret) { perror("bind"); return 1; } socklen_t len = sizeof(cli); char buf[1024] = {0}; recvfrom(udpfd, buf, sizeof(buf), 0, (SA)&cli, &len); // ep1 create set struct epoll_event rev[2]; int epfd = epoll_create(2); if (-1 == epfd) { perror("epoll_creaete"); return 1; } // ep2 add_fd add_fd(epfd, udpfd); add_fd(epfd, 0); while (1) { bzero(buf, sizeof(buf)); int ep_ret = epoll_wait(epfd, rev, 2, -1); int i = 0; for (i = 0; i < ep_ret; i++) { if (0 == rev[i].data.fd) // 标准输入可以读取 { printf("to cli:"); fgets(buf, sizeof(buf), stdin); sendto(udpfd, buf, sizeof(buf), 0, (SA)&cli, len); if (0 == strcmp(buf, "#quit\n")) { return 0; } } else { recvfrom(udpfd, buf, sizeof(buf), 0, NULL, NULL); if (0 == strcmp(buf, "#quit\n")) { return 0; } printf("from cli:%s", buf); fflush(stdout); } } } return 0; }一、TCP并发进程
/** * @file 01ser.c 进程版本的并发 tcp 服务器 1 .僵尸进程的回收 2. 文件描述符的回收 listfd conn ,对于父子进程的差异 * @author yashiro (rage_yas@hotmail.com) * @brief * @version 0.1 * @date 2026-03-09 * * @copyright Copyright (c) 2026 * */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <time.h> #include <sys/wait.h> #include <signal.h> typedef struct sockaddr *(SA); void handle(int num) { wait(NULL); } int main(int argc, char **argv) { signal(SIGCHLD, handle); // 1 打开网络设备,获得文件描述(套接字) // 监听套接字 int listfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == listfd) { perror("socket"); return 1; } struct sockaddr_in ser, cli; //清空 结构体 bzero(&ser, sizeof(ser)); bzero(&cli, sizeof(cli)); ser.sin_family = AF_INET; ser.sin_port = htons(50000); ser.sin_addr.s_addr = INADDR_ANY; // 2 给套接字绑定 ip +port ,方便客户端找到服务器 int ret = bind(listfd, (SA)&ser, sizeof(ser)); if (-1 == ret) { perror("bind"); return 1; } // 3 进入监听状态 (套接字进入可以被链接的状态) // 参数2 ,进行三次握手的排队数 listen(listfd, 3); socklen_t len = sizeof(cli); while (1) // 三次握手多个客户端 { // 4 建立链接 (触发三次握手) // 通信套接字,表示从服务端来看,conn 是客户端的套接字 int conn = accept(listfd, (SA)&cli, &len); if (-1 == conn) { perror("accept"); close(conn); continue; } pid_t pid = fork(); if (pid > 0) { close(conn); // wait(NULL); } else if (0 == pid) { close(listfd); while (1) // 与客户端的多次收发 { char buf[512] = {0}; // 5 接收数据 // 返回值 >0 实际收到的字节数 ==0 对方断开 -1 错误 int rd_ret = recv(conn, buf, sizeof(buf), 0); if (rd_ret <= 0) { printf("cli offline\n"); exit(0); } // 5.5 处理数据 printf("cli:%s\n", buf); time_t tm; time(&tm); sprintf(buf, "%s %s", buf, ctime(&tm)); // 6 发送数据 send(conn, buf, strlen(buf), 0); } } else { perror("fork"); continue; } } // 7 断开链接 close(listfd); return 0; }二、tcp 线程
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/types.h> /* See NOTES */ #include <sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <time.h> #include <pthread.h> #include <semaphore.h> sem_t sem_arg; typedef struct sockaddr*(SA); void* th(void* arg) { int conn = *(int*)arg; sem_post(&sem_arg); // 分离属性, 当线程结束后,栈区自动由系统回收 pthread_detach(pthread_self()); while (1) { char buf[512] = {0}; // 5 接收数据 // 返回值 >0 实际收到的字节数 ==0 对方断开 -1 错误 int rd_ret = recv(conn, buf, sizeof(buf), 0); if (rd_ret <= 0) { printf("cli offline\n"); close(conn); break; } // 5.5 处理数据 printf("cli:%s\n", buf); time_t tm; time(&tm); sprintf(buf, "%s %s", buf, ctime(&tm)); // 6 发送数据 send(conn, buf, strlen(buf), 0); } return NULL; } int main(int argc, char** argv) { // 1 打开网络设备,获得文件描述(套接字) // 监听套接字 int listfd = socket(AF_INET, SOCK_STREAM, 0); if (-1 == listfd) { perror("socket"); return 1; } struct sockaddr_in ser, cli; //清空 结构体 bzero(&ser, sizeof(ser)); bzero(&cli, sizeof(cli)); ser.sin_family = AF_INET; ser.sin_port = htons(50000); ser.sin_addr.s_addr = INADDR_ANY; // 2 给套接字绑定 ip +port ,方便客户端找到服务器 int ret = bind(listfd, (SA)&ser, sizeof(ser)); if (-1 == ret) { perror("bind"); return 1; } // 3 进入监听状态 (套接字进入可以被链接的状态) // 参数2 ,进行三次握手的排队数 listen(listfd, 3); socklen_t len = sizeof(cli); sem_init(&sem_arg, 0, 0); while (1) { // 4 建立链接 (触发三次握手) // 通信套接字,表示从服务端来看,conn 是客户端的套接字 int conn = accept(listfd, (SA)&cli, &len); if (-1 == conn) { perror("accept"); close(conn); continue; } pthread_t tid; pthread_create(&tid, NULL, th, &conn); // usleep(1000*20); //20 ms // pthread_join(); // 确保 conn 参数一定在th现存中,被保存下来 sem_wait(&sem_arg); } sem_destroy(&sem_arg); // 7 断开链接 close(listfd); return 0; }三、数据库
数据库,是一个应用程序。可以对数据进行存储,并进行管理和统计的程序。多和服务器搭配使用
数据库中,数据是以表的形式组织在一起。一张表可以分为多个记录(行),一条记录可以分为多个字段(列)。
SQL struct query language 关系型数据库 非关系 芒果db
ddl data defination language 建表
dml 新增 修改 删除一行 data modifty
dql 查询 data query language 查询 select
2、名词:
DB 数据库 select update database
DBMS 数据库管理系统
MIS 管理信息系统
OA 办公自动化
3、嵌入式数据库:
sqlite www.sqlite.org www.kernal.org
GNU
特点:
1、开源 C语言开发
2、代码量少1万行左右,,总大小10M以内
3、绿色软件无需安装4、文件型数据库,可以移动。
5、数据容量最大2T
.database列出当前库和系统中那个文件在关联
.tables列出当期数据库中的所有表
.schemaXXX列出当前指定的xxx表结构
.headers on查询数据的时候显示列名
2、标准SQL语句:===》通用语法在其他平台可以直接使用。
struct query language;
注意:所有的sql语句都以;结尾。
创建一个表:ddl
create table 表名(表字段1,表字段2,...);
eg: create table user(id,name,age); char
注意:以上表的表字段,支持如下数据类型。int text real blob
默认是text类型。char
create table 表名(表字段 类型,表字段 类型,。。。);
eg: create table user(id int ,name char,age int);
删除一个表:
drop table 表名;
eg:drop table user;
向表中增加数据:insert into表名(字段名称)values(值名称);
eg: insert into user (id,age) values (1,10);
insert into user values(3,"wang",11);
insert into user (age) values ( 12);
insert into user1 values (2,'张三',23,datetime('now"'+8hours'));时间列
select datetime('now','+8 hours','-1 year');
CREATE TABLE user3(id INTEGER PRIMARY KEY ASC,name char,age int,dt datetime);
sqlite> insert into user3 (NULL,'李四',23,datetime('now','+ 8 hours');自动增长列
PRIMARY KEY主键,唯一性,如果使用主键作为搜索条件,比普通字段块。
查询表中的数据:
select 列名 from 表名 条件;
* 代表所有的列
select id,name from user where not age <30 ;
'%':0到任意多个任意字符;
'_':一个任意字符。
升序:select * from user order by id;
降序:select *from user order by id desc;
有限:select * from user limit 3;
修改表中数据:
update 表名 set 表字段 = 值满足条件:
update user set id = 2 where name = "li" or name ="zhao";
删除表中数据delete from 表名 满足条件:
delete from user where id =10;
数据库的导入导出
1、数据的导出:sqlite3 xxx.db.dump > xxx.sq1
//将数据库名称为xxx的数据库整体导出到脚本中。
2、数据的导入:sqlite3 xxx.db < xxx.sq1
数据库代码
1.打开数据库:
sqlite3_openint sqlite3_open(char * path,sqlite3 ** db);
功能:打开指定path路径+文件名称的数据库,并将打开的地址指向db变量的句柄。
参数:path要打开的数据库路径+名称db要打开的数据库地址指针
返回值:成功0;失败-1;
2.关闭数据库:sqlite3_closeint sqlite3_close(sqlite3 *db);
功能:关闭指定的数据库
参数:要关闭的数据库地址
返回值:成功0;失败-1;
3执行sql语句
int sqlite3_exec(sqlite3 *db,char *sql,callback fun,void *arg,char errmsg);
功能:在db数据库上执行sq1非查询语句。并将结果返回。
参数:db要执行sql的数据库sq1要执行的非查询sql语句。
fun如果该函数要执行查询语句,则该回调函数用来回收查询的结果。
arg回调函数的参数,如果没有回调函数则该参数为NULL:
errmsg执行过程中的错误信息。
返回值:执行成功0;失败非0。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sqlite3.h> int main(int argc, char **argv) { sqlite3 *db = NULL; // 1 打开数据库,获得数据的句柄(相当于linux 中的文件描述符) int ret = sqlite3_open("aaa.db", &db); if (SQLITE_OK != ret) { fprintf(stderr, "open db error %s\n", sqlite3_errstr(ret)); sqlite3_close(db); return 1; } char *errmsg = NULL; //需要执行的sql语句, 不要执行查询语句(select), char sql_cmd[512] = "insert into user values(7,'帅哥',20)"; // 2 执行sql语句(对数据库的读写) ret = sqlite3_exec(db, sql_cmd, NULL, NULL, &errmsg); if (SQLITE_OK != ret) { fprintf(stderr, "sqlite3_exec sql_cmd:[%s] ,%s\n", sql_cmd, errmsg); sqlite3_free(errmsg); sqlite3_close(db); return 1; } // 3. 关闭数据 释放资源 sqlite3_close(db); return 0; }