• C/C++网络编程基础知识超详细讲解上部分(系统性学习day11)


    目录

    前言

    一、网络的含义与构成

    含义:

    构成: 

    二、网络的体系结构

    1>OSI七层模型

    2>TCP/IP协议体系结构 

    3>数据经过体系结构,怎么封装? 

    4>端口号

    5>大小端序

    6>TCP/UDP传输层的协议 

    三、系统函数API学习框架(TCP)    

    服务器(优先):

     客户端:

    四、服务器和客户端代码实例 

    总结


    前言

    网络编程是指使用编程语言进行网络通信的过程。通过网络编程,计算机可以通过互联网或局域网与其他计算机进行数据交换和通信。在网络编程中,程序员需要使用特定的网络编程接口和协议(如TCP/IP、HTTP等)来实现数据的发送和接收。网络编程常用于开发网络应用、远程服务和分    布式系统等。

    网络编程具有以下几个重要的作用:

    1. 数据交换和通信:通过网络编程,计算机可以在网络上进行数据的发送和接收,实现信息的交换和通信。这对于实现远程服务、分布式系统以及网络应用等都非常重要。

    2. 分布式系统:通过网络编程,可以将多台计算机连接起来,形成一个分布式系统。在分布式系统中,不同计算机之间可以互相通信和协作,共享资源和处理任务,从而提高系统的可靠性、性能和扩展性。

    3. 网络应用开发:网络编程是开发网络应用(如Web应用、聊天室、在线游戏等)的基础。通过网络编程,可以实现服务器端和客户端之间的数据交互,从而实现用户与服务器的交互和信息的展示。

    4. 网络安全:网络编程也与网络安全密切相关。通过网络编程,可以实现加密、认证、防止信息泄漏等安全机制,保护网络通信的隐私和安全。

    总之,网络编程为计算机之间的数据交换和通信提供了技术基础,成为了构建分布式系统、开发网络应用以及保障网络安全的重要手段。


    一、网络的含义与构成

    含义:

       1.什么是网络?
            网络是信息传输、接收和共享的虚拟世界,通过把地球村内所有
    信息汇聚起来,从而实现这些资源的共享。
            初衷:知识共享            

    构成: 

     2.计算机上的软件层面的网络是由什么构成?
            1>IP
                格式:
                    点分十进制        用户浏览与编写    192.168.10.x
                    网络二进制        系统、电脑看的  0、1组合
                分类:
                    IPv4   (主要集中,应用在电脑)
                        点分十进制        4个字节
                        网络二进制        32位
                    (42个ip地址)
                    IPv6  (手机WiFi、目前在电脑中不集中)
                        点分十进制        16个字节
                        网络二进制        128位


                    IPv4分五类
                        A B C D E
                    大型网 中大型 中小型 组播型 待用型

                     

                     

    (1)A类地址
                        网络二进制:是以0开头
                        1个网络地址 3个主机地址(网络地址等于你在哪个教室,主机地址
                        代表你在教室中的位置)
    网络二进制:
    00000000 00000000 00000000 00000001 - 01111111 11111111 11111111 11111110 
    点分十进制:
        0.0.0.1-127.255.255.254  
    注意:
            主机位全为0,定义为网段号,网络ID号
            主机位全为1,定义广播地址
            

    (2) B类地址
                        网络二进制:是以10开头
                        2个网络地址 2个主机地址(网络地址等于你在哪个教室,主机地址
                        代表你在教室中的位置)
    网络二进制:
    10000000 00000000 00000000 00000001 - 10111111 11111111 11111111 11111110 
    点分十进制:
        128.0.0.1-191.255.255.254  
    注意:
            主机位全为0,定义为网段号,网络ID号
            主机位全为1,定义广播地址

    (3)C类地址
                        网络二进制:是以110开头
                        3个网络地址 1个主机地址(网络地址等于你在哪个教室,主机地址
                        代表你在教室中的位置)
    网络二进制:
    11000000 00000000 00000000 00000001 - 11011111 11111111 11111111 11111110 
    点分十进制:
        192.0.0.1-223.255.255.254  
    注意:
            主机位全为0,定义为网段号,网络ID号
            主机位全为1,定义广播地址

    (4)D类地址
                        网络二进制:是以1110开头
                        4个网络地址 0个主机地址(网络地址等于你在哪个教室,主机地址
                        代表你在教室中的位置)
    网络二进制:
    11100000 00000000 00000000 00000001 - 11101111 11111111 11111111 11111110 
    点分十进制:
        224.0.0.1-239.255.255.254    
    注意:
            主机位全为0,定义为网段号,网络ID号
            主机位全为1,定义广播地址            
            
    (5)E类地址
                        未来可期

            2>子网掩码
                网络地址全为1,主机全为0
                255.255.255.0
                用来判断是否在同一网段
                前缀长度:24(主要看子网掩码中1的个数)
                -->在linux网络配置中有体现
                
            3>默认网关
                主机地址默认值为1,随机取1-254,掐头去尾
                用来管理当前网段下的信息传输;网络的门户
                -->结合图片理解
                
            4>DNS域名解析服务器
                按照地方运营商提供的DNS域名服务器
                202.98.128.86
                www.baidu.com
                IP所属地:广东、深圳

    二、网络的体系结构

    1.OSI七层模型

     ISO公司推出的网络体系模型
            
            协议:双方规定好的通信规则
                应用层
                表示层
                会话层
                传输层
                网络层
                数据链路层
                物理层
            
            目的:将数据封装起来,形成一个约定好的通信协议
            缺点:太复杂,太繁琐,有写功能重复

    2.TCP/IP协议体系结构 

            应用层        ftp、http、ping、ssh        
            传输层        TCP、UDP
            网络层        IP、ICMP、IGMP
            物理层        网线
            
            重点学习的网络体系结构,网络协议中的世界

    3.数据经过体系结构,怎么封装? 

     封装数据的目的是为了保证数据在网络中传输的稳定性
                -->结合图片理解

    4.端口号

     区分不同的应用程序,针对主机
                QQ4999,微信5050
                2个字节 0~65535
                0~1023  --》系统进程使用的
                1024~65535  --》用户用的 

    5.大小端

     不同类型的CPU的主机中,内存存储的整数字节序有两种
                小端序:
                    低位字节存储到低位地址,     linux
                大端序: 
                    低位字节存储到高位地址,     系统

    6.TCP/UDP传输层的协议 

        TCP/UDP的区别:
            UDP(用户数据报协议)的特点:只管发送,没有连接属性,数据因此不可靠,不稳定,易丢失。
            举例:写信
            
            TCP(传输控制协议)的特点:要先建立连接,保证了数据的可靠信,因此数据稳定,不丢包。
            举例:带电话

    三、系统函数API学习框架(TCP)    

    服务器(优先):

         框架:             
                    1>创建socket套接字
                    2>绑定自己的IP地址和端口号
                    3>监听
                    4>等待客户端连接
                    5>数据收/发
                    6>关闭套接字(具有网路属性的文件描述符) 

    1.创建socket套接字 (socket

       头文件:

        #include
        #include
        int socket(int domain, int type, int protocol);
        功能:
            创建一个具有网络属性的文件描述符
        参数:
            domain:协议族
                AF_UNIX,AF_LOCAL          本地连接
                AF_INET                   IPv4
                AF_INET6                   IPv6
            type:
            SOCK_STREAM    流式套接字       TCP
            SOCK_DGRAM  数据报套接字   UDP
            SOCK_RAW    原始套接字
            protocol:
                默认为0,表示前面两个所选参数生效
        返回值:
            成功返回具有网络属性的文件描述符
            失败,返回-1并设置错误码
            
        socket位于哪里,位于应用层和传输层之间

     2.绑定自己的IP地址和端口号(bind

        头文件:

        #include
        #include
        int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
        功能:
            将IP地址和端口号绑定在sockfd上,难点在于第二参结构体赋值
        参数:
            sockfd:这个是socket创建出来的具有网络属性的文件描述符
            my_addr:结构体指针,用来赋值IP地址和端口号
            addrlen:结构体的长度
        返回值:
            成功返回0
            失败,返回-1并设置错误码
        
        第二参数const struct sockaddr *my_addr
        
        struct sockaddr {
           sa_family_t sa_family;  2个字节
           char        sa_data[14]; 14个字节
        }
        
        问题:
            赋值时IP地址和端口号哪个在前哪个在后不确定
            IP地址和端口号只占据6个字节,还有8个字节怎么填充
            
        因此选用同族结构体
        struct sockaddr_in{
            sa_family_t   sin_family;   //地址族
            uint16_t      sin_port;     //端口号 
            struct in_addr    sin_addr;  //32位IP地址
            char     sin_zero[8];      //预留未使用,自动填充0
        };
        struct in_addr{
            In_addr_t  s_addr;    //32位IPv4地址
        };

        1>注意端口大小端序转换的问题
        #include
        
        uint32_t htonl(uint32_t hostlong);  32位
        uint16_t htons(uint16_t hostshort); 16位
        以上小端序转大端序
        
        uint32_t ntohl(uint32_t netlong);
        uint16_t ntohs(uint16_t netshort);
        大端序转回小端序

        2>注意IP格式转换
        #include
        in_addr_t inet_addr(const char *cp);
        将点分十进制的IP地址转换为网络二进制
        
        char *inet_ntoa(struct in_addr in);
        将网络二进制转回点分十进制

    3.监听 (listen

        头文件:
        #include
        #include
        int listen(int sockfd, int backlog);
        功能:
            保护服务器,限制同一瞬间最大的客户端连接数量
        参数:
            sockfd:这个是socket创建出来的具有网络属性的文件描述符
            backlog:最大的客户端连接数量
        返回值:
            成功返回0
            失败,返回-1并设置错误码

    4.等待客户端连接 (等待意味着“阻塞” accept)

       头文件:

        #include
        #include
        int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
        功能:
            等待客户端连接,第二参能保存对方的IP地址和端口号,不需要保存对方设置NULL
        参数:
            sockfd:这个是socket创建出来的具有网络属性的文件描述符
            addr:用来保存客户端信息的结构体
            addrlen:结构体长度。
        返回值:
            成功返回与客户端通信的文件描述符,与socket函数类似
            失败,返回-1并设置错误码

     客户端:

    为了演示效果明显,我们开始写客户端框架

            1>创建socket套接字
            2>声明服务器所在的IP地址和端口号
            3>主动连接服务器
            4>数据收/发
            5>关闭文件描述符

    1.创建socket套接字与服务器相似

    2.声明服务器所在的IP地址和端口号

            struct sockaddr_in server;
            server.sin_family = AF_INET;
            server.sin_port = htons(8888);
            server.sin_addr.s_addr = inet_addr("192.168.10.5");
            注意声明都是别人的,与你无关

    3.主动连接服务器 (connect

        头文件:

        #include
        #include
        int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen)
        功能:
            主动连接服务器,第二参能保存对方的IP地址和端口号,不需要设置NULL
        参数:
            sockfd:这个是socket创建出来的具有网络属性的文件描述符
            addr:用来连接服务器的结构体
            addrlen:结构体长度,一般用sizeof()。
        返回值:
            成功返回0
            失败,返回-1并设置错误码

     4.数据发送(send

        头文件:

        #include
        #include
     
        ssize_t send(int sockfd, const void *buf, size_t len, int flags);
        功能:
            数据发送
        参数:
            sockfd:套接字文件描述符
            buf:发送缓冲区
            len:发送缓冲区长度
            flags:默认为0,表示阻塞
        返回值:
        成功:返回发送的字节数
        失败:返回-1,并设置errno

     5.数据接收(recv

       头文件:

        #include
        #include
        ssize_t recv(int sockfd,void *buf, size_t len, int flags);
        功能:
            数据接收
        参数:
            sockfd:套接字文件描述符
            buf:接收缓冲区
            len:接收缓冲区长度
            flags:默认为0,表示阻塞
        返回值:
        >0: 返回接收的字节数
        =0:    客户端异常退出(CTRL+C)
        <0: 失败:返回-1,并设置errno 

    四、服务器和客户端代码实例 

    1. //服务器代码
    2. #include <stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/socket.h>
    5. #include <arpa/inet.h>
    6. #include <netinet/in.h>
    7. #include <string.h>
    8. int main(void)
    9. {
    10. //1>创建socket套接字
    11. int serfd = socket(AF_INET,SOCK_STREAM,0);//1.选IPv4,2选TCP,3默认0
    12. if(serfd<0) //错误判断
    13. {
    14. perror("socket");
    15. return -1;
    16. }
    17. printf("创建出的socket的值为%d\n",serfd);
    18. //2>绑定自己的IP地址和端口号
    19. struct sockaddr_in my_addr;
    20. my_addr.sin_family = AF_INET;//IPv4
    21. my_addr.sin_port = htons(8888);//将linux小端转系统的大端
    22. my_addr.sin_addr.s_addr =inet_addr("192.168.10.5");//注意将IP地址格式转为网络二进制,还有记得改成自己的linuxIP地址
    23. int ret;
    24. ret = bind(serfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
    25. //第二参将同族结构体强转为函数需要的结构体类型
    26. if(ret<0) //错误判断
    27. {
    28. perror("bind");
    29. return -1;
    30. }
    31. printf("serfd网络属性已成功配置!\n");
    32. //3>监听
    33. ret = listen(serfd,8);
    34. if(ret<0) //错误判断
    35. {
    36. perror("listen");
    37. return -1;
    38. }
    39. printf("监听已启动,保护服务器中^-^\n");
    40. //4>等待客户端连接 阻塞
    41. int clifd = accept(serfd,NULL,NULL);//accept接触阻塞后将产生一个与客户端通信的文件描述符
    42. if(clifd<0) //错误判断
    43. {
    44. perror("accept");
    45. return -1;
    46. }
    47. printf("创建出与客户端通信的文件描述符值为%d\n",clifd);
    48. printf("有客户连接进来了!\n");
    49. //5>数据的接收
    50. char buf[30];
    51. while(1)
    52. {
    53. #if 0
    54. bzero(buf,sizeof(buf));
    55. ret = recv(clifd,buf,sizeof(buf),0);//阻塞
    56. printf("客户端说:%s\n",buf);
    57. #endif
    58. bzero(buf,sizeof(buf));
    59. ret = recv(clifd,buf,sizeof(buf),0);//阻塞
    60. if(ret<0)
    61. {
    62. perror("recv");
    63. return -1;
    64. }else if(ret == 0)
    65. {
    66. printf("客户带着小姨子跑了!\n");
    67. return -1;
    68. }else
    69. {
    70. printf("客户端说:%s\n",buf);
    71. }
    72. }
    73. //6>关闭套接字
    74. close(serfd);
    75. close(clifd);
    76. return 0;
    77. }
    1. //客户端代码
    2. #include <stdio.h>
    3. #include <sys/types.h>
    4. #include <sys/socket.h>
    5. #include <arpa/inet.h>
    6. #include <netinet/in.h>
    7. #include <string.h>
    8. int main(void)
    9. {
    10. //1>创建socket套接字
    11. int sockfd = socket(AF_INET,SOCK_STREAM,0);
    12. if(sockfd<0)
    13. {
    14. perror("socket");
    15. return -1;
    16. }
    17. printf("创建出的socket的值为%d\n",sockfd);
    18. //2>声明"服务器"所在的IP地址和端口号
    19. struct sockaddr_in server;
    20. server.sin_family = AF_INET;
    21. server.sin_port = htons(8888);
    22. server.sin_addr.s_addr = inet_addr("192.168.10.5");
    23. printf("已经声明服务器的IP地址和端口号!\n");
    24. //3>主动连接服务器
    25. int ret = connect(sockfd,(struct sockaddr*)&server,sizeof(server));
    26. if(ret<0)
    27. {
    28. perror("connect");
    29. return -1;
    30. }
    31. printf("连接服务器成功,请进行操作!\n");
    32. //4>数据发送
    33. char buf[30];
    34. while(1)
    35. {
    36. bzero(buf,sizeof(buf));
    37. scanf("%s",buf);
    38. send(sockfd,buf,strlen(buf),0);
    39. }
    40. //5>关闭文件描述符
    41. close(sockfd);
    42. return 0;
    43. }


    总结

            本篇文章针对C/C++ 网络编程进行详细讲解,希望能够帮到大家!

            以后还会给大家展现更多关于嵌入式和C语言的其他重要的基础知识,感谢大家支持懒大王!

           希望这篇博客能给各位朋友们带来帮助,最后懒大王请来过的朋友们留下你们宝贵的三连以及关注,感谢你们!  

  • 相关阅读:
    Python基础入门篇【41】--python中的时间包
    K8S 证书过期不能使用kubectl之后,kubeadm 重新生成证书
    MySQL入门
    Windows 下 Kafka 2.8.1 启动报错“输入行太长”问题解决方案
    C++11改动
    笔记本电脑windows10有线连接开无线热点方法已经成功
    Linux内核(一)
    http请求方式及传参方式
    【.NET Core】使用 Castle 实现 AOP,以及 Autofac 集成 Castle
    VcXsrv Releases 21.1.13 更新发布了~~
  • 原文地址:https://blog.csdn.net/weixin_58070962/article/details/133907368