计算机网络的体系结构
网络采用分而治之的方法设计,将网络的功能划分为不同的模块,以分层的形式有机结合在一起
每层实现不同的功能,其内部实现的方法对外部其他层次来说是透明的,每层向上一层提供服务,使用下一层提供的服务;
两类非常重要的体系结构:
开放式系统互联(opensystem interconnection 简称 OSI)和TCP/IP
OSI系统模型(7层)
OSI系统模型是国际化标准组织(IS0)为了实现计算机网络标准化颁布的参考型,根据网络中数据传输的过程,:将该模式分为7个层,每一层都向上一层提供服务,同时使用下层提供的服务。
TCP/IP 系统模型(4层)
国际化标准组织(IS0)指定的 0SI参考模型虽然规定得十分细致和完善,但在实际中却得不到广泛应用,原因就是它过于庞大和复杂,但它仍是此后众多协议模型的基础,与oS的复杂相比,TCP/IP 协议的四层结构模型获得了更广泛的使用。TCP/IP 协议是Internet事实上的工业标准。
TCP/IP的三次握手和四次挥手
三次握手
3次握手协议:TCP 是面向连接,所谓面向连接,就是计算机双方通信时必须先建立连接,然后进行数据通信。最后断开连接。TCP在建立连接时,有以下三个步骤;
第一次握手)客户端发送一个 SYN(包含有同步序列号的标志位的数据段和通信请求)给服务器,客户端进入SYN SEND 状态,然后等待服务器的回发确认信息
第二次握手) 服务器发一个 SYN+ACK 给客户端,确认已经收到客户端发来的信息,此时服务器进入SYN RECV状态;
第三次握手) 客户端接收到服务器发来的确认信息后,再反馈一个 ACK给服务器,完成三次握手,客户端和服务器进入ESTABLISHED状态,到此一个TCP连接就完成了。
四次挥手
因为TCP/IP 的连接是双向的,所以每个方向都要单独进行关闭。
每当TCP单方向的数据传输结束后,都会再发送一个 FIN 过去,告诉对方我这个方向上的数据要关闭了,当双方接收到FIN后,就会通知应用层,TCP连接已经终止了数据传输。
第一次断开:客户端向服务器端发送数据后,将 FIN置1,告诉它要关闭这一方向上的数据传输。
第二次断开:服务器接收到FIN后,将 ACK置1发送客户端
第三次断开:向客户端申请反方向的数据断开,将FIN置1。
第四次断开:客户端接收到服务器端发来的请求,将 ACK置1,双方同时关闭连接
套接字(Socket)
Socket是独立于具体协议的网络编程接口,在OSI模型中,主要位于会话层和传输层之间在Linux 下,套接字是一种特殊的IO接口,也是一种文件描述符。
Socket类型
流式套接字(SOCK STREAM)
提供了一个面向连接、可靠的数据传输服务,数据无差错、无重复的发送且按发送顺序接收。内设置流量控制,避免数据流淹没慢的接收方。数据被看作是字节流,无长度限制。
数据报套接字(SOCK DGRAM)
提供无连接服务。数据包以独立数据包的形式被发送,不提供无差错保证,数据可能丢失或重复,顺序发送,可能乱序接收。
原始套接字(SOCK RAW)
可以对较低层次协议,如IP、ICMP直接访问。功能强大但使用较为不便主要用于一些协议的开发
套接字相关函数
socket:创建一个套接字。
函数 | socket |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | int socket(int domain, int type, int protocol); |
功能 | 创建一个套接字。 |
参数 | 1.domain:协议族。 AF_INET AF_INET6 2.type:协议类型 SOCK_DGRAM,SOCK_STREAM,SOCK_RAW 3.protocol:指定应用程序使用的通讯协议,一般取值为0,让系统决定使用的协议。 |
返回值 | 成功:返回新建的套接字描述符;失败:返回-1。并将错误码放入 errno |
bind:绑定一个套接字。
函数 | bind |
头文件 | #include <sys/socket.h> #include <sys/types.h> #inclue <netinet/in.h> |
函数原型 | int bind(int sockfd, struct sockaddr* addr, int addlen); |
功能 | 绑定一个套接字。 |
参数 | 1.sockfd:套接字描述符。 2.addr:指向sockaddr结构体的指针,标识绑定的IP,端口,协议族等信息, 通常情况下使用另一个 结构体。sockaddr_in 3.addlen:sockaddr结构体长度。 |
返回值 | 成功:返回0, 失败:返回 -1 错误存放在errno 中 |
htons,htonl,ntohs,ntohl:从主机字节序转换成网络字节序,或者相反
函数 | htons,htonl,ntohs,ntohl |
头文件 | #include <netinet/in.h> |
函数原型 | uint32_t htonl(uint32_t hostlong); uint16_t htons(uint16_t hostshort); uint32_t ntohl(uint32_t netlong); uint16_t ntohs(uint16_t netshort); |
功能 | htonl:把32位值从主机字节序转换成网络字节序; htons:把16位值从主机字节序转换成网络字节序; ntohl:把32位值从网络字节序转换成主机字节序; ntohs:把16位值从网络字节序转换成主机字节序。 |
参数 | 1.hostlong:32位主机字节序的数据。 2.hostshort:16位主机字节序的数据。 3.netlong:32位网络字节序的数据。 4.netshort:16位网络字节序的数据。 |
返回值 | 已经转换好的数据 |
inet_addr,inet_ntoa:字符串转换为网络字节序,或者相反
函数 | inet_addr,inet_ntoa |
头文件 | #include <netinet/in.h> #include <arpa/inet.h> |
函数原型 | uint32_t inet_addr(const char * cp); char * inet_ntoa(struct in_addr in); |
功能 | inet_addr: 点分十进制地址字符串转换为32位网络字节序; inet_ntoa: 将32位值从网络字节序转换成主机字节序的点分 十进制IP字符串; |
参数 | 1.inet_addr的参数为点分十进制地址字符串方式IP信息; 执行成功,返回32位IP地址,并且是网络存储顺序; 2.inet_ntoa的参数为网络字节序的IP信息; 执行成功,返回主机字节序的点分十进制IP字符串; |
返回值 | 已经转换好的数据 |
recvfrom:接收对方主机传送来的数据
函数 | recvfrom |
头文件 | #include <sys/types.h> #include <sys/socket.h> |
函数原型 | int recvfrom(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen); |
功能 | 用来由指定的socket接收对方主机传送来的数据. |
参数 | 1.sockfd:标识一个套接字的描述符。 2.buf:接收数据缓冲区。 3.len:缓冲区长度。 4.flags:调用操作方式,一般设0。 5.from:[OUT]对方主机的网络地址 6.fromlen:对方主机地址sockaddr 的结构长度 |
返回值 | 成功:返回实际传送的字符数;失败:返回-1,错误原因存于errno 中 |
sendto:将数据由指定的socket传给对方
函数 | sendto |
头文件 | #include <sys/types.h> #include <sys/socket.h> |
函数原型 | int sendto(int sockfd, void *buf, int len, unsigned int flags, struct sockaddr *to, int tolen); |
功能 | 用来将数据由指定的socket传给对方主机 |
参数 | 1.sockfd:标识一个套接字的描述符。 2.buf:发送数据缓冲区。 3.len:实际发送的数据长度。 4.flags:调用操作方式,一般设0。 5.to:欲传送的网络地址, 6.tolen:sockaddr 的结构长度。 |
返回值 | 成功:返回实际传送的字符数;失败:返回-1,错误原因存于errno 中。 |
setsockopt:设置套接字选项
函数 | setsockopt |
头文件 | #include <sys/types.h> #include <sys/socket.h> |
函数原型 | int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen); |
功能 | 设置套接字选项 |
参数 | 1.sockfd:标识一个套接字的描述符。 2.level:指定控制套接字的层次.可以取三种值: 3. optname:待设置套接字选项的名称。(取决于level) 4. optval:选项的取值。(注意传递变量地址,变量中存储取值) 5. optlen:选项值的长度, |
返回值 | 成功:0;失败:返回-1,错误原因存于errno 中 |
listen:监听,等待客户端连接。
函数 | listen |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | int listen(int sockfd, int backlog); |
功能 | 监听,等待客户端连接。 |
参数 | 1.sockfd:要监听的套接字描述符。 2.backlog:可排队连接的最大连接数 |
返回值 | 成功:返回0;失败:返回-1。并将错误码放入 errno |
connect:建立与TCP 服务器的连接。
函数 | connect |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | int connect((int sockfd, struct sockaddr* addr, int addlen)); |
功能 | 建立与TCP 服务器的连接。 |
参数 | 1.sockfd:客户端套接字描述符。 2.addr:服务器端的地址信息; 3.addlen:sockaddr结构的长度 |
返回值 | 成功:返回0; 失败:返回-1。并将错误码放入 errno |
accept:TCP 服务器接受客户端的连接请求。
函数 | accept |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | int accept(int sockfd, struct sockaddr* addr, int* addlen); |
功能 | TCP 服务器接受客户端的连接请求。 |
参数 | 1.sockfd:服务器端套接字描述符。 2.addr:指向sockaddr结构指针,接收客户端IP信息; 3.addlen:sockaddr结构的长度 |
返回值 | 成功:返回一个新的套接字描述符,用它来和客户端通信; 失败:返回-1。并将错误码放入 errno |
send:向一个已经连接的套接字发送数据。
函数 | send |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | size_t send(int sockfd, const void* buf, size_t len,int flags); |
功能 | 向一个已经连接的套接字发送数据。 |
参数 | 1.sockfd:已连接套接字描述符。 2.buf:数据缓冲区指针,用于存放要发送的数据 3.len:要发送数据的长度。 4.flags:调用执行方式,一般设为0 |
返回值 | 成功:返回发送的数据总数, 失败: -1 并将错误码放入 errno |
recv:从一个已经连接的套接字接收数据。
函数 | recv |
头文件 | #include <sys/socket.h> #include <sys/types.h> |
函数原型 | size_t recv(int sockfd, void* buf, size_t len,int flags); |
功能 | 从一个已经连接的套接字接收数据。 |
参数 | 1.sockfd:已连接套接字描述符。 2.buf:数据缓冲区指针,用于存放接收到的数据 3.len:数据缓冲区的长度。 4.flags:调用执行方式,一般设为0 |
返回值 | 成功:返回接收的数据总数, 0: 代表客户端断开连接 失败: -1 并将错误码放入 errno |