目录
前言
网络编程是指使用编程语言进行网络通信的过程。通过网络编程,计算机可以通过互联网或局域网与其他计算机进行数据交换和通信。在网络编程中,程序员需要使用特定的网络编程接口和协议(如TCP/IP、HTTP等)来实现数据的发送和接收。网络编程常用于开发网络应用、远程服务和分 布式系统等。
网络编程具有以下几个重要的作用:
-
数据交换和通信:通过网络编程,计算机可以在网络上进行数据的发送和接收,实现信息的交换和通信。这对于实现远程服务、分布式系统以及网络应用等都非常重要。
-
分布式系统:通过网络编程,可以将多台计算机连接起来,形成一个分布式系统。在分布式系统中,不同计算机之间可以互相通信和协作,共享资源和处理任务,从而提高系统的可靠性、性能和扩展性。
-
网络应用开发:网络编程是开发网络应用(如Web应用、聊天室、在线游戏等)的基础。通过网络编程,可以实现服务器端和客户端之间的数据交互,从而实现用户与服务器的交互和信息的展示。
-
网络安全:网络编程也与网络安全密切相关。通过网络编程,可以实现加密、认证、防止信息泄漏等安全机制,保护网络通信的隐私和安全。
总之,网络编程为计算机之间的数据交换和通信提供了技术基础,成为了构建分布式系统、开发网络应用以及保障网络安全的重要手段。
一、网络的含义与构成
含义:
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
四、服务器和客户端代码实例
//服务器代码#include #include #include #include #include #include int main(void){//1>创建socket套接字int serfd = socket(AF_INET,SOCK_STREAM,0);//1.选IPv4,2选TCP,3默认0if(serfd<0)//错误判断{perror("socket");return -1;}printf("创建出的socket的值为%d\n",serfd);//2>绑定自己的IP地址和端口号struct sockaddr_in my_addr;my_addr.sin_family = AF_INET;//IPv4my_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 0bzero(buf,sizeof(buf));ret = recv(clifd,buf,sizeof(buf),0);//阻塞printf("客户端说:%s\n",buf);#endifbzero(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 #include #include #include #include #include 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语言的其他重要的基础知识,感谢大家支持懒大王!
希望这篇博客能给各位朋友们带来帮助,最后懒大王请来过的朋友们留下你们宝贵的三连以及关注,感谢你们!
来源地址:https://blog.csdn.net/weixin_58070962/article/details/133907368