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

简介: C/C++网络编程基础知识超详细讲解第一部分(系统性学习day11)

前言

网络编程是指使用编程语言进行网络通信的过程。通过网络编程,计算机可以通过互联网或局域网与其他计算机进行数据交换和通信。在网络编程中,程序员需要使用特定的网络编程接口和协议(如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<sys/types.h>

   #include<sys/socket.h>

   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<sys/types.h>
    #include<sys/socket.h>
    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 <arpa/inet.h>

   

   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 <netinet/in.h>

   in_addr_t inet_addr(const char *cp);

   将点分十进制的IP地址转换为网络二进制

   

   char *inet_ntoa(struct in_addr in);

   将网络二进制转回点分十进制

3.监听listen

   头文件:

   #include <sys/types.h>

   #include <sys/socket.h>

   int listen(int sockfd, int backlog);

   功能:

       保护服务器,限制同一瞬间最大的客户端连接数量

   参数:

       sockfd:这个是socket创建出来的具有网络属性的文件描述符

       backlog:最大的客户端连接数量

   返回值:

       成功返回0

       失败,返回-1并设置错误码

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

  头文件:

   #include <sys/types.h>

   #include <sys/socket.h>

   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 <sys/types.h>

   #include <sys/socket.h>

   int connect(int sockfd, const struct sockaddr* addr, socklen_t addrlen)

   功能:

       主动连接服务器,第二参能保存对方的IP地址和端口号,不需要设置NULL

   参数:

       sockfd:这个是socket创建出来的具有网络属性的文件描述符

       addr:用来连接服务器的结构体

       addrlen:结构体长度,一般用sizeof()。

   返回值:

       成功返回0

       失败,返回-1并设置错误码

4.数据发送(send

   头文件:

   #include <sys/types.h>

   #include <sys/socket.h>

 

   ssize_t send(int sockfd, const void *buf, size_t len, int flags);

   功能:

       数据发送

   参数:

       sockfd:套接字文件描述符

       buf:发送缓冲区

       len:发送缓冲区长度

       flags:默认为0,表示阻塞

   返回值:

   成功:返回发送的字节数

   失败:返回-1,并设置errno

5.数据接收(recv

  头文件:

   #include <sys/types.h>

   #include <sys/socket.h>

   ssize_t recv(int sockfd,void *buf, size_t len, int flags);

   功能:

       数据接收

   参数:

       sockfd:套接字文件描述符

       buf:接收缓冲区

       len:接收缓冲区长度

       flags:默认为0,表示阻塞

   返回值:

   >0: 返回接收的字节数

   =0:    客户端异常退出(CTRL+C)

   <0: 失败:返回-1,并设置errno

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

//服务器代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
 
int main(void)
{
  //1>创建socket套接字
  int serfd = socket(AF_INET,SOCK_STREAM,0);//1.选IPv4,2选TCP,3默认0
  if(serfd<0) //错误判断
  {
    perror("socket");
    return -1;
  }
  printf("创建出的socket的值为%d\n",serfd);
  //2>绑定自己的IP地址和端口号
  struct sockaddr_in my_addr;
  my_addr.sin_family = AF_INET;//IPv4
  my_addr.sin_port = htons(8888);//将linux小端转系统的大端
  my_addr.sin_addr.s_addr =inet_addr("192.168.10.5");//注意将IP地址格式转为网络二进制,还有记得改成自己的linuxIP地址
  int ret;
  ret = bind(serfd,(struct sockaddr *)&my_addr,sizeof(my_addr));
  //第二参将同族结构体强转为函数需要的结构体类型
  if(ret<0) //错误判断
  {
    perror("bind");
    return -1;
  }
  printf("serfd网络属性已成功配置!\n");
  //3>监听
  ret = listen(serfd,8);
  if(ret<0) //错误判断
  {
    perror("listen");
    return -1;
  }
  printf("监听已启动,保护服务器中^-^\n");
  //4>等待客户端连接 阻塞
  int clifd = accept(serfd,NULL,NULL);//accept接触阻塞后将产生一个与客户端通信的文件描述符
  if(clifd<0) //错误判断
  {
    perror("accept");
    return -1;
  }
  printf("创建出与客户端通信的文件描述符值为%d\n",clifd);
  printf("有客户连接进来了!\n");
  //5>数据的接收
  char buf[30];
  while(1)
  {
#if 0
    bzero(buf,sizeof(buf));
    ret = recv(clifd,buf,sizeof(buf),0);//阻塞
    printf("客户端说:%s\n",buf);
#endif
    bzero(buf,sizeof(buf));
    ret = recv(clifd,buf,sizeof(buf),0);//阻塞
    if(ret<0)
    {
      perror("recv");
      return -1;
    }else if(ret == 0)
     {
       printf("客户带着小姨子跑了!\n");
       return -1;
     }else
      {
      printf("客户端说:%s\n",buf);
      }
  }
  //6>关闭套接字
  close(serfd);
  close(clifd);
  return 0;
}
//客户端代码
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <string.h>
 
int main(void)
{
  //1>创建socket套接字
  int sockfd = socket(AF_INET,SOCK_STREAM,0);
  if(sockfd<0)
  {
    perror("socket");
    return -1;
  }
  printf("创建出的socket的值为%d\n",sockfd);
  //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");
  printf("已经声明服务器的IP地址和端口号!\n");
  //3>主动连接服务器
  int ret = connect(sockfd,(struct sockaddr*)&server,sizeof(server));
  if(ret<0)
  {
    perror("connect");
    return -1;
  }
  printf("连接服务器成功,请进行操作!\n");
  //4>数据发送
  char buf[30];
  while(1)
  {
    bzero(buf,sizeof(buf));
    scanf("%s",buf);
    send(sockfd,buf,strlen(buf),0); 
  }
  
  //5>关闭文件描述符
  close(sockfd);
  return 0;
}


总结

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

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

相关文章
|
4天前
|
算法 API C++
使用C++进行系统级编程的深入探索
【5月更文挑战第23天】本文探讨了C++在系统级编程中的应用,强调其接近底层、高性能、可移植性和面向对象编程的优势。关键技术和最佳实践包括:内存管理(智能指针和RAII原则)、多线程(std::thread和同步原语)、系统调用与API、以及设备驱动和内核编程。编写清晰代码、注重性能、确保安全稳定及利用开源库是成功系统级编程的关键。
|
12天前
|
监控 安全 网络安全
漏洞扫描系统可以用于发现网络入侵者?
漏洞扫描系统自动检测系统安全漏洞,如未打补丁软件和弱密码,但无法直接发现网络入侵者。入侵者可能使用加密和掩盖手段逃避检测。为此,需结合入侵检测系统(IDS)、防火墙、安全事件管理(SIEM)系统和蜜罐等工具实时监控异常行为。企业还应提升员工安全意识以增强防御能力。
|
4天前
|
JavaScript 小程序 Java
基于微信小程序的网络安全科普系统的设计与实现(源码+lw+部署文档+讲解等)
基于微信小程序的网络安全科普系统的设计与实现(源码+lw+部署文档+讲解等)
|
5天前
|
Serverless C++
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
|
6天前
|
JavaScript Java 关系型数据库
网络在线考试|基于SSM+vue的网络在线考试系统的设计与实现(源码+数据库+文档)
网络在线考试|基于SSM+vue的网络在线考试系统的设计与实现(源码+数据库+文档)
23 0
|
6天前
|
算法 编译器 C语言
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(下)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
13 0
|
6天前
|
编译器 C语言 C++
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL(上)
从C语言到C++⑩(第四章_模板初阶+STL简介)如何学习STL
8 0
|
6天前
|
编译器 C语言 C++
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)(下)
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)
12 0
|
6天前
|
Java 编译器 C#
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)(上)
从C语言到C++①(第一章_C++入门_上篇)C++学习介绍(命名空间和C++输入输出流)
22 0
|
7天前
|
机器学习/深度学习 人工智能 算法
食物识别系统Python+深度学习人工智能+TensorFlow+卷积神经网络算法模型
食物识别系统采用TensorFlow的ResNet50模型,训练了包含11类食物的数据集,生成高精度H5模型。系统整合Django框架,提供网页平台,用户可上传图片进行食物识别。效果图片展示成功识别各类食物。[查看演示视频、代码及安装指南](https://www.yuque.com/ziwu/yygu3z/yhd6a7vai4o9iuys?singleDoc#)。项目利用深度学习的卷积神经网络(CNN),其局部感受野和权重共享机制适于图像识别,广泛应用于医疗图像分析等领域。示例代码展示了一个使用TensorFlow训练的简单CNN模型,用于MNIST手写数字识别。
25 3