网络编程知识点概览
========================================
1.核心知识点
传输层的两个重要协议
tcp协议:
tcp有关的理论概念(面试的时候喜欢问)
linux中tcp通信流程和接口函数
tcp单播(点播)
tcp双向通信
tcp广播
udp协议
udp有关的理论概念
linux中udp通信流程和接口函数
udp单向和双向通信
多路复用
tcp和udp的对比,三次握手,四次握手
2.引入网络编程
温故知新
进程间通信:管道(pipe mkfifo) 信号(默认响应动作,改变响应动作kill和signal/sigqueue和sigaction,忽略信号,屏蔽/阻塞信号sigprocmask) 信号量(semgetsemctlsemop) 共享内存(shmget shmat shmdt shmctl) 消息队列(msgget msgsnd msgrecv msgctl)
以上通信方法都只能在同一台主机内部进行通信
网络编程也是属于进程间通信的一种方式,网络编程既可以在同一台主机内部通信,也可以在不同的主机间通信
网络中基本概念
========================================
1.网络模型
网络模型:为了方便大家理解整个网络的通信过程,人为把网络通信的过程划分为不同的层次
通信协议:计算机科学家制定的游戏规则
比如:古代打仗的通信协议,敌人来了--》放狼烟
计算机网络中常见的通信协议 --》HTTP协议
FTP协议文件传输协议
telnet协议远程登陆协议
路由:寻找网络数据传输的最优路径(有专门的算法去寻找最优路径)
两种常见的网络模型:
第一种: OSI七层模型
应用层作用:开发特定的应用程序需要用到其中的部分协议
比如:HTTP协议
FTP协议文件传输协议
telnet协议远程登陆协议
会话层作用:建立会话,对数据加密,解密
表示层作用:数据的封装,解析http协议(超文本传输协议)ftp协议(文件传输协议)telnet(远程登录)
传输层作用:解决数据在网络中传输的问题tcp协议和udp协议
网络层(ip层)作用:解决路由(数据采取何种路径发送出去最优)问题ip协议
数据链路层作用:开发网卡的驱动,需要深入了解这个层次的协议
物理层网络接口,真实的网卡
第二种:TCP/IP模型
依据OSI七层模型演变过来的
应用层(把应用层,会话层,表示层三个合并)
传输层
网际层
网络接口层(把数据链路层和物理层合并)
2.MAC地址
你电脑物理网卡的地址,是全世界独一无二
地址协议族
ip地址有两种,一种IPV4地址协议族,另外一种是IPV6地址协议族
IPV4
32位的IP地址,比如:192.168.22.2(点分十进制IP,三个小数点隔成四个部分,每个部分一个字节,小数点不占用存储空间,仅仅只是写法标记)
IPV6
为了解决IPV4地址不够用,扩展位数,128位
3.端口号
作用:为了区分同一台主机内部不同的网络进程
端口号本质上是个无符号的短整型数字0---65535之间
程序员是可以自己指定端口号,但是不能使用1024以内的端口号,因为1024以内的端口号很多都被操作系统占用了
误解:端口号是不是就是进程的ID号--》不是,两个不同的概念
tcp协议的通信过程和接口函数
========================================
1.tcp协议的通信过程/流程
客户端的流程
创建套接字--》绑定自己的ip和端口号--》连接服务器--》收发信息--》关闭套接字
服务器的流程
创建套接字--》绑定自己的ip和端口号--》监听--》接受客户端的连接请求--》收发信息--》关闭套接字
2.相关的接口函数
(1)创建tcp套接字--》买手机
#include
int socket(int domain, int type, int protocol);
返回值: 成功 返回套接字的文件描述符
失败 -1
参数:domain --》地址协议族类型
ipv4地址协议族 --》AF_INET
ipv6地址协议族 --》AF_INET6
type --》套接字的类型
tcp套接字/数据流套接字/流式套接字 --》SOCK_STREAM
udp套接字/数据报套接字--》SOCK_DGRAM
protocol --》扩展协议,一般设置0,不会理会
(2)绑定ip和端口号
#include
int bind(int socket, const struct sockaddr *address, socklen_t address_len);
//既可以传递ipv4也可以传递ipv6
假设:int bind(int socket, const struct sockaddr_in *address, socklen_t address_len);
//局限性
假设:int bind(int socket, const struct sockaddr_in6 *address, socklen_t address_len);
//局限性
返回值:成功 返回0
失败 -1
参数:socket --》套接字文件描述符
address --》用来存放你需要绑定的ip和端口号(自己的ip和端口号)
struct sockaddr//通用地址结构体(兼容ipv4和ipv6)
{
unsigned short sa_family;
//地址协议类型AF_INET或者AF_INET6
char sa_data[14];
//存放要绑定的ip和端口号
}
struct sockaddr_in//ipv4地址结构体(专门用来存放ipv4地址)
{
sin_family;
//存放地址协议族 AF_INET
struct in_addr sin_addr;
//结构体嵌套,存放你要绑定的ipv4地址
sin_port;
//存放你要绑定的端口号
}
struct in_addr
{
in_addr_t s_addr;
;
//最终用来存放你需要绑定的ip地址
}
struct sockaddr_in6//ipv6地址结构体(专门用来存放ipv6地址)
{
}
address_len --》地址结构体的大小,sizeof
(3)ip地址和端口号的转换--》大小端
字节序:反映数据在计算机内存中采用何种存储方式去存储数据,分为两种,大小端
不同的操作系统采用的字节序是不同的
比如:ubuntu采用就是小端序
计算机网络中传递的数据采用的是大端序存储
大端序:数据的高字节存放在低地址,低字节存放在高地址
小端序:数据的高字节存放在高地址,低字节存放在低地址
主机字节序:指的就是小端序
网络字节序:指的就是大端序
3.1 小端序ip转换成大端序ip
#include
#include
#include
in_addr_t inet_addr(const char *cp);
返回值:返回转换得到的大端序(网络字节序)ip
参数:cp --》字符串ip(小端序ip/主机字节序)
int inet_aton(const char *cp, struct in_addr *inp);
返回值:成功 0失败 -1
参数:cp --》字符串ip
inp --》存放转换得到的大端序ip
代码参考:inet_aton("192.168.22.9",&(bindaddr.sin_addr));
3.2 小端序端口号转换成大端序端口
uint16_t htons(uint16_t hostshort);
h -->hostn -->networks -->short
返回值:返回转换得到的大端序端口号
参数:hostshort --》小端序端口号
【嵌入式Linux|第三十三篇,网络编程TCP协议通讯过程实现和函数接口】3.3 大端序ip转换成小端序ip
char *inet_ntoa(struct in_addr in);
返回值:字符串格式的,小端序的ip
参数:in --》大端序ip
3.4 大端序端口号转换成小端序端口
uint16_t ntohs(uint16_t netshort);
(4)连接女朋友 --》连接服务器
#include
int connect(int socket, const struct sockaddr *address, socklen_t address_len);
返回值: 成功 0
失败 -1
参数:address --》存放对方(服务器)的ip和端口号
(5)监听
int listen(int socket, int backlog);
返回值:成功 0
失败 -1
参数:socket --》套接字文件描述符
backlog --》重点,同时最多允许多少个男朋友(客户端)连接我,一般这个值建议你5---10之间就可以了
listen(tcpsock,5);
//最多允许5个男朋友(客户端)同时连接我(服务器)
(6)愿意接听--》接受客户端的连接请求
int accept(int socket, struct sockaddr *address,socklen_t *address_len);
返回值(重点,重点,重点): 成功 返回新的套接字文件描述符
之所以要产生新的套接字,原因在于服务器需要区分不同的客户端
每个客户端连接服务器成功之后,accept都会返回一个新的套接字
失败 -1
参数:socket --》套接字文件描述符
address --》存放对方(客户端)的ip和端口号
address_len --》地址长度大小,要求是指针
总结验证accept函数的特点
特点1:如果客户端没有连接服务器,服务器会一直阻塞在accept的位置
如果有客户端连接服务器成功,accept就不会阻塞,立马返回新的套接字文件描述符
特点2:客户端连接成功,accept函数会自动帮你把连接成功的客户端信息(ip和端口号)保存到第二个参数中
(7)收发信息
tcp收发信息有两组函数都可以用来收发信息
第一组:传统的read/write
第二组:使用recv/sendread和recv作用相同write和send作用相同
发送信息
ssize_t send(int socket, const void *buffer, size_t length, int flags);
返回值:成功 发送的字节数
失败 -1
参数:前面三个参数跟write一模一样
flags --》默认设置为0
接收信息
ssize_t recv(int socket, void *buffer, size_t length, int flags);
返回值:成功 接收的字节数
0 --》对方断开连接了
失败 -1
参数:前面三个参数跟read一模一样
flags --》默认设置为0
遇到的问题
========================================
1.ubuntu配置ip不熟
ubuntu配置ip两种常用方法:
方法一:使用图形用户界面配置
详细配置见截图
方法二:修改配置文件配置
vim /etc/network/interfaces打开这个文件
如果是静态ip,linux网络配置成桥接模式
(1) 打开/etc/network/interfaces文件
在这个文件的后面加入如下几句话(静态)
autoens33
iface ens33 inet static//设置静态ip
address 192.168.1.5//设置ip地址
gateway 192.168.1.1//设置网关
netmask 255.255.255.0//子网掩码
dns-nameservers 192.168.120.1//dns服务器
打开/etc/resolv.conf文件
namesever你自己的DNS服务器地址
(2)重启网络
sudo /etc/init.d/networking force-reload
sudo /etc/init.d/networking restart
如果是动态ip,linux的网络配置成NAT模式
(1) 打开/etc/network/interfaces文件
在这个文件的后面加入如下几句话(动态)
autoens33
iface ens33 inet dhcp//设置动态ip
后面的内容就不需要再写了
2.绑定失败,地址还在使用这种错误
问题一:
Cannot assign requested address
原因:绝对是你的ip地址写错了
解决方法:
方法一:修改代码中的ip地址,改成正确的ip(啰嗦,每个拿到代码都要修改)
方法二:linux提供了一个宏定义INADDR_ANY,配合一个函数htonl()函数实现自动配置本地主机上的任意ip地址--》自适应
函数原型:uint32_t htonl(uint32_t hostlong);
写法一:采用了具体的ip地址bindaddr.sin_addr.s_addr=inet_addr("192.168.22.5");
写法二:没有采用具体的ipbindaddr.sin_addr.s_addr=htonl(INADDR_ANY)
问题二:
Address already in use
原因:ubuntu系统有个机制,当你的程序异常结束的时候,端口号并不会立马释放(大概会延迟30秒钟左右才释放),如果你性子急躁,马上再次运行程序,就会有这种错误提示
解决方法:
方法一:耐心等待30秒--》馊主意
方法二:修改代码(主函数传参),换个端口号 --》略微好一点
方法三:调用setsockopt()函数去设置套接字可以重复使用端口号
int setsockopt(int socket, int level, int option_name,const void *option_value, socklen_t option_len);
比如:
int on=1;
setsockopt(tcpsock,SOL_SOCKET,SO_REUSEADDR,&on,sizeof(on));
注意:此代码只能在socket之后,bind之前使用
推荐阅读
- Linux网络编程|select函数实现TCP双向通信
- ARM开发板 嵌入式Linux 修改开机启动LOGO
- 学嵌入式Linux软件开发需要的知识
- 嵌入式Linux开发环境中双网卡使用过程杂记
- OpenWRT嵌入式Linux故障排除一例
- 嵌入式linux/android alsa_aplay alsa_amixer命令行用法
- 嵌入式Linux下完成LCD屏文字显示(帧缓冲框架)