网络编程学习笔记
网络编程发展历史:1957年 前苏联发射两枚卫星 1958年提出DARPA 1968年6月DARPA提出“资源共享计算机网络” 1974年12月两人正式发表第一份TCP协议详细说明,但此协议在有数据包丢失时不能有效的纠正。
ARRPA 网前期有两个缺点
{
1.只能连接ARRPA主机
2.数据交互不能保证传输稳定
}
tcp/ip协议
{
1.tcp 解决数据传输问题
2.ip 解决不同网络之间的连接
}
osi七层模型:应用层 app
表示层 数据加密解析
会话层 建立逻辑名字和物理名字的联系
传输层 确保数据的传输,流量控制
网络层 数据分组,选择路由
数据链路层 把数据组装成可以发送的帧格式
物理层 把数据转化成物理信号
tcp/ip协议模型:应用层
传输层 tcp/udp
网络层
网络接口和物理层
tcp/ip协议传输的数据格式组装过程
tcp 稳定可靠,有连接,无失序,数据流式
udp 不稳定,无连接,有失序,数据报式
tcp协议
{
ip地址:标识唯一主机 ipv4 4字节 点分形式:192.168.7.33
端口号:标识进程 2字节 0到1023系统 1024-5000应用 5001 - 65535
地址族:说明ip的类型
}
cs架构服务器:
{
1.创建套接字
int socket(int domain, int type, int protocol);
返回值: 成功返回文件描述符, 失败返回-1
参数:domain:地址族 ipv4 AF_INET
type: 套接字类型 tcp SOCK_STREAM
protocol:协议 0默认协议
2.绑定套接字信息 ip地址 端口号 地址族
struct sockaddr_in
{
sa_family_t sin_family; /* address family: AF_INET */
in_port_t sin_port; /* port in network byte order */
struct in_addr sin_addr; /* internet address */
};
/* Internet address. */
struct in_addr
{
uint32_t s_addr; /* address in network byte order */
};
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
返回值:成功返回0 失败-1
参数:sockfd:套接字文件描述符
addr:存储信息的结构体地址
{
127.0.0.1 本机回环地址,作于测试
0.0.0.0 本机地址
}
addrlen:结构体大小
大小端:
{
大端存储:低字节存在高位,高字节存低位
小端存储:低字节存在低位,高字节存高位
}
htons() 把短整型转换位网络字节序
ntohs() 把网络字节序转换为短整型
innet_addr() 把字符串转换为网络字节序
inet_ntoa() 把网络字节序转换为字符串
3.监听套接字
int listen(int sockfd, int backlog);
设置监听队列
返回值:成功返回0 失败 -1
参数: sockfd:套接字文件描述符
backlog:监听队列的大小一般3到4
4.被动等待连接 阻塞
accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
返回值:成功返回客户端文件描述符,失败-1
参数: sockfd:服务器套接字
addr:存客户端信息
addrlen:结构体大小
通信:接收客户端信息
处理信息
返回信息
}
客户端
{
1.创建套接字
2.绑定/可选
3.连接connect
}
1.写出tcp服务器,使用飞机测试通信
2.使用自己写的客户端测试通信
3.recv() send()
三次握手:SYN请求连接信号 0代表没确认 1代表确认
seq信息编号 记录发送数据的编号
ACK确认信号 0代表没确认 1代表确认
ack确认的包的编号 值应该是seq加1
一:客户端向服务器发送建立连接请求(SYN=1),数据包编号seq=x
二:服务器收到客户端请求:发送建立连接请求(SYN=1),数据包编号seq=y
回复客户端请求(ACK=1, ack=x+1)
三:客户端收到服务器请求:回复服务器(ACK=1, ack=y+1)
四次挥手:
一:客户端向服务器发送断开连接请求(FIN = 1),数据包编号u
二:服务器收到客户端请求:发送(ACK = 1, ack=u+1),剩余数据 (seq = v)
三:服务向客户端发送断开连接请求(FIN=1, seq=w, ack=u+1)
四:客户端收到服务器请求:(ACK=1, ack=w+1)
并发服务器模型{
多进程实现
{
优点:相互独立抗干扰
缺点:开辟进程的数量是有限的,占用资源,进程交互比较麻烦
}
eg:
int main()
{
1.创建套接字 socket
2.绑定套接字 bind
3.监听套接字 listen
捕获17号信号,回收子进程资源 signal
while(1)
{
4.被动等待连接 accept
fork()
if(pid == 0)
{
处理客户端请求
if(0==read)
close(connfd);
exit(0);
}
}
close(sockfd);
}
难点:资源回收, signal()捕获17号信号,回收子进程资源
多线程实现
{
优点:交互简单,资源占用小
缺点:抗干扰能力弱,需要考虑共享数据同步互斥
}
int main()
{
1.创建套接字 socket
2.绑定套接字 bind
3.监听套接字 listen
while(1)
{
4.被动等待连接 accept
pthread_create();
pthread_detach();
}
close(sockfd);
}
void*func(int *arg)
{
while(1)
{
处理客户端请求;
if(0 == read)
{
break;
}
}
pthread_exit(NULL);
}
UDP
无连接,有失序,数据报式,不稳定
服务器
{
1.创建套接字 SOCK_DGRAM
2.绑定套接字信息
while(1)
{
交互
}
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
}
客户端{
1.创建套接字 SOCK_DGRAM
2.绑定套接字信息(可省略)
while(1)
{
交互
}
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
}
写一个时间服务器{
客户端发送get_time
接收服务器回发的信息。打印
服务器接收命令,判断是不是get_time,如果不是就不处理,如果是就获取本地时间发送给客户端
}
IO模型{
1.阻塞 read fgets rcv
缺点:阻塞之后没办法执行其他功能
优点:逻辑简单,资源占用不高
2.非阻塞 write 缓存区满(阻塞)
缺点:需要循环遍历,cpu占用高
优点:不会影响其他功能执行
3.信号驱动
4.io多路复用{
select
poll
epoll
}
- 异步IO
套接字分类{
1.流式套接字
2.报式套接字
3.unix域套接字 只能进行本机通信
{
struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[108]; /* Pathname */
};
作用:传递文件描述符,传递凭证
}
}
ip地址分类{
A:一个字节为网络号,3个字节为主机号
学校,国企
以0开始
范围 0.0.0.0到127.255.255.255 0.0.0.0 本机 127.0.0.1回环 以.255结尾广播地址
B:两个字节为网络号,2个字节为主机号
私有
以10开始
范围128.0.0.0 到 191.255.255.255
C:三个字节为网络号,1个字节为主机地址
私有
以110开始
范围192.0.0.0 到 223.255.255.255
D:组播地址
以1110开始
范围224.0.0.0 到239.255.255.255
E:保留地址
以11110开始
}
广播{
向广播地址发送消息
发送广播{
1.设置允许发送广播选项 setsockopt()
2.向广播地址发送信息 以255结尾
}
接收广播{
1.我绑定的地址需要是一个广播地址或者是0地址
}
}
组播{
加入组播地址才能收到发给组播地址的信息
struct ip_mreq
{
struct in_addr imr_multiaddr; //组播地址
struct in_addr imr_interface; //加入到组播组中的地址
};
发送组播{
1.创建套接字
2.允许发送组播地址
}
接收方{
1.创建套接字
2.绑定
3.加入到组播组中
}
}