网络编程
文章目录
一、网络常识
(一)OSI 7层网络互联参考模型
1 物理层 :
功能:连接物理电路,确保数据发送
设备:集线器
作用:
1 放大信号
2 扩展物理接口
2 数据链路层:
功能:确保数据在物理点路上的可靠传输,具有物理编址、网络拓扑结构、 帧序列、错误校验和流控
设备:交换机
1> :自动寻址
2> :交换作用
网络拓扑结构
总线型:
星型 :
环型 :
错误校验:
奇偶校验:就是看数据每一位1的个数是奇数还是偶数
和校验 :
3 网络层:
作用:把IP地址转换成MAC地址,也叫地址解析协议
逆地址解析协议:MAX地址转换成IP地址
设备:路由
地址翻译、协议转换和数据格式转换等功能
协议:就是数据在传输过程中格式或者规则
4 传输层:
功能:实现不同用户时间通讯
TCP: 面向连接服务
UDP: 面向非连接服务
5 会话层:
可以保证数据同步显示
6 表示层:
数据一种体现方式
压缩、解压缩、加密、解密
7 应用层:
就是给应用层用户提供编程接口
(二)TCP/IP 4层网络模型
物理层:比特流
网络层:数据帧 IP
传输层:数据包 TCP UDP
应用层:数据段
(三)Ethernet II帧格式
最小长度是64字节 最大是1518字节
MAC地址是由两部分组成
前面3个字节表示厂商编码 <= IEEE
后面3个字节表示适配器编号 <= 厂商
全局唯一
format:
目标MAC地址:6个字节
表示把数据帧方送给那个用户
源MAC地址:6个字节
表示数据是谁发送的
类型:2个字节
数据段:46 - 1500字节 由数据帧一层一层封装
数据帧:
帧头 + IP包 + 帧尾
帧头:保存源和目标的MAC地址
帧尾:校验位
ip包:
IP包头 + TCP包(UDP包)
IP包:源和目标IP地址
tcp包:
源和目标端口、序列号、标志位和校验位
校验位:4个字节
(四)IP地址
点分十进制
总共32bit,划分成4个字段,每一个字段占8位
组成:
ip = 网络号 + 主机号
如果网络号一致,则表示同一网段的用户。
分类:
私有ip :
局域网:就是针对社区或者团体独立信息共享网络ip
公有ip :
因特网 : 因特管理中心同一规定ip地址
动态ip:
是由路由给用户指定一个未使用的ip地址
静态ip:
由用户指定未使用ip地址
ip冲突:
网络号一致(表示同一网段)的主机号一致
(五)TCP三次握手和四次挥手
第一次握手:
客户端向服务发送一个请求建立连接SYN包 SYN => 1,同时发送一个X序列号。
第二次握手:
服务器接受到客户端请求包,然后向客户端发送一个确认(ACK)包,
ACK => 1 SYN => 1 确认序列号字段中填入 X + 1, 请求序列号字段中填入Y的序列号。
第三次握手:
客户端接受到服务器确认包,会再次向服务器发送一个确认包ACK => 1 SYN => 0 把服务区发送序列号Y + 1保存到确认字段中,并把自己序列号X + 1保存数据段。
服务器接受到客户端的确认包后,双方处于通讯的状态。
在三次握手的基础上,最后拆除连接步骤,称为四次挥手。
(六)tcp和udp区别
tcp 是面向连接的一种协议
udp 是面向非连接的一种协议
tcp传输数据比dup更安全
udp传输效率比tcp更高效
二、TCP /IP
(一)client
(一)创建套接字
int socket(int domain, int type, int protocol);
参数:
@domain 套接子地址家族
PF_INET :IPV4的协议类型
AF_INET
@type 套接子类型
SOCK_STREAM :表示流式套接子 TCP
SOCK_DGRAM :表示数据报套接子UDP
@protocol 协议类型
0 : 根据前面套接子类型分配协议类型
IPPROTO_TCP : 表示tcp协议类型
IPPROTO_UDP : 表示udp协议类型
返回值:
成功:网络套接字文件描述符
失败:-1
(二)请求连接
int connect(int sockfd,const struct sockaddr *serv_addr, socklen_t addrlen);
参数:
@sockfd 套接子文件描述符 socket返回值
@serv_addr 目标套接子结构体信息地址 实例化
struct sockaddr_in {
sa_family_t sin_family; 地址家族
u_int16_t sin_port; 端口号
struct in_addr sin_addr; ip 地址
struct in_addr {
u_int32_t s_addr;
};
};
@addlen 结构体大小
返回值:
成功:0
失败:-1
(三)字节序转化
(一)端口号转换:
1.主机字节序转换成网络字节序
uint32_t htonl(uint32_t hostlong);//长整形
uint16_t htons(uint16_t hostshort);//短整形
2.网络字节序转换成主机字节序
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
(二)ip地址转换:
1.主机字符串ip转换成网络ip字节序
in_addr_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *inp);
2.网路ip字节序转换成本机字符串
char *inet_ntoa(struct in_addr in);
(四)发送数据
size_t send(int s, const void *buf, size_t len, int
flags);
参数:
@s 套接子的文件描述符
@buf 发送数据的空间地址
@len 数据大小
@flsg 标志位 0
返回值:
成功:表示发送数据个数
失败:-1
(二)server
(一)创建套接字
int socket(int domain, int type, int protocol);
参数:
@domain 套接子地址家族
PF_INET :IPV4的协议类型
AF_INET
@type 套接子类型
SOCK_STREAM :表示流式套接子 TCP
SOCK_DGRAM :表示数据报套接子UDP
@protocol 协议类型
0 : 根据前面套接子类型分配协议类型
IPPROTO_TCP : 表示tcp协议类型
IPPROTO_UDP : 表示udp协议类型
返回值:
成功:网络套接字文件描述符
失败:-1
(二)绑定
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
参数:
@sockfd 套接子文件描述符 socket返回值
@my_addr 服务器网络地址
@addrlen 结构体大小
返回值:
成功:0
失败:-1
(三)监听
int listen(int sockfd, int backlog);
参数:
@sockfd 监听套接子文件描述符
@backlog 监听用户个数
返回值:
成功:0
失败:-1
(四)连接
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
参数:
@sockfd socket返回值
@addr 目标地址结构体 不需要实例化
@addrlen 目标结构体大小
返回值:
成功:表示文件描述符 区分不同的用户
失败:-1
(五)接收数据
ssize_t recv(int s, void *buf, size_t len, int flags);
参数:
@s 套接子的文件描述符
@buf 接收数据的空间地址
@len 空间大小
@flags 标志位 0
0 : 表示阻塞
MSG_DONTWAIT :不阻塞
返回值:
成功:接受数据个数
失败:-1
结束:0
(三)注意
文件描述符:
sd : socket 用于建立连接
fd : accept 用户数据通讯
端口:
10086 : 用户指定,服务端口号
XXXXX : 系统指定,数据端口号
三、UDP
(一)client
(一)创建套接字
int socket(int domain, int type, int protocol);
参数:
@domain 套接子地址家族
PF_INET :IPV4的协议类型
AF_INET
@type 套接子类型
SOCK_STREAM :表示流式套接子 TCP
SOCK_DGRAM :表示数据报套接子UDP
@protocol 协议类型
0 : 根据前面套接子类型分配协议类型
IPPROTO_TCP : 表示tcp协议类型
IPPROTO_UDP : 表示udp协议类型
返回值:
成功:网络套接字文件描述符
失败:-1
(二)连接并发送
ssize_t sendto(int s, const void *buf, size_t len, int flags, const struct sockaddr *to, socklen_t tolen);
参数:
@s 套接子文件描述符 socket
@buf 发送数据空间地址
@len 发送数据大小
@flags 标志位 0
@to 目标地址结构体 实例化
(struct sockaddr *)sockaddr_in
@tolen 结构体大小
return:
成功:发送成功数据个数
失败:-1
(二)server
(一)创建套接字
int socket(int domain, int type, int protocol);
参数:
@domain 套接子地址家族
PF_INET :IPV4的协议类型
AF_INET
@type 套接子类型
SOCK_STREAM :表示流式套接子 TCP
SOCK_DGRAM :表示数据报套接子UDP
@protocol 协议类型
0 : 根据前面套接子类型分配协议类型
IPPROTO_TCP : 表示tcp协议类型
IPPROTO_UDP : 表示udp协议类型
返回值:
成功:网络套接字文件描述符
失败:-1
(二)绑定
int bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen);
参数:
@sockfd 套接子文件描述符 socket返回值
@my_addr 服务器网络地址
@addrlen 结构体大小
返回值:
成功:0
失败:-1
(三)连接并接收
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
参数:
@s 套接子文件描述符 socket
@buf 接收数据空间地址
@len 接收数据大小
@flags 标志位 0
@to 目标地址结构体 无需实例化
(struct sockaddr *)sockaddr_in
@tolen 结构体大小
记得&
返回值:
成功:接收数据个数
失败:-1
(三)bcast
(一)设置套接字广播类型
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
参数:
@s 套接子文件描述符 socket返回值
@level 级别
SOL_SOCKET :一般套接子级别
IPPROTO_IP :ipv4级别 多播套接字类型
@optname 指令
SO_REUSEADDR : 表示端口重用
SO_BROADCAST : 表示广播
IP_MULTICAST_TTL:表示多播生存周期
IP_MULTICAST_LOOP:进制多播回环
IP_ADD_MEMBERSHIP:表示添加用户到多播组中
struct ip_mreqn {
//表示多播号
struct in_addr imr_multiaddr;
//表示本地ip
struct in_addr imr_address;
//表示端口标识 0
int imr_ifindex;
};
IP_DROP_MEMBERSHIP:表示从多播组中删除用户
@optval 是否启动广播
非零:表示开启广播
0 :表示关闭广播
@optlen 开关大小
返回值:
成功:0
失败:-1
(二)设置套接字多播类型
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);
参数:
@s 套接子文件描述符 socket返回值
@level 级别
SOL_SOCKET :一般套接子级别
IPPROTO_IP :ipv4级别 多播套接字类型
@optname 指令
SO_REUSEADDR : 表示端口重用
SO_BROADCAST : 表示广播
IP_MULTICAST_TTL:表示多播生存周期
IP_MULTICAST_LOOP:进制多播回环
IP_ADD_MEMBERSHIP:表示添加用户到多播组中
struct ip_mreqn {
//表示多播号
struct in_addr imr_multiaddr;
//表示本地ip
struct in_addr imr_address;
//表示端口标识 0
int imr_ifindex;
};
IP_DROP_MEMBERSHIP:表示从多播组中删除用户
@optval 是否启动广播
非零:表示开启广播
0 :表示关闭广播
@optlen 开关大小
返回值:
成功:0
失败:-1
注意:
指定一个多播号(ip) => D类 224.1.2.3
224.0.0.0 ~ 239.255.255.255
ip地址是静态IP,则一定设置默认网关。
四、IO复用
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
参数:
@nfds 最大文件描述符 + 1
@readfds 文件描述符 读集 NULL
@writefds 文件描述符 写集 NULL
@exceptfds 文件描述符 异常集合 NULL
@timeout 时间结构体
NULL : 表示阻塞的方式检测用户
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
};
0 0 : 表示轮询的方式检测用户
1 1 : 表示设定时间到后则去检测用户
返回值:
成功:文件描述符个数
失败:-1
超时: 0
void FD_CLR(int fd, fd_set *set);表示从集合中删除用户
int FD_ISSET(int fd, fd_set *set);表示判断用户是否在集合中
void FD_SET(int fd, fd_set *set);表示添加用户到集合中
void FD_ZERO(fd_set *set);清空集合