网络编程概况

文章介绍了网络的基础知识,包括网络的分层结构如OSI七层和TCP/IP四/五层模型,各种协议如TCP、UDP的应用,以及IP地址、端口、域名等概念。还探讨了TCP的三次握手和四次挥手过程,以及不同IO模型如阻塞、非阻塞和多路复用。此外,提到了广播、组播的概念以及数据库操作的基本流程。
摘要由CSDN通过智能技术生成

网络编程
    网络基础
    TCP/UDP通信
    IO模型
    服务器搭建
    广播、组播
    网络超时
    Unix通信    
    数据库
    项目
        点菜宝
        医院排队叫号
        售票
        超市收银        
今天的内容
网络基础
    网络的历史:战争的产物
    分层结构 *****
        OSI七层 : 应用层、表示层、会话层、传输层、网络层、数据链路层、物理层
        TCP/IP四层:应用层、传输层、网络层、网络接口层
        TCP/IP五层:应用层、传输层、网络层、数据链路层、物理层
    协议: 
        应用层:http, DNS, FTP, TFTP, SMTP, telnet
        传输层:TCP、UDP 
        网络层:IP、ICMP、IGMP
        网络接口层:ARP
    地址:
        mac/HWaddr: 硬件地址,一般不可以改。
        IP地址:IPV4是32位的数,点分十进制,可改。由网段+主机号构成。
            A类:1.0.0.1 ~ 126.255.255.255(政府)
            B类:128.0.0.1 ~ 191.255.255.255 (公司)
            C类:192.0.0.1 ~ 223.255.255.255 (公用)
            D类:224.0.0.1 ~ 239.255.255.255 (多播)
            E类:保留地址
        广播地址:某个网段内主机号最大的就是广播地址。
        子网掩码:IP & mask = 网段 ;IP &(~mask) = 主机号
        域名:
            www.baidu.com
    PORT:16bit,范围:0~65535
        http:80, SMTP:23, FTP:20和21, tomcat:8080, TFTP:69, VNC:5800和5900 ... ...
        自己的程序推荐端口号>50000
    封包和解包
        rawData: 表示的是用户想发的消息。
        以太网头(协议+目的和源mac地址 ) | 网络层头(协议+目的和源ip地址) | 传输层头(协议+目的和源port) | 应用层头 | rawData | CRC(校验)
    小结:
        网络是一个分层结构,每一层使用下一层提供内容为上一层进行服务。
        网络上的进程进行通信的三要素
            IP地址 协议 PORT 
TCP协议特点 *****
    类比:打电话
    建立连接,可靠性高,速度慢。
UDP协议特点 *****
    类比:发短信
    不需要建立连接,可靠性不高,速度快。
    应用:
        银行的业务,网络游戏(购买装备,打怪兽),在线看视频,网课
TCP三次握手 *****
    建立连接的过程
    1. 客户端发送连接请求(拨号)
    2. 服务器回应(接电话,说:你好!)
    3. 客户端确认连接(说:你好,我是张三)
TCP四次挥手 *****
    断开连接的过程
    1. 服务器发送断开请求(说:好,今天就聊天这)
    2. 客户端回应收到断开请求(说:好的!)
    3. 客户端发送断开请求(说:拜拜~)
    4. 服务器回应收到断开请求(说:拜拜~)
预备知识 
    socket 
        套接字 一种特殊的文件描述符 整型  >=0
        分类 
            流式套接字 (SOCK_STREAM面向连接TCP)
            数据报套接字 (SOCK_DGRAM面向无连接UDP)
            原始套接字(SOCK_RAW)
    字节序
        小端序:
            低字节存放在低位,比如:intel/AMD
        大端序:
            高字节存放在低位,比如:ARM/网络
            一个整型由四个字节构成,0x0a0b0c0d
tcp通信
    掌握通信流程 ***    

注意:
    bind:一个套接字描述符,只能用一个端口号

UDP通信
        服务器                         客户端 
    创建用户数据报套接字           创建用户数据报套接字
    绑定自己的ip/port              //绑定自己的ip/port    INADDR_ANY
    通信                           通信 
    关闭套接字                     关闭套接字
IO模型
    阻塞
        例:tcp服务器accept接受连接是阻塞、tcp接收消息是阻塞、UDP接收消息、标准输入
    非阻塞
        例:标准输出
    多路复用
        理解select原理
            1. 应用程序准备一张保存描述符的表 fd_set  readFds;
            2. 应用程序把所有想要监听的描述符都放在表里 FD_SET(fd, &readFds);
            3. 应用程序调用select(),//此时,会将readFds拷贝一份给内核
            4. //内核轮询描述符的表中的每一个描述符,查看哪一个描述符可以进行IO操作。
            5. //直到某一个或者某几个描述符可以进行IO操作时,内核将不能操作的描述符从表中删除
            6. select()返回//内核将新表返回给应用程序
            7. 应用程序轮询描述符的表,如果某个描述符在表中,也就是说它可以进行IO操作,这时操作不会阻塞
        问题:
            1. 表有多大,最多能放多少个描述符
                sizeof( readFds ) = sizeof( fd_set.__fds_bits )
                = (1024 / __NFDBITS) * sizeof(long)
                = 1024 / 8
                = 128(byte)
                = 1024(bit)
                答:表的大小是128byte,也就是1024bit。最多可以放1024个描述符,0~1023。
                //将描述符值对应的bit置1表示在表里,清0表示不在表里。
            2. 有两次表的拷贝,多次轮询,如何提交效率?
                答:记录当前表中描述符最大值maxFd,只需要轮询0~maxFd这些描述符,总共轮询maxFd+1。
            
            /* fd_set for select  */
            typedef struct
            {
                long int __fds_bits[1024 / __NFDBITS];                
            } fd_set;
            
            __NFDBITS = 8 * sizeof(unsigned long)            
            
    信号驱动
        周末中午饿了才去吃饭。---饿就是一个信号,吃饭就是一个行为。

    //将newID改为非阻塞
    int flag = 0;
    flag = fcntl( newID, F_GETFL, 0 ); //获取操作方式
    flag |= O_NONBLOCK;
    fcntl(  newID, F_SETFL, flag );//设置新的操作方式
循环服务器
    socket + bind + listen
    while(1)
    {
        accept(...);
        while(1)
        {
            recv(...);
            send(...);
        }
        close();
    }
    close();
    总结:
        前一个客户端不结束,服务器无法连接下一个客户端。用户体验差。

多路复用
        select/epoll/poll
        多路复用在哪里用
            当一个进程中有多个阻塞时,可以考虑使用多路复用。
            例:10086
        select原理
            1. 首先创建一张保存阻塞描述符的表 fd_set readFds;
            2. 把所有准备监听的描述符放在表中 FD_SET( fd, &readFds );
            3. 调用select函数,此时,应用程序会将表拷贝到内核
            4. 内核轮询表中描述符对应的文件,查看哪个文件可以进行IO操作,
               如果有某个或者某几个文件可以进行IO操作时,就会修改表,只保留可以进行IO操作的描述符,
               然后,通过select将表返回,保存在readFds
            5. 应用程序轮询readFds,判断哪个文件可以进行IO操作,然后进行操作。
        select特点
            1. 表在用户空间和内核空间来回拷贝
            2. 表在用户空间和内核空间进行轮询
            3. 表是1024bit的大小,能保存的描述符范围0~1023
            4. 为了提高效率,select第一个参数是表中最大描述符加1,轮询的范围0~最大描述符
服务器模型
    客户端1可以和服务器通信,客户端2可以和服务器通信,在此中间不需要重启服务器。    
    1. 循环服务器
            TCP循环服务器        
        创建流式套接字        
        绑定自己的ip/port         
        监听 --> 等连接套接字    
        while (1)
        { 
            接受连接,返回已连接的套接字    
            while(1)
            { 
                用已连接套接字接收消息        
                用已连接套接字回复消息
                //某些情况下,跳出循环
            }    
        }
        关闭套接字(等连接套接字和已连接套接字)
        
            TCP循环服务器    
        socket + bind + listen
        while(1)
        {
            accept(...);
            while(1)
            {
                recv(...);
                send(...);
            }
            close();
        }
        close();
        小结:
            TCP循环服务器一次只能和一个客户端通信,只有前一个客户端通信结束后,才能和下一个客户端通信。    TCP服务器一般很少采用循环服务器模型。        
            UDP循环服务器          
        创建数据报套接字        
        绑定自己的ip/port
        while(1)
        {
            接收消息 
            回复消息
        }
        关闭套接字
        小结:
            UDP循环服务器可以同时和多个客户端通信。
    2. 并发服务器
            UDP并发服务器          
        创建数据报套接字        
        绑定自己的ip/port
        创建管道
        创建子进程 
                while (1)//子进程
                {
                    接收消息 recvfrom(来源地址) 
                    把地址放在管道中
                    把处理结果放在管道中
                }
        父进程 
        while(1)
        {
            从管道中拿出目的地址
            从管道中得到处理结果 
            回复消息   sendto(处理结果,目的地址)
        }
        关闭套接字
        小结:
            UDP的并发服务器复杂,效率低,一般不使用。
            
            TCP并发服务器
        创建流式套接字
        绑定自己的ip/port 
        监听 --> 等连接套接字
        while(1)
        {
            接受连接,返回已连接的套接字
            创建进程/线程来实现通信
                while(1) //子进程/子线程
                {
                    用已连接套接字接收消息
                    用已连接套接字回复消息
                }
                关闭套接字(已连接套接字)
        }
        关闭套接字(等连接套接字)
        
        小结:tcp的并发服务器可以实现一次来处理多个客户端通信。
            客户端越多,线程/进程会越多,cpu可能会比较卡顿。
    3. 多路复用服务器
网络超时
    在tcp通信中的accept/recv以及udp通信中的recvfrom是阻塞操作。
    如果不设置超时时间,那么,会一直阻塞下去。
    如果设置超时时间,那么,在给定时间内等待消息,超时直接返回。
    
    三种办法设置
        struct timeval tv = {5, 0} ;//5秒0微秒
    1. setsockopt( socketID, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
    2. select( maxFd + 1, &readFds, NULL, NULL, &tv );
    3. 启动定时器信号,在信号处理结束以后,重启阻塞/结束阻塞

单播:
        tcp是一对一的,只能实现单播。
        UDP可以实现单播,也可以实现多播。
    广播
        广播地址:当前网段内,主机号最大的ip地址。
        默认,用户数据报套接字不能发广播消息,如果想发,需要进行设置setsockopt
        广播通信流程
            udp服务器(接收端)          udp客户端(发送端)
        创建用户数据报套接字         创建用户数据报套接字
        绑定自己的ip/port            设置当前套接字可以发送广播消息
        等待接收消息                 设置接收地址(ip地址是广播地址,port是服务器的port),发送消息  
        回复消息                     接收消息
        关闭套接字                   关闭套接字
        小结:
            在同一个局域网内的任意主机都能收到广播消息,这样,有时会造成广播风暴。
    组播
        只有加入某个多播组的主机才能收到数据。
        D类地址(组播地址)
            不分网络地址和主机地址,第1字节的前4位固定为1110
            224.0.0.1 – 239.255.255.255
        组播通信流程
            udp服务器(接收消息)       udp客户端(发送消息)
        创建用户数据报套接字       创建用户数据报套接字
        绑定自己的ip/port          设置接收地址(ip地址是组播地址,port是服务器的port), 
        加入到某个组播组中         发送消息 
        等待接收消息               等待接收消息
        回复消息                   关闭套接字
        关闭套接字
        小结: 
            组播是加入到组播组的主机都能收到组播消息。

操作数据库的流程
                创建并打开数据库
                操作数据库
                关闭数据库
            相关函数
                创建并打开数据库
                int   sqlite3_open(char  *path,   sqlite3 **db); //FILE * fopen(...);
                    参数:path: 数据库文件路径
                          db: [返回]指向sqlite句柄的指针
                    返回值:成功返回0,失败返回错误码(非零值)
                关闭数据库
                int   sqlite3_close(sqlite3 *db);                
                    返回值:成功返回0,失败返回错误码    
                执行SQL
                int   sqlite3_exec(sqlite3 *db, const  char  *sql,  sqlite3_callback callback, void *data,  char **errmsg);
                    参数:
                    db:数据库句柄
                    sql:要执行的SQL语句
                    callback:回调函数,只有执行select查询语句的时候,它才会被调用
                    data :回调函数的第一个参数
                    errmsg:错误信息指针的地址 如果执行sql出错,会通过errmsg返回错误信息
                    返回值:成功返回0,失败返回错误码
                释放出错信息
                int sqlite3_free(char *errmsg);
                    返回值:成功返回0,失败返回错误码
                不使用回调函数执行SQL语句
                int   sqlite3_get_table(sqlite3 *db, const  char  *sql,  char ***resultp,  int*nrow,  int *ncolumn, char **errmsg);
                    功能:执行SQL操作,查询表
                    参数:db:数据库句柄
                    sql:SQL语句
                    resultp:用来指向sql执行结果的指针
                    nrow:满足条件的记录的数目
                    ncolumn:每条记录包含的字段数目
                    errmsg:错误信息指针的地址
                    返回值:成功返回0,失败返回错误码
                释放查询结果 
                sqlite3_free_table(char ** ppTable);

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值