网络编程总结

Day1:

  1. 从零开始设计一个网络

如果要实现两台主机通信,怎么做?

如果要实现五台主机通信,怎么做?

缺点:隐私低。效率低。

MAC地址:48位(全球唯一地址),不好记

五类IP地址:

A类网络的地址范围:1.0.0.0 ~ 127.255.255.255

B类网络的地址范围:128.0.0.0 ~ 191.255.255.255

C类网络的地址范围:192.0.0.0 ~ 223.255.255.255

D类网络的地址范围:224.0.0.0 ~ 239.255.255.255

E类网络的地址范围:240.0.0.0 ~ 255.255.255.255

判断流程:

网段:主机和子网掩码&操作,结果为网段,网段一样即可通信。

若不一样,引入网关进行通信。(路由器会存入192.168.1.1和192.168.0.1等网络接口。)

  1. Internet的历史

  1. OSI参考模型和TCP/IP协议

网络协议:网络通信过程中,通信双方所共同遵从的约定。

网络体系结构:网络的层次结构和每层所使用协议的集合。

  1. TCP/IP协议族

IP分片的过程:

MTU=IP头+TCP头+APP头

MSS=APP头+User data

  1. TCP和UDP协议

TCP是面向连接的,可靠的传输层协议

UDP是无连接的,不保证可靠的传输层协议

TCP的三次握手:

TCP的四次挥手:

TCP可靠性如何保证:

  1. 预备知识

Socket(插座):

IP:地址

3)端口号:

区分同一个主机上的不同进程

TCP和UDP的端口号允许一样

字节序:

主机字节序:不同CPU架构的主机,在内存中存储多字节数字的方式,分为大端字节序和小端字节序。

  1. 系统调用

  1. 创建套接字

Socket:

  1. 绑定IP地址和端口号

  1. 设置监听套接字(把主动套接字改为被动套接字)

通常写5

listen()

4)等待接受客户端的连接

5)客户端连接服务器

6)发送消息

Send:

7)接收消息

Recv

8)关闭套接字:

9)基于TCP协议的服务器和客户端

Day2

  1. 抓包

  1. 安装软件

Sudu apt-get install wireshark

2)启动 wireshark

Sudo wireshark

3)抓包

  1. TCP程序优化
    ./client 192.168.50.128 5001

Argc = 3

Argv[0] = “./client”

Argv[1] = “192.168.50.128”

Argv[2] = “5001”

服务器优化代码:

客户端优化代码:

3.基于UDP协议的服务器和客户端

  1. UPD协议:

UDP是无连接的,不保证可靠性的传输层协议。

UDP为啥不可靠:

  1. UDP协议头中没有序列号和确认序列号,没有消息确认机制,无法确认对端是否收到本端发送的消息。

  1. UDP效验和允许关闭。

UDP的使用场景:

  1. 对于可靠性要求不高,对于实时性要求高的场景适合使用UDP,比如视频聊天,语音聊天

  1. 广播和组播场景只能使用UDP。

  1. 发送小尺寸数据(如对DNS服务器进行IP地址查询时)

如果想用UDP协议,还要保证可靠性,在怎么做?

应用层自己做消息的响应机制。

  1. UDP服务器和客户端

Ssize_t sendto(int socket, void *message,size_t length,int flags,struct sockaddr *dest_addr, socklen_t dest_len);

功能:发送消息

参数1:套接字的文件描述符

参数2:发送缓冲区地址

参数3:发送消息的长度

参数4:发送方式,一般填0

参数5:发送的目的地址和端口

参数6:发送的目的地址结构的长度

Ssize_t recvfrom(int socket,void *buffer,size_t length,int flags,struct sockaddr *address, socklen_t *address_len);

功能:接收消息

参数1:套接字的文件描述符

参数2:接受缓冲区的地址

参数3:接受缓冲区的长度

参数4:接受方式 0代表阻塞接受

参数5:从哪个地址和端口接受

参数6:参数5地址结构的长度

4.IO模型

  1. 阻塞IO

对于发送函数:如果发送缓冲区不足,发送函数就会阻塞不返回。

对于接受函数:如果对端不发送消息,接受函数就会阻塞不返回。

优点:简单、常用。

缺点:效率低/ 如果IO通道损坏,那么进程会阻塞等待。

  1. 非阻塞IO

While(1)

{

Ret = recv();

If(ret < 0 && ret == EAGAIN)

{

Continue;

}

//处理读取的消息内容

}

对于接受函数:不断读取消息内容,如果对端没有发送消息,返回错误,需要继续读取。

对于发送函数:发送缓冲区不足,会返回错误,需要继续发送。

优点:可以防止进程阻塞在IO操作上。

缺点:极浪费CPU资源。

  1. 信号驱动IO

void sigFunc(int signo);

{

Recv(); //主要在收消息

}

Signal(SIGIO,sigFunc);

  1. IO多路复用

Linux默认情况下一个进程做多能打开1024个文件,对应1024个文件描述符。

文件描述符的特点:

①文件描述符是非负整数

②文件描述符一般都是从小到大分配的

③进程启动的时候,默认会分配三个文件描述符,0,1,2.

IO多路复用不止针对套接字文件描述符,也针对普通的文件描述符。

IO多路复用的3种实现方式:

①select(3种最简单)

Int select (int n,fd_set *read_fds,fd_set *write_fds,fd_set *except_fds,struct timeval *timeout);

Select IO 多路复用的思想,分为3步:

①创建一个文件描述符集合,集合里有1024个bit位,每个bit位代表一路IO通道的文件描述符。如果关注该文件描述符,就将该文件描述符加入文件描述符集合,将文件描述符集合里对应该文件的bit位置1,其他bit位置0.

②调用select函数监控文件描述符集合,如果关注的文件描述符里IO通道对应的文件描述符上有数据发生,将该文件描述符对应的bit位置1,其余bit位置0,返回有数据发生的文

件描述符的数量。如果关注的文件描述符上都没有数据发生,select函数阻塞不返回。

③遍历文件描述符集合里关注的文件描述符,用FD_ISSET判断文件描述符对应的IO通道上是否有数据发生,如果FD_ISSET返回1代表文件描述符对应的IO通道上有数据发生,处理该IO通道上的数据。

②poll

③epoll(最复杂)

Day3:

  1. 服务器模型

  1. 循环服务器

①TCP循环服务器

服务器一次只能接入一个客户端,处理一个客户端的消息,该客户端如果不退出,其他客户端无法接入。(不常用)。

listenFd = socket();

Bind(listenFd,...);

Listen(listenFd,....);

While(1)

{

connFd = accept(listenFd,...);

While(1)

{

Recv(connFd,...);

Process();

Send(connFd,...);

}

}

②UDP循环服务器

只要处理每个客户端消息的时间不长,服务器可以同时处理多个客户端的请求。UDP循环服务器可以使用。

sockFd = socket();

Bind(sockFd);

While(1)

{

Recvfrom(sockFd,...);

Process();

Sendto(sockFd,...);

}

  1. 并发服务器

TCP多线程并发服务器:

客户端接入服务器后,服务器为客户端分配单独的线程,为该客户端提供服务。

TCP多进程并发服务器:

客户端接入服务器后,服务器为客户端分配单独的进程,为该客户端提供服务。

  1. IO多路复用服务器

在服务器对每个客户端消息处理时间都不长的情况下,可以使用IO多路复用服务器。

  1. 网络超时检测

①设置套接字属性

Struct timeval tv;

Tv.tv_sec = 5; //单位是秒,设置5秒时间

Tv.tv_usec = 0; //单位是微秒

Setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(tv));//设置接受超时

Recv()/recvfrom() //从socket读取数据

1秒 = 1000毫秒 = 10^6微秒

②select超时检测

Int select(int nfds,fd_set *readfds,fd_set *writefds, fd_set *exceptfds,struct timeval *timeout);

Struct fd_set rdfs;

Struct timeval tv = {5,0}; //设置5秒时间

返回值:

小于0,代表select出错

等于0,代表select超时返回

大于0,代表select检测到文件描述符上有数据发生

③用信号触发超市检测

Alarm是一个闹钟函数,在指定时间超时后会触发SIGALRM信号。

如果给信号设置SA_RESTART,慢系统调用被该信号打断后,慢系统调用会自动重启, 然后不会返回。

如果清楚信号的SA_RESTART,慢系统调用被该信号打断后,慢系统调用会返回出错,errno是EINTR。

Int sigaction(int signum,const struct sigaction *act, struct sigaction *oldact);

参数1:信号

参数2:要设置的新的信号处理方式

参数3:原来老的信号处理方式

Void handler(int signo)

{

Reuturn;

}

Struct sigaction act;

Sigaction(SIGALRM,NULL,&act); //获取SIGALRM老的信号处理方式

Act.sa_handler = hadler; //设置信号处理回调函数

Act.sa_flags & = ~SA_RESTART; //清除SA_RESTART标志位

Sigaction(SIGALRM,&act,NULL); //设置SIGALRM新的信号处理方式

Alarm(5);

If(recv(....) < 0)......

  1. 广播

我们之前学到过消息的发送方式,都是单一的消息接收方,这种消息发送方式称为单播。

广播是主机发送的消息,局域网内所有主机都能收到的消息发送方式。

广播必须使用UDP编程。

网段内,主机号最大的地址是广播地址。比如:192.168.1.0/24网段内,广播地址是192.168.1.255。

所有网段的广播地址:255.255.255.255

发送方:

接收方:

Day4:

  1. 文件上传和下载

命令#文件名#文件长度

文件上传:put#1.txt#555

文件下载:get#1.txt

  1. 组播

组播是一台主机发送消息,只有加入多播组的主机才能收到消息。

组播必须使用UDP实现。

组播地址:224.0.0.0~239.255.255.255(除去网络地址和广播地址)

发送方:

接收方:

  1. unix域套接字

unix域套接字用于本地进程间通信,通信效率仅次于共享内存,由于共享内存通常需要配合信号量做共享资源的同步和互斥,unix域套接字用起来通常比共享内存要好用。

使用AF_UNIX或者AF_LOCAL创建套接字。

unix域套接字既可以用SOCK_STREAM,也可以用SOCK_DGRAM。

客户端:

服务器:

  1. 数据库

数据:能够输入计算机并能被计算机程序识别和处理的信息集合。

数据库:在数据库管理系统管理和控制之下,存放在存储介质上的数据集合。

数据库相对文件的优点:

  1. 文件里存储的是字符串或者二进制数据,不是结构化的数据。读取文件里的数据,需要读取并解析整个文件,效率低。

  1. 程序和文件之间缺乏高度独立性。

SQLite数据库是一个用C语言写的数据库,是一个轻量级的嵌入式数据库。

SQLite有以下特性:

零配置一无需安装和管理配置;

储存在单一磁盘文件中的一个完整的数据库;

数据库文件可以在不同字节顺序的机器间自由共享;

支持数据库大小至2TB;

足够小,全部源码大致3万行c代码,250KB;

比目前流行的大多数数据库对数据的操作要快;

SQLite3相关网站:

官网:https://www.sqlite.org/index.html

菜鸟教程:https://www.runoob.com/sqlite/sqlite-c-cpp.html

SQLite3的数据类型:

SQLite3的约束:

SQLite3软件安装:

  1. 安装SQLite3命令行工具

sudo apt-get install sqlite3

  1. 安装SQLite3的开发库

sudo apt-get install libsqlite3-dev

SQLite3的系统命令:

SQLite3的系统命令也叫点命令,命令是以点开头

  1. 打开数据库,书库不存在则创建数据库

sqlite3 数据库文件名

例如:sqlite3 test.db

  1. 查询数据库帮助信息

.help

  1. 查询数据库的表

.tables

  1. 查询数据库文件的路径

.databases

  1. 查询数据库表的创建语句

.schema

  1. 退出数据库

.quit

.exit

SQL语句:

SQL语句不以点开头,要以分号结尾。

  1. 创建表

create table 表名(字段1 类型 约束, 字段2 类型 约束, …);

create table stu(id integer primary key not null, name text not null, age integer);

  1. 插入表记录

insert into 表名 values(字段1的值, 字段2的值, …);

insert into stu values(1001, 'zhangsan', 20);

insert into 表名(字段1, 字段n,…) values(字段1的值, 字段n的值,…);

insert into stu(id, name) values(1002, 'lisi');

  1. 查询表记录

select * from 表名;

select * from stu;

select 字段m, 字段n … from 表名;

select id, name from stu;

select * from 表名 where 查询条件;

select * from stu where id=1001;

select * from stu where id=1001 or name='lisi';

select * from stu where id=1001 and name='zhangsan';

  1. 更新表记录

update 表名 set 字段m=字段m的新值, … where 查询条件;

update stu set name='wangwu', age=21 where name='lisi';

  1. 删除表记录

delete from 表名 where 查询条件;

delete from stu where name='wangwu';

  1. 删除表

drop table 表名;

drop table stu;

  1. 插入表字段

alter table 表名 add column 字段 类型;

alter table stu add column score integer;

  1. 删除表字段

SQLite3不支持直接删除表字段,可以通过创建临时表改名成原表表名的方式删除表字段。

create table 临时表名 as select 字段m, 字段n, … from 原表名;

drop table 原表名;

alter table 临时表名 rename to 原表名;

create table stu1 as select id, name, score from stu;

drop table stu;

alter table stu1 rename to stu;

SQLite3的编程接口:

  1. int sqlite3_open(char *path, sqlite3 **db);

功能:打开数据库,如果数据库不存在则创建数据库

参数1:数据库文件的路径(包含数据库文件名)

参数2:指向数据库句柄的指针

返回值:成功返回0(SQLITE_OK),失败返回错误码

  1. int sqlite3_close(sqlite3 *db);

功能:关闭数据库

参数1:数据库的句柄

返回值:成功返回0(SQLITE_OK),失败返回错误码

  1. int sqlite3_exec(sqlite3 *db, const char *sql, sqlite3_callback callback, void *, char **errmsg);

功能:执行SQL操作

参数1:数据库的句柄

参数2:SQL语句

参数3:回调函数,用于返回SQL查询语句的查询结果

参数4:传递给sqlite3_callback回调函数的参数

参数5:错误信息

返回值:成功返回0(SQLITE_OK),失败返回错误码

typedef int (*sqlite3_callback)(void *para, int f_num, char **f_value, char **f_name);

功能:返回SQL语句查询结果,每找到一条记录,返回一次查询结果

参数1:传递给回调函数的参数

参数2:查询结果中字段的数目

参数3:包含每个字段值的指针数组

参数4:包含每个字段名称的指针数组

返回值:成功返回0,失败返回-1

  1. int sqlite3_get_table(sqlite3 *db, const char *sql, char ***resultp, int *nrow, int *ncolumn, char **errmsg);

功能:执行SQL操作

参数1:数据库的句柄

参数2:SQL语句

参数3:用来指向SQL语句执行结果的指针

参数4:满足条件的记录的数目

参数5:每条记录包含的字段数目

参数6:错误信息

返回值:成功返回0(SQLITE_OK),失败返回错误码

  1. const char *sqlite3_errmsg(sqlite3 *db);

功能:获取错误信息

参数1:数据库的句柄

返回值:返回错误信息

  1. void sqlite3_free(void *errmsg);

功能:释放错误信息

参数1:错误信息指针

  1. void sqlite3_free_table(char **result);

功能:释放用sqlite3_get_table函数查询到的结果

参数1:用sqlite3_get_table函数查询到的结果

Day5:

  1. 学生信息管理系统

表设计:

stu

字段设计:

id:学号

name:姓名

score:成绩

功能设计:

插入学生记录

更新学生记录

查询学生记录

删除学生记录

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值