1.网络介绍
网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机组合在一起。每层实现不同的功能,其内部实现方法对外部其他层次来说是透明的。每层向上层提供服务,同时使用下层提供的服务网络体系结构即指网络的层次结构和每层所使用协议的集合两类非常重要的体系结构:OSI与TCP/IP。TCP/IP的四层模型是:网络接口与物理层 : 网卡与网卡驱动,网络层 : 路由器, ip地址,传输层: TCP 与UDP ,应用层: FTP, TFTP,DNS, SMTP, Samba ,SSH等。
2.网络编程
在网络编程中我们主要来看对其中API的使用,相关API使用的程序和讲解如下:
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
int main(int argc, char const *argv[])
{
struct sockaddr_in myaddr;
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&myaddr,0,sizeof(myaddr));
myaddr.sin_family = AF_INET; //internet协议
myaddr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
myaddr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
int ret = bind(skfd,(const struct sockaddr*)&myaddr,sizeof(myaddr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
//设置监听
ret = listen(skfd,10);
if(ret < 0)
{
perror("listen");
exit(-1);
}
system("netstat -ant");
//关闭socket
close(skfd);
return 0;
}
该段程序是socket的基本创建过程。socket:创建一个socket,第一个参数指定要通信的类型,第二个参数创建socket的类型,第三个参数通信的协议通常设置为0,返回值成功返回文件描述符失败返回-1.atoi:将字符串转化为整数,参数需要转化的字符串,返回值转化后的整数。htons:将主机字节序转化成网络字节序,参数主机的字节序,返回值转化后的网络字节序。inet_addr:将点分十进制的字符串转化成网络ip,参数点分十进制的字符串。bind:绑定端口号,第一个参数要操作的socket文件描述符,第二个参数包含创建的socket类型信息的结构体,第三个参数结构体的长度,返回值成功返回0失败返回-1。listen:设置soket成监听,第一个参数要设置的socket文件描述符,第二个参数等待队列的长度,返回值成功返回0失败返回-1.
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
int ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
//设置监听
ret = listen(skfd,10);
if(ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
newskfd = accept(skfd,(struct sockaddr*)&client_addr,&addr_len);
if(newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n",newskfd);
printf("client ip port:%s %d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
ret = recv(newskfd,buf,Nsize,0);
if(ret < 0)
{
perror("recv");
exit(-1);
}
printf("recv:%s\n",buf);
strcpy(buf,"server is received!!\n");
ret = send(newskfd,buf,Nsize,0);
if(ret < 0)
{
perror("send");
exit(-1);
}
close(newskfd);
}
//关闭socket
close(skfd);
return 0;
}
该段程序创建了一个tcp服务器。accept:接收客户端的连接请求,返回一个新的socket与客户端进行一对一通信,第一个参数socket文件描述符,第二个参数包含客户端信息的结构体,第三个参数结构体的长度,返回值成功返回一个新的socket文件描述符失败返回-1.recv:从socket中读取数据,第一个参数要读取的socket,第二个参数读取后的内容要存入的空间,第三个参数要读取的字节数,第四个参数一般设置为0,返回值成功返回读取的字节数失败返回-1.send:往socket中写入数据,第一个参数要写入数据的socket,第二个参数保存要写入数据的地址空间,第三个参数要写入的字节数,第四个参数一般为0.
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
//发送接收数据
printf(">:");
fgets(buf,Nsize,stdin);
buf[strlen(buf)-1] = 0;
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
ret = recv(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
printf("recv:%s\n", buf);
// 关闭socket
close(skfd);
return 0;
}
该段程序创建了一个tcp客户端,用以与服务端建立通信。connect:连接服务器,第一个参数要使用的socket文件描述符,第二个参数包含服务器信息的结构体,第三个参数结构体的长度,返回值成功返回0失败返回-1.
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
while (1)
{
memset(buf, 0, Nsize);
ret = recv(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
if (strcmp(buf, "quit") == 0)
break;
printf("%s %d said:%s\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port, buf);
printf(">:");
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
ret = send(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
close(newskfd);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是创建了服务器和客服端可以进行信息传输交谈的服务器程序,对比与前面两端程序的不同是该程序可以进行多次的信息交流。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
while (1)
{
// 发送接收数据
printf(">:");
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
if (strcmp(buf, "quit") == 0)
break;
memset(buf, 0, Nsize);
ret = recv(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
printf("%s\n", buf);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是实现客户端与服务器可以多次信息交流的客户端程序。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <dirent.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#define Nsize 128
int process_list(int newskfd, char buf[])
{
// 打开目录内容
DIR *dirp;
struct dirent *dt;
dirp = opendir(".");
if (dirp == NULL)
{
perror("opendir");
exit(-1);
}
while ((dt = readdir(dirp)) != NULL)
{
if (strncmp(dt->d_name, ".", 1) == 0)
continue;
sprintf(buf, "%s ", dt->d_name);
// 将目录内容发送
int ret = send(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
// 关闭目录
closedir(dirp);
// 关闭newskfd->关闭后客户端recv返回值为0,表示发送完成客户端也可以结束了
close(newskfd);
return 0;
}
int process_get(int newskfd, char buf[])
{
int fd,nbytes;
//打开当前目录文件
fd = open(buf+4,O_RDONLY|O_EXCL);
if(fd < 0)
{
perror("open");
exit(-1);
}
//读取文件内容
while ((nbytes = read(fd,buf,Nsize)) > 0)
{
// 将目录内容发送
int ret = send(newskfd, buf, nbytes, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
// 关闭文件
close(fd);
// 关闭newskfd->关闭后客户端recv返回值为0,表示发送完成客户端也可以结束了
close(newskfd);
return 0;
}
int process_put(int newskfd, char buf[])
{
int fd,nbytes;
//打开或者创建文件
fd = open(buf+4,O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd < 0)
{
perror("open");
exit(-1);
}
//接收内容
while ((nbytes = recv(newskfd,buf,Nsize,0)) > 0)
{
// 将目录内容发送
int ret = write(fd, buf, nbytes);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
// 关闭文件
close(fd);
// 关闭newskfd->关闭后客户端recv返回值为0,表示发送完成客户端也可以结束了
close(newskfd);
return 0;
}
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 绑定
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
// 接受客户端
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
// 处理客户端发送的数据
ret = recv(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
printf("%s %d said:%s\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port, buf);
if (strncmp(buf, "list", 4) == 0)
{
process_list(newskfd, buf);
}
else if (strncmp(buf, "get", 3) == 0)
{
process_get(newskfd, buf);
}
else if (strncmp(buf, "put", 3) == 0)
{
process_put(newskfd, buf);
}
close(newskfd);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序实现的是文件服务器中的服务器端程序,该程序实现的服务器和客户端可以进行文件的上传和下载。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/stat.h>
#include <fcntl.h>
#define Nsize 128
int process_list(struct sockaddr_in *addr, char buf[])
{
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)addr, sizeof(*addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
// 发送数据
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
// 接收数据->recv解析:当服务器close(newskfd),客户端recv返回值为0,当接收数据错误时返回-1
while (recv(skfd, buf, Nsize, 0) > 0)
{
printf("%s\n", buf);
}
// 关闭socket
close(skfd);
return 0;
}
int process_get(struct sockaddr_in *addr, char buf[])
{
int fd , nbytes;
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)addr, sizeof(*addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
// 发送数据
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
//打开或者创建一个文件来接收服务器发送的数据
fd = open(buf+4,O_WRONLY|O_CREAT|O_TRUNC,0664);
if(fd < 0)
{
perror("open");
exit(-1);
}
// 接收数据->recv解析:当服务器close(newskfd),客户端recv返回值为0,当接收数据错误时返回-1
while((nbytes = recv(skfd, buf, Nsize, 0)) > 0)
{
ret = write(fd,buf,nbytes);
if(ret < 0)
{
perror("write");
exit(-1);
}
}
// 关闭socket
close(skfd);
//关闭文件
close(fd);
return 0;
}
int process_put(struct sockaddr_in *addr, char buf[])
{
int fd , nbytes;
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)addr, sizeof(*addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
// 发送数据
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
//打开一个文件
fd = open(buf+4,O_RDONLY|O_EXCL);
if(fd < 0)
{
perror("open");
exit(-1);
}
// 接收数据->recv解析:当服务器close(newskfd),客户端recv返回值为0,当接收数据错误时返回-1
while((nbytes = read(fd, buf, Nsize)) > 0)
{
ret = send(skfd,buf,nbytes,0);
if(ret < 0)
{
perror("send");
exit(-1);
}
}
// 关闭socket
close(skfd);
//关闭文件
close(fd);
return 0;
}
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
while (1)
{
printf(">:list 显示目录\n");
printf(">:get namefile\n");
printf(">:put namefile\n");
printf(">:quit 退出程序\n");
printf(">:");
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
if (strncmp(buf, "list", 4) == 0)
{
process_list(&server_addr, buf);
}
else if (strncmp(buf, "get", 3) == 0)
{
process_get(&server_addr, buf);
}
else if (strncmp(buf, "put", 3) == 0)
{
process_put(&server_addr, buf);
}
else if (strncmp(buf, "quit", 4) == 0)
{
exit(0);
}
}
return 0;
}
该段程序实现的是文件服务器中的客户端。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
int ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,&addr_len);
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d said:%s\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port,buf);
memset(buf,0,Nsize);
strcpy(buf,"server is received!!");
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,addr_len);
if(ret < 0)
{
perror("sendto");
exit(-1);
}
}
//关闭socket
close(skfd);
return 0;
}
该段程序实现的是一个udp服务器,udp不需要像tcp一样进行握手和挥手操作。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int ret;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
while(1)
{
printf(">:");
fgets(buf,Nsize,stdin);
buf[strlen(buf)-1] = 0;
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("sendto");
exit(-1);
}
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,NULL,NULL);//不需要保存服务器返回的结构体地址
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d said:%s\n",inet_ntoa(server_addr.sin_addr),server_addr.sin_port,buf);
}
//关闭socket
close(skfd);
return 0;
}
该段程序实现的是一个udp客户端。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
// 定义链表
typedef struct link
{
struct sockaddr_in addr;
struct link *next;
} linklist_t;
linklist_t *link_init(void)
{
linklist_t *h = (linklist_t *)malloc(sizeof(linklist_t));
h->next = NULL;
memset(&h->addr, 0, sizeof(h->addr));
return h;
}
typedef struct
{
char type; // 消息类型L:登录 C:聊天 Q:退出
char name[Nsize]; // 消息名称
char text[Nsize]; // 消息正文
} msg_t;
// 定义函数
int process_login(linklist_t *h, int skfd, msg_t *msgp, struct sockaddr_in *addr)
{
int ret;
// 拼接文本
sprintf(msgp->text, "login");
// 遍历链表
linklist_t *p = h->next;
while (p != NULL)
{
ret = sendto(skfd, msgp, sizeof(msg_t), 0, (struct sockaddr *)&p->addr, sizeof(p->addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
p = p->next;
}
// 插入登录的客服端地址节点
p = (linklist_t *)malloc(sizeof(linklist_t));
p->addr = *addr;
p->next = h->next;
h->next = p;
return 0;
}
int process_chat(linklist_t *h, int skfd, msg_t *msgp, struct sockaddr_in *addr)
{
int ret;
// 遍历链表
linklist_t *p = h->next;
while (p != NULL)
{
if (memcmp(&p->addr, addr, sizeof(*addr)) != 0)
{
ret = sendto(skfd, msgp, sizeof(msg_t), 0, (struct sockaddr *)&p->addr, sizeof(p->addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
}
p = p->next;
}
return 0;
}
int process_quit(linklist_t *h, int skfd, msg_t *msgp, struct sockaddr_in *addr)
{
int ret;
// 拼接文本
sprintf(msgp->text, "quit");
// 遍历链表
linklist_t *p = h->next;
while (p != NULL)
{
if (memcmp(&p->addr, addr, sizeof(*addr)) != 0)
{
ret = sendto(skfd, msgp, sizeof(msg_t), 0, (struct sockaddr *)&p->addr, sizeof(p->addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
}
p = p->next;
}
// 删除登录的客服端地址节点
linklist_t *q;
p = h;
while (p->next != NULL)
{
q = p->next;
if (memcmp(&q->addr, addr, sizeof(*addr)) == 0)
{
p->next = q->next;
free(q);
return 0;
}
p = p->next;
}
return 0;
}
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
msg_t msg;
memset(&msg, 0, sizeof(msg));
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 创建父子进程
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0) // 子进程
{
while (1)
{
msg.type = 'C';
strcpy(msg.name, "server");
printf(">:");
fgets(msg.text, sizeof(msg.text), stdin);
msg.text[strlen(msg.text) - 1] = 0;
ret = sendto(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
}
}
else // 父进程
{
linklist_t *H = link_init();
addr_len = sizeof(&client_addr);
while (1)
{
ret = recvfrom(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&client_addr, &addr_len);
if (ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d msg.type=%c\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port, msg.type);
switch (msg.type)
{
case 'L':
process_login(H, skfd, &msg, &client_addr);
break;
case 'C':
process_chat(H, skfd, &msg, &client_addr);
break;
case 'Q':
process_quit(H, skfd, &msg, &client_addr);
break;
default:
break;
}
}
// 关闭socket
close(skfd);
}
return 0;
}
该段程序实现的是使用多进程实现的一个udp聊天室的服务器端,服务器端用来处理客户端的信息,并下发给聊天室中的所有客户端,实现一个简易的聊天室。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#define Nsize 128
typedef struct
{
char type; // 消息类型L:登录 C:聊天 Q:退出
char name[Nsize]; // 消息名称
char text[Nsize]; // 消息正文
} msg_t;
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int ret;
char buf[Nsize] = {0};
msg_t msg;
memset(&msg, 0, sizeof(msg));
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 登录到服务器
msg.type = 'L';
printf("input your name >:");
fgets(msg.name, sizeof(msg.name), stdin);
msg.name[strlen(msg.name) - 1] = 0;
ret = sendto(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
// 创建父子进程
pid_t pid = fork();
if (pid < 0)
{
perror("fork");
exit(-1);
}
else if (pid == 0) // 子进程->发送聊天文本
{
while (1)
{
printf("input yout text >:");
fgets(msg.text, sizeof(msg.text), stdin);
msg.text[strlen(msg.text) - 1] = 0;
if (strcmp(msg.text, "quit") == 0)
{
msg.type = 'Q';
ret = sendto(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
kill(getppid(), SIGKILL);
exit(0);
}
else
{
msg.type = 'C';
ret = sendto(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("sendto");
exit(-1);
}
}
}
}
else // 父进程->接收服务器下发的消息
{
while (1)
{
addr_len = sizeof(&server_addr);
ret = recvfrom(skfd, &msg, sizeof(msg), 0, (struct sockaddr *)&server_addr, &addr_len);
if (ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s:%s\n",msg.name, msg.text);
}
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是实现的udp聊天室的客户端,子进程向服务器端发送数据,父进程来接收和处理服务器下发的数据。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(&client_addr);
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
// 创建一个监视表
fd_set fds;
while (1)
{
// 清空监视表
FD_ZERO(&fds);
// 添加IO到监视表
FD_SET(0, &fds);
FD_SET(skfd, &fds);
// 开始监视监视表,若有有效IO则立即返回,没有则循环监视
ret = select(skfd + 1, &fds, NULL, NULL, NULL);
if (ret < 0)
{
perror("select");
exit(-1);
}
// 判断有效IO
for (int i = 0; i < skfd + 1; i++)
{
// 判断在监控表中是否有效,有效返回真无效返回假
if (FD_ISSET(i, &fds))
{
if (i == 0)
{
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
printf("readfrom stdin:%s\n", buf);
}
if (i == skfd)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
printf("client ip port:%s %d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
close(newskfd);
}
}
}
}
// 关闭socket
close(skfd);
return 0;
}
该段程序使用select来实现了多路复用IO,监控两个文件的读标准输入和网络通信socket。select:实现多路复用机制,第一个参数所有监控的文件描述符中最大的加一,第二个参数要监控的要读的监控表,第三个参数要监控的要写的监控表,第四个参数要监控的其他监控表,第四个参数超时时间,返回值成功返回可操作的文件个数超时返回0失败返回-1.
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//防止产生僵尸进程
signal(SIGCHLD,SIG_IGN);
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
// 创建子进程
if (fork() == 0)
{
printf("client ip port:%s %d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
while (1)
{
memset(buf,0,Nsize);
ret = recv(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
if (strcmp(buf, "quit") == 0)
break;
printf("recv:%s\n", buf);
strcpy(buf, "server is received!!");
ret = send(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
close(newskfd);
exit(0);
}
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是使用的fork来实现的tcp并发服务器。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(&client_addr);
int newskfd,maxfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
// 创建一个可读的监视表
fd_set fds, tmpfds;
// 清空监视表
FD_ZERO(&fds);
// 添加IO到监视表
FD_SET(skfd, &fds);
maxfd = skfd;
while (1)
{
tmpfds = fds;
// 开始监视监视表,若有有效IO则立即返回,没有则循环监视
ret = select(maxfd + 1, &tmpfds, NULL, NULL, NULL);
if (ret < 0)
{
perror("select");
exit(-1);
}
// 判断有效IO
for (int i = 0; i < maxfd + 1; i++)
{
// 判断在监控表中是否有效,有效返回真无效返回假
if (FD_ISSET(i, &tmpfds))
{
if (i == skfd)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
// 将新的socket添加到监控表中
FD_SET(newskfd, &fds);
//更新最大maxfd
maxfd = (maxfd > newskfd) ? maxfd : newskfd;
}
else
{
ret = recv(i, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
else if (ret == 0)
{
close(i);
FD_CLR(i, &fds);
}
else
{
strcpy(buf, "server is received!!");
ret = send(i, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
}
}
}
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是使用另一种形式来实现的tcp并发服务器,使用的是select多路复用IO。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
int main(int argc, char const *argv[])
{
struct sockaddr_in addr;
if(argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
struct hostent * host = gethostbyname(argv[1]);
if(host == NULL)
{
perror("gethostbyname");
exit(-1);
}
//显示官方主机名
printf("Official name:%s\n",host->h_name);
//显示别名
for(int i = 0;host->h_aliases[i]!=NULL;i++)
{
printf("alises:%s\n",host->h_aliases[i]);
}
//显示ip
for(int i = 0;host->h_addr_list[i]!=NULL;i++)
{
memcpy(&addr.sin_addr,host->h_addr_list[i],host->h_length);
printf("ip:%s\n",inet_ntoa(addr.sin_addr));
}
return 0;
}
该段程序是用来获取的域名的对应信息如该域名的官方主机名别名ip等。gethostbyname:将指定的域名网址转化成对应的ip地址,参数要转化的域名,返回值包含ip等信息的结构体指针。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd, ret;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 获取socket属性中的接收缓存区大小
int recvbuf;
int len = sizeof(recvbuf);
ret = getsockopt(skfd, SOL_SOCKET, SO_RCVBUF, &recvbuf, &len);
if (ret < 0)
{
perror("getsockopt");
exit(-1);
}
printf("1:recvbuf=%d/%dKB\n", recvbuf, recvbuf / 1024);
// 设置socket缓存区大小
recvbuf = 1024 * 200;
ret = setsockopt(skfd, SOL_SOCKET, SO_RCVBUF, &recvbuf, len);
if (ret < 0)
{
perror("setsockopt");
exit(-1);
}
ret = getsockopt(skfd, SOL_SOCKET, SO_RCVBUF, &recvbuf, &len);
if (ret < 0)
{
perror("getsockopt");
exit(-1);
}
printf("1:recvbuf=%d/%dKB\n", recvbuf, recvbuf / 1024);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
printf("client ip port:%s %d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
ret = recv(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
printf("recv:%s\n", buf);
strcpy(buf, "server is received!!\n");
ret = send(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
close(newskfd);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是获取到socket的属性其中的缓存区的大小,并设置其大小。getsocket:获取socket的属性,第一个参数socket文件描述符,第二个参数指定套接字的层次,第三个参数指定控制的方式选项的名称,第四个参数获取到套接字的选项,第五个参数获取到选项的值的大小,返回值成功返回0失败返回-1.setsocket:设置socket的属性,参数与getsocket一致。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len;
int newskfd, ret;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置socket的超时时间
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
ret = setsockopt(skfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
if (ret < 0)
{
perror("setsockopt");
exit(-1);
}
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
//exit(-1);
}
printf("newskfd=%d\n", newskfd);
close(newskfd);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是通过设置socket的属性setsockopt来实现socket的一个超时机制。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/select.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr, client_addr;
socklen_t addr_len = sizeof(&client_addr);
int newskfd;
char buf[Nsize] = {0};
if (argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET; // internet协议
server_addr.sin_port = htons(atoi(argv[2])); // 主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); // 将点分十进制ip转化成网络二进制ip
// 设置端口号
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
// 创建一个监视表
fd_set fds;
//设置超时时间
struct timeval tv;
while (1)
{
// 清空监视表
FD_ZERO(&fds);
// 添加IO到监视表
FD_SET(0, &fds);
FD_SET(skfd, &fds);
tv.tv_sec = 5;
tv.tv_usec = 0;
// 开始监视监视表,若有有效IO则立即返回,没有则循环监视
ret = select(skfd + 1, &fds, NULL, NULL, &tv);
if (ret < 0)
{
perror("select");
exit(-1);
}
else if(ret == 0)
{
printf("超时时间到\n");
}
// 判断有效IO
for (int i = 0; i < skfd + 1; i++)
{
// 判断在监控表中是否有效,有效返回真无效返回假
if (FD_ISSET(i, &fds))
{
if (i == 0)
{
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
printf("readfrom stdin:%s\n", buf);
}
if (i == skfd)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
printf("client ip port:%s %d\n", inet_ntoa(client_addr.sin_addr), client_addr.sin_port);
close(newskfd);
}
}
}
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是使用的select函数中所带有的超时机制来实现socket的超时机制。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#define Nsize 128
void handler (int signum)
{
}
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//超时机制
struct sigaction act;
sigaction(SIGALRM,NULL,&act); //获取信号的原有属性
act.sa_handler = handler; //重新安装信号处理函数
act.sa_flags &= ~SA_RESTART; //重启信号
sigaction(SIGALRM,&act,NULL); //装载信号的新属性
alarm(5);
//创建一个socket
int skfd = socket(AF_INET, SOCK_STREAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
int ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
//设置监听
ret = listen(skfd,10);
if(ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
newskfd = accept(skfd,(struct sockaddr*)&client_addr,&addr_len);
if(newskfd < 0)
{
perror("accept");
//exit(-1);
}
printf("newskfd=%d\n",newskfd);
printf("client ip port:%s %d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port);
close(newskfd);
}
//关闭socket
close(skfd);
return 0;
}
该段程序通过使用捕捉信号的方式来实现出网络通信中的超时检查机制。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
int ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,&addr_len);
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d said:%s\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port,buf);
memset(buf,0,Nsize);
strcpy(buf,"server is received!!");
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,addr_len);
if(ret < 0)
{
perror("sendto");
exit(-1);
}
}
//关闭socket
close(skfd);
return 0;
}
该段程序是服务器设置的广播的接收,可以接收客户端所发的广播信息。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int ret;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//修改socket属性,实现广播功能
int on = 1;//为真,开启广播功能
ret = setsockopt(skfd,SOL_SOCKET,SO_BROADCAST,&on,sizeof(on));
if(ret < 0)
{
perror("setsockopt");
exit(-1);
}
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
while(1)
{
printf(">:");
fgets(buf,Nsize,stdin);
buf[strlen(buf)-1] = 0;
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("sendto");
exit(-1);
}
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,NULL,NULL);//不需要保存服务器返回的结构体地址
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d said:%s\n",inet_ntoa(server_addr.sin_addr),server_addr.sin_port,buf);
}
//关闭socket
close(skfd);
return 0;
}
该段程序是广播的发送客户端,通过修改socket实现广播功能。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_in server_addr,client_addr;
socklen_t addr_len;
int newskfd,ret;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app ip port)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_INET, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//加入多播组
struct ip_mreq mreq;
memset(&mreq,0,sizeof(mreq));
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //设置多播地址
mreq.imr_interface.s_addr = htonl(INADDR_ANY); //任何地址都可以加入多播
ret = setsockopt(skfd,IPPROTO_IP,IP_ADD_MEMBERSHIP,&mreq,sizeof(mreq));
if(ret < 0)
{
perror("setsockopt");
exit(-1);
}
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
server_addr.sin_family = AF_INET; //internet协议
server_addr.sin_port = htons(atoi(argv[2])); //主机字节序转化成网络字节序
server_addr.sin_addr.s_addr = inet_addr(argv[1]); //将点分十进制ip转化成网络二进制ip
//设置端口号
ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,&addr_len);
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s %d said:%s\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port,buf);
memset(buf,0,Nsize);
strcpy(buf,"server is received!!");
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,addr_len);
if(ret < 0)
{
perror("sendto");
exit(-1);
}
}
//关闭socket
close(skfd);
return 0;
}
该段程序是通过设置socket属性来实现多播,加入多播组后就可以等待数据的接收。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_un server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_LOCAL; // 本地协议
strcpy(server_addr.sun_path,argv[1]); // 设置文件名
// 设置文件名
int ret = bind(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("bind");
exit(-1);
}
// 设置监听
ret = listen(skfd, 10);
if (ret < 0)
{
perror("listen");
exit(-1);
}
addr_len = sizeof(&client_addr);
while (1)
{
newskfd = accept(skfd, (struct sockaddr *)&client_addr, &addr_len);
if (newskfd < 0)
{
perror("accept");
exit(-1);
}
printf("newskfd=%d\n", newskfd);
while (1)
{
memset(buf, 0, Nsize);
ret = recv(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
if (strcmp(buf, "quit") == 0)
break;
printf("%s\n",buf);
printf(">:");
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
ret = send(newskfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
}
close(newskfd);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是使用的流式套接字机制来实现的进程间通信的服务器端。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_un server_addr, client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if (argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
// 创建一个socket
int skfd = socket(AF_LOCAL, SOCK_STREAM, 0);
if (skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n", skfd);
// 设置结构体内容
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sun_family = AF_LOCAL; // 本地协议
strcpy(server_addr.sun_path,argv[1]); // 设置文件名
// 链接服务器
int ret = connect(skfd, (const struct sockaddr *)&server_addr, sizeof(server_addr));
if (ret < 0)
{
perror("connect");
exit(-1);
}
while (1)
{
// 发送接收数据
printf(">:");
fgets(buf, Nsize, stdin);
buf[strlen(buf) - 1] = 0;
ret = send(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("send");
exit(-1);
}
if (strcmp(buf, "quit") == 0)
break;
memset(buf, 0, Nsize);
ret = recv(skfd, buf, Nsize, 0);
if (ret < 0)
{
perror("recv");
exit(-1);
}
printf("%s\n", buf);
}
// 关闭socket
close(skfd);
return 0;
}
该段程序是使用的流式套接字机制来实现的进程间通信的客户端,客户端也要通过bind来绑定端口否则不能接收数据。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_un server_addr,client_addr;
socklen_t addr_len;
int newskfd;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app send recv)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_LOCAL, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
memset(&client_addr,0,sizeof(client_addr));
server_addr.sun_family = AF_LOCAL; //本地协议
strcpy(server_addr.sun_path,argv[1]); //设置文件名
//绑定文件
int ret = bind(skfd,(const struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
addr_len = sizeof(&client_addr);
while(1)
{
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,&addr_len);
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("buf=%s\n",buf);
memset(buf,0,Nsize);
strcpy(buf,"server is received!!");
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&client_addr,addr_len);
if(ret < 0)
{
perror("sendto");
exit(-1);
}
}
//关闭socket
close(skfd);
return 0;
}
该段程序实现了用户数据报套接字的服务器,修改对应结构体可以实现。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/un.h>
#define Nsize 128
int main(int argc, char const *argv[])
{
struct sockaddr_un server_addr,client_addr;
socklen_t addr_len;
int ret;
char buf[Nsize] = {0};
if(argc != 3)
{
printf("运行时请带入参数(./app send recv)\n");
exit(-1);
}
//创建一个socket
int skfd = socket(AF_LOCAL, SOCK_DGRAM,0);
if(skfd < 0)
{
perror("socket");
exit(-1);
}
printf("skfd=%d\n",skfd);
//设置结构体内容
memset(&server_addr,0,sizeof(server_addr));
memset(&client_addr,0,sizeof(client_addr));
server_addr.sun_family = AF_LOCAL; //本地协议
strcpy(server_addr.sun_path,argv[1]); //设置文件名
client_addr.sun_family = AF_LOCAL; //本地协议
strcpy(client_addr.sun_path,argv[2]); //设置文件名
//绑定文件
ret = bind(skfd,(const struct sockaddr*)&client_addr,sizeof(client_addr));
if(ret < 0)
{
perror("bind");
exit(-1);
}
while(1)
{
printf(">:");
fgets(buf,Nsize,stdin);
buf[strlen(buf)-1] = 0;
ret = sendto(skfd,buf,Nsize,0,(struct sockaddr*)&server_addr,sizeof(server_addr));
if(ret < 0)
{
perror("sendto");
exit(-1);
}
memset(buf,0,Nsize);
ret = recvfrom(skfd,buf,Nsize,0,NULL,NULL);//不需要保存服务器返回的结构体地址
if(ret < 0)
{
perror("recvfrom");
exit(-1);
}
printf("%s\n",buf);
}
//关闭socket
close(skfd);
return 0;
}
该段程序实现了用户数据报套接字的客户端。
3.数据库
这里我们来了解的sqlite数据库,SQLite数据库采用了模块化设计,由8个独立的模块构成,这些独立模块又构成了三个主要的子系统,模块将复杂的查询过程分解为细小的工作进行处理。我们先来看如何使用命令来操作一个数据库。
cpp
linux@ubuntu:~/work/02-linuxapp$ sqlite3 my.bd
SQLite version 3.37.2 2022-01-06 13:25:41
Enter ".help" for usage hints.
sqlite> create table student(number int,name char,sex char,age int,score float);
sqlite> .scheam
Error: unknown command or invalid arguments: "scheam". Enter ".help" for help
sqlite> .schema
CREATE TABLE student(number int,name char,sex char,age int,score float);
sqlite> .database
main: /home/linux/work/02-linuxapp/my.bd r/w
sqlite> create table teacher(number int,name char,sex char,age int,score float);
sqlite> .schema
CREATE TABLE student(number int,name char,sex char,age int,score float);
CREATE TABLE teacher(number int,name char,sex char,age int,score float);
sqlite> .tables
student teacher
sqlite> drop table teacher
...> ;
sqlite> .tables
student
sqlite> insert into student values(1,
...> 'zhao','male',28,92.5);
sqlite> select * from student
...> ;
1|zhao|male|28|92.5
sqlite> insert into student values(2,'liu','female',22,89.5);
sqlite> select * from student;
1|zhao|male|28|92.5
2|liu|female|22|89.5
sqlite> select * from student where number=1;
1|zhao|male|28|92.5
sqlite> delete from student where number=1;
sqlite> select * from student
...> ;
2|liu|female|22|89.5
sqlite> updata student set score=88 where number=2;
Error: in prepare, near "updata": syntax error (1)
sqlite> update student set score=88 where number=2;
sqlite> select * from student
...> ;
2|liu|female|22|88.0
sqlite> alter table student add column telephone char;
sqlite> .schema
CREATE TABLE student(number int,name char,sex char,age int,score float, telephone char);
sqlite> .quit
sqlite3:创建或打开一个数据库文件。create table :创建一个表,在创建数据库文件后一定要创建一个表,若没有创建直接退出数据库文件是不会被创建的。.schema:查看表的结构。.database:查看所打开的数据库文件。.tables:查看该数据库下的所有表。drop table :删除一个表。insert into:向表中添加新行。select * from:显示表中的所有行。select * from where:查看指定内容的行。delete from where :删除指定内容的行。update set where :修改指定内容行中的指定内容。alter table add column :在表中添加字段。.quit :退出该数据库文件。
接下来我们来看看使用程序来操作数据库:
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
int main(int argc, char const *argv[])
{
sqlite3 *db;
if(argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
//打开或创建一个数据库
int ret = sqlite3_open(argv[1],&db);
if(ret != SQLITE_OK)
{
printf("%s\n",sqlite3_errmsg(db)); //错误处理
}
//关闭一个数据库
sqlite3_close(db);
return 0;
}
该段程序是打开了一个数据库文件后关闭了该数据库文件。sqlite3_open :打开或创建一个数据库文件,第一个参数要打开或创建的数据库文件名,第二个参数该指针保存打开数据库文件的文件描述符。sqlite3_errmsg:获取到错误提示,参数数据库文件描述符,返回值错误信息字符串。sqlite3_close:关闭一个数据库文件,参数数据库文件描述符。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
int callback(void *arg, int f_num, char **f_value, char **f_name)
{
if(*(int*)arg == 1)
{
for(int i = 0;i<f_num;i++)
{
printf("|%s",f_name[i]);
}
printf("|\n");
*(int*)arg = 0;
}
for(int i = 0;i<f_num;i++)
{
printf("|%s",f_value[i]);
}
printf("|\n");
return 0;
}
int main(int argc, char const *argv[])
{
sqlite3 *db;
char sql[128] = {0};
char *errmsg;
if(argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
//打开或创建一个数据库
int ret = sqlite3_open(argv[1],&db);
if(ret != SQLITE_OK)
{
printf("%s\n",sqlite3_errmsg(db)); //错误处理
exit(-1);
}
//增加数据
sprintf(sql,"insert into student values(%d,'%s','%s',%d,%f);",1,"zhao","male",18,90.5);
printf("sql=%s\n",sql);
ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
printf("%s\n",errmsg); //错误处理
exit(-1);
}
//删除数据
sprintf(sql,"delete from student where number=%d;",5);
printf("sql=%s\n",sql);
ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
printf("%s\n",errmsg); //错误处理
exit(-1);
}
//修改数据
sprintf(sql,"update student set score=80 where number=%d;",1);
printf("sql=%s\n",sql);
ret = sqlite3_exec(db,sql,NULL,NULL,&errmsg);
if(ret != SQLITE_OK)
{
printf("%s\n",errmsg); //错误处理
exit(-1);
}
//查看数据库
int arg =1;
sprintf(sql,"select * from student;");
printf("sql=%s\n",sql);
ret = sqlite3_exec(db,sql,callback,&arg,&errmsg);
if(ret != SQLITE_OK)
{
printf("%s\n",errmsg); //错误处理
exit(-1);
}
//关闭一个数据库
sqlite3_close(db);
return 0;
}
该段程序实现了数据库中的增删改查。sqlite3_exec:执行一个数据库语句,第一个参数数据库文件描述符,第二个参数要执行的数据库语句字符串,第三个参数回调函数指针,第四个参数回调函数书所需要的参数,第四个函数存放错误信息的地址空间。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>
int callback(void *arg, int f_num, char **f_value, char **f_name)
{
if (*(int *)arg == 1)
{
for (int i = 0; i < f_num; i++)
{
printf("|%s", f_name[i]);
}
printf("|\n");
*(int *)arg = 0;
}
for (int i = 0; i < f_num; i++)
{
printf("|%s", f_value[i]);
}
printf("|\n");
return 0;
}
int process_insert(sqlite3* db)
{
char sql[128*2] = {0};
char *errmsg;
int number,age;
float score;
char name[64] = {0},sex[20] = {0};
printf("请输入学生的学号>:");
scanf("%d",&number);
printf("请输入学生的姓名>:");
scanf("%s",name);
printf("请输入学生的性别>:");
scanf("%s",sex);
printf("请输入学生的年龄>:");
scanf("%d",&age);
printf("请输入学生的成绩>:");
scanf("%f",&score);
sprintf(sql, "insert into student values(%d,'%s','%s',%d,%f);", number, name, sex, age, score);
printf("sql=%s\n", sql);
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("%s\n", errmsg); // 错误处理
exit(-1);
}
}
int process_delete(sqlite3* db)
{
char sql[128] = {0};
char *errmsg;
int number;
printf("请输入要删除学生的学号>:");
scanf("%d",&number);
sprintf(sql, "delete from student where number=%d;", number);
printf("sql=%s\n", sql);
int ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
if (ret != SQLITE_OK)
{
printf("%s\n", errmsg); // 错误处理
exit(-1);
}
}
int process_show(sqlite3 *db)
{
char sql[128] = {0};
char *errmsg;
int arg = 1;
sprintf(sql, "select * from student;");
printf("sql=%s\n", sql);
int ret = sqlite3_exec(db, sql, callback, &arg, &errmsg);
if (ret != SQLITE_OK)
{
printf("%s\n", errmsg); // 错误处理
exit(-1);
}
return 0;
}
int main(int argc, char const *argv[])
{
sqlite3 *db;
char sql[128] = {0};
char *errmsg;
int num;
if (argc != 2)
{
printf("运行时请带入参数(./app filename)\n");
exit(-1);
}
// 打开或创建一个数据库
int ret = sqlite3_open(argv[1], &db);
if (ret != SQLITE_OK)
{
printf("%s\n", sqlite3_errmsg(db)); // 错误处理
exit(-1);
}
while (1)
{
printf("**********************************************\n");
printf("**1.增加数据 2.删除数据 3.查看数据 4.退出程序**\n");
printf("**********************************************\n");
printf(">:");
scanf("%d", &num);
switch (num)
{
case 1:
process_insert(db);
break;
case 2:
process_delete(db);
break;
case 3:
process_show(db);
break;
case 4:
sqlite3_close(db);
exit(0);
break;
default:
break;
}
}
return 0;
}
该段程序是使用数据库来实现一个基本的学生信息管理系统,实现了查看学生信息,增加学生信息和删除学生信息的功能。