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<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语言的其他重要的基础知识,感谢大家支持懒大王!

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

猜你喜欢

转载自blog.csdn.net/weixin_58070962/article/details/133907368