网络:是由若干个结点和连接这些结点的链路组成,网络中的结点可以是计算机、交换机、路由器等设备。如下图就是一个简单的网络示意图
网络设备:交换机、路由器、集线器
传输介质:双绞线、同轴电缆、光纤、无线
互联网:把多个网络连接起来的构成互联网
IP地址
为了方便主机与主机之前通信,在网络中唯一标识一台主机,该标识就是IP地址。
在自己主机上查询ip地址: ifcongfig
ping 127.0.0.1 //给自己ping,如果ping成功,所以之间的网络联通的,可以互发消息
IP地址分ipv4(32位)、ipv6(128位),由网络号+主机号构成,便于我们寻址。
MAC地址(48位):唯一标识一台主机,但是MAC无法表示出物理地址发生的变化,当你位置变化时,寻址无法找到主机
端口号:软件层次的,应用程序的代号 ipi地址+post端口号 找到主机上的某一个进程
使用netstat -natp 可以查看当前所有的端口号
协议:一组网络的规则的集合,tcp、udp、http、ip...
分层结构:
应用层:网络传输的用户接口,传输文件,协议
传输层:可以提供不同主机进程之间通讯的功能 tcp udp
网络层:依靠ip地址,可以解决不相邻的两个节点的数据传输
数据链路层:解决相邻的两个节点之间的数据的可靠传输
IP协议头部:
传输层头部:
当主机A的程序A向主机B的程序B发送HELLO
tcp协议特点:面向连接的 可靠的 流式服务
udp协议:无连接 不可靠 数据报服务 效率高
socket网络编程
在传数据时要把主机字节序列转为网络字节序列,有以下函数来实现主机和网络之间的转换:
头文件#include<netinet/in.h>
uint32_t htonl(uint32_t hostlong); //长整型主机序列转网络
uint32_t ntonl(uint32_t netlong); //长整型网络序列转主机
uint32_t htons(uint32_t hostshort); //短整型主机序列转网络
uint32_t ntohs(uint16_t netshort); //短整型网络序列转主机
套接字就是用来收发数据
套接字的地址:为了能在网络中找到你
通用的套接字地址:表示socket地址的是结构体sockaddr
专用的套接字地址:TCP/IP协议族中有ipv4 使用sockaddr_in ipv6使用sockaddr_in6两个专用的socket地址结构体
地址转换函数:头文件#include<arpa/inet.h>
in_addr_t inet_addr(const char* cp); //字符串ipv4转为网络字节序列
char* inet_ntoa(struct in_add in); //ipv4地址的网络字节转为字符串
tcp协议 服务器——客户端
tcp协议特点:面向连接、可靠的、流式服务
tcp可靠性体现在应答确认、超时重传,在信息传输过程中顺序乱了,tcp也有乱序重排的功能,还有去重功能
IPV4:AF_INET IPV6:AF_INET6
服务器
第一步:创建套接字
头文件:
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
int sockfd=socket(设置协议ipv4,创建流式套接字,0) //创建套接字,返回失败为-1
第二步:绑定套接字使用的端口
先设置端口结构体:包括设置服务器端口,初始化服务器地址,设置协议族,设置端口号,转换ip地址
对套接字指定或命名使用的端口、ip(类似于给手机装手机卡)
然后 int res=bind(套接字,通用套接字地址,地址大小); 指定套接字使用的端口,绑定一下
第三步:创建监听套接字队列
int res=listen(sockfd套接字,多少个队列);//创建监听套接字队列
创建监听套接字队列时会创建两个队列,一个来存放未完成三次握手,一个来存放已完成三次握手
一般listen(套接字,数字)中的参数数字设置的就是已完成三次握手的队列的长度
这个时候accept()建立连接套接字函数会等待已完成三次握手队列中出现已完成消息,如果没有消息则会一直阻塞,如果有拿到消息后再给到accept得接受变量中
三次握手:开始于客户端connect
客户端先向服务器发SYN i报文,表示客户端要建立链接
服务器会向客户端回复SYN j,ACK i+1,告诉客户端我们服务器的序号以及对序号的确认号
客户端会再给服务器端发送一个确认信息ACK j+1
四次挥手:开始于close,服务器客户端各close一次,一次挥两次手
服务器执行close向客户端发一个FIN n报文段告诉客户端我们服务器要关闭了
客户端发送ACK n+1给服务器,知道服务器要关了
过了一阵具体不确定,等客户端执行close 向服务器发送一个FIN m 告诉服务器我们也要关闭
服务器回复ACK m+1给客户端说好的我们知道了
三次握手四次挥手是传输层做的!!!!!!
第四步:创建链接套接字
int c=accept(套接字,客户端通用套接字地址,地址大小的地址) ; //创建连接套接字,有多少个客户端就有多少个连接套接字,外加一个监听套接字
第五步:接收数据
int n=recv(接受套接字,数据,大小,标识一般为0); //接收客户端发来的数据
第六步:回复数据
send(接受套接字,数据,大小,标识一般为0)
第七步:关闭接收套接字
客户端
第一步:创建套接字
int sockfd=socket(设置协议ipv4,创建流式套接字,0) //创建套接字,返回失败为-1 同样选用ipv4流式套接字
第二步:创建连接套接字
在这里,客户端设置的是要连接的服务器的端口,不用设置自己的端口,因为我们要给服务其发送数据,就比如我们打电话一样,需要输入对方的号码,不需要自己的手机号码!!!!!!!!!
int connect(套接字,通用套接字地址,地指大小); //创建连接套接字连接服务器
第三步:从键盘输入数据发送给服务器
send(套接字,数组,数据大小,标识为0);
第四步:接收服务器回复的数据
recv(套接字,字符串数组,接收的大小,标识为0);
第五步:关闭套接字
close(套接字);
udp协议:无连接 不可靠 数据报
udp客户端发数据时不在乎服务器的状态,只管发数据,成功与否不管,数据会一直积压在本地,当服务器打开后又会传递给服务器
udp服务器端
第一步:创建数据报套接字
socket(AF_INET,SOCK_DGRAM,0); //参数地址族、服务类型ipv4、恒为0
第二步:指定命名绑定端口号
bind(套接字、通用套接字地址、地址大小); //绑定端口号、指定协议族、设置IP地址
第三步:接收数据
recvfrom(套接字,接收数组,大小,标志位0,通用套接字地址,长度指针);
第四步:回复数据
sendto(套接字,回复内容,大小,标志位0,通用套接字地址,,大小)
udp客户端
第一步:创建数据报套接字
socket(AF_INET,SOCK_DGRAM,0); //参数地址族、服务类型ipv4、恒为0
第二步:设置服务器端口号、IP地址、协议族
struct sockaddr_in saddr中还有第四个成员起占位的作用,我们需要对它置零,因为不太方便,所以我们使用memset函数把saddr中的所有成员全部置零,然后再下面设置协议族,端口号、IP地址
第三步:向服务器发送数据
sendto(套接字,数据数组,数据大小,标志位0,通用套接字地址,地址大小);
第四步:接送服务器回复数据
recvfrom(套接字、存入数组,大小,标志位0,通用套接字地址,地址长度指针);
第五步:关闭套接字
close(套接字)
如果服务器一次只能接收一个字符
那么服务器在接受时候,客户端发多个字符,服务器接收就会丢失数据
tcp和udp区别:
tcp在接收时候客户端发来的数据时,可以先把数据放在发送缓冲区中,一起再发给服务器的接收缓冲区,tcp有应答机制;udp客户端在发送数据时会直接发数据报给服务器,服务器在接收时接受不完就会数据丢失,成功不成功发送客户端不管,所以不可靠
tcp拥塞控制方法:慢开始、拥塞避免、快重传、快恢复
慢开始
传数据时,数据量由小到大逐渐增大发送,按指数规律增长
拥塞避免
慢开始增长到一定量时停止指数规律增长,开始一个一个量增长,加法增长
快恢复
当网络拥塞,数据量就快速恢复到1,再慢开始,然后拥塞避免比上一次提前开始
快重传
当服务器重复确认三次后时执行快重传
http是应用层的协议,客户端时浏览器,使用tcp实现传输数据
http请求方法: GET获取服务器资源,不会对服务器端产生影响 POST 对服务器提交数据,对服务器产生影响
应答状态码:200 ok 400 客户端出错 500 服务器出错 300 重定向 100 收到头部数据继续发