Linux网络编程I

1.网络结构模式
  • C/S结构(客户端/服务器)
    • 服务器存有多个用户共享的信息与功能,执行后台服务,如控制共享数据库的操作等
    • 客户端为用户专有,负责执行前台功能,包括出错提示、在线帮助等功能,并且可以在子程序间自由切换。
    • 优点:1)能充分发挥客户端PC的处理能力,很多工作可以在客户端吃力后嫁给服务器,响应速度快;2)操作界面漂亮,个性化定制;3)管理信息系统具有较强的事务处理能力,能实现复杂的业务流程;4)安全性较高,面对固定用户群,对权限进行多层校验,提供了安全的存储模式。
    • 缺点:1)需要安装客户端软件,维护升级成本高;2)操作系统有限制,不能跨平台。
  • B/S结构(浏览器/服务器)
    • WEB浏览器是客户端最主要的应用软件,这种模式统一了客户端,将系统功能实现的核心部分集中到服务器上,简化了系统的开发、维护和使用。
    • 客户机上只要安装有浏览器,即可通过Web Server与服务器上的数据交互。
    • 优点:成本低、维护方便、分布性强、开发简单。客户端零成本,系统的扩展容易。
    • 缺点:通信开销大、系统和数据的安全性较难保障;协议是固定的http/https,无法操作大数据量文件;客户端服务器端的交互时请求-响应模式,动态刷新页面,响应速度低。
 
2.协议。网络协议,规定通信计算机双方必须遵从的一组规则,体现为在网络上传输的数据包的格式。协议往往分为几个层次定义,某一层协议的改变不影响其他层次的协议。
 
3.常见的协议:
  • 应用层:文件传输协议FTP,HTTP协议,网络文件协议NFS。
  • 传输层:TCP协议,UDP协议。
  • 网络层协议:IP协议,网际控制报文协议ICMP,网络组报文协议IGMP,地址解析协议ARP。
 
4.UDP数据报首部
 
5.TCP报文段的首部
 
6.协议封装。上层协议如何使用下层协议提供的服务?
  • 应用程序数据在发送到物理网络之前,将沿着协议栈从上往下依次传递。每层协议都在上层数据的基础上加上自己的头部信息和尾部信息,以实现该层的功能。
 
7.数据报分用。接收方计算机如何准确接受到信息?
  • 当帧到达目的主机后,将沿着协议栈自底向上依次传递。各层协议依次处理下层协议传上来的数据,以获取所需要信息,并将最终处理后的数据交给目标程序。
  • 分用依靠的是数据报头部信息中的类型字段实现的。
 
8.ARP地址解析协议。解决同一局域网上的主机/路由器的IP地址和硬件地址的映射问题。
  • 每一台主机上都有ARP高速缓存,里面存有本局域网上各主机和路由器的IP地址到硬件地址的映射表。每个项目根据生存时间动态更新。
 
9.socket套接字。
  • 网络中不同主机上的应用进程之间进行双向通信的端点的抽象。上联应用进程,下联网络协议栈,是应用进程通过网络协议进行通信的接口。
  • 通信时,其中一个网络应用程序将要传输带一段信息写入它所在主机的socket中,该socket通过与网卡连接的传输介质将这段信息传送到另外一台主机的socket中,使对方能接收到这段信息。
  • socket由IP地址和端口结合,提供向应用进程传送数据包的机制。
  • socket表示进程间网络通信的特殊文件类型。本质为内核借助缓冲区形成的伪文件,因此可以使用文件描述符引用套接字。
  • 与管道类似,Linux将其封装成文件可以统一接口,使得读写套接字和读写文件的操作一致。
 
10.字节序
  • 小端字节序:数据的高位字节存储在内存的高位地址,低位字节存储在内存的低位地址。
  • 大端字节序:数据的高位字节存储在内存的低位地址,低位字节存储在内存的高位地址。
 
11.字节序转换函数。网络字节序是TCP/IP中规定好的数据表示格式,采用大端排序方式。
#include <arpa/inet.h>
uint16_t htons(uint16_t hostshort);        // h: host 主机字节序
uint16_t htonl(uint16_t hostlong);         // n: network 网络字节序
 
uint16_t ntohs(uint16_t hostshort);        // s: short  转换端口
uint16_t ntohl(uint16_t hostlong);         // l: long   转换ip 

 

12.socket地址。所有专用socket地址类型的变量在实际使用时都需要转化成通用socket地址类型sockaddr(强制转换),因为所有socket编程接口使用的地址参数类型都是sockaddr。
# 通用socket地址
#include<bits/socket.h>
strcuct sockaddr {
    sa_family_t sa_family;            // 地址族,对应协议族,PF_UNIX, AF_UNIX: Unix本地域协议族;PF_INET, AF_INET: TCP/IPv4协议族;PF_INET6, AF_INET6: TCP/IPv6协议族
    char sa_data[14];                 // socket地址
};
 
struct sockaddr_storage {
    sa_family_t sa_family;
    unsigned long int __ss_align;
    char __ss_padding[128 - sizeof(__aa_align)];
};
typedef unsigned short int sa_family_t;
 
# 专用socket地址
#include <netinet/in.h>
struct sockaddr_in {
    sa_family_t sin_family;
    in_port_t sin_port;          // 端口
    struct in_addr sin_addr;     // ip
    unsigned char sin_zero[sizeof(struct sockaddr) - __SOCKADDR_COMMON_SIZE - sizeof(in_port_t_ - sizeof(struct in_addr)];
};
 
struct in_addr {
    in_addr_t s_addr;
};
typedef unsigned short uint16_t;    // 2字节
typedef unsigned int   uint32_t;    // 4字节
typedef uint16_t in_port_t;
typedef uint32_t in_addr_t;

 

13.IP地址转换。(字符串ip - 整数,主机、网络字节序的转换)
# 点分十进制字符串表示的IPv4地址和用网络字节序整数标表示的IPv4地址之间的转换
#include <arpa/inet.h>
int inet_pton(int af, const char *src, void *dst);        // p: point 点分十进制的IP字符串,n: network 网络字节序的整数
    - af: 地址族 AF_INET AF_INET6
    - src: 需要转换的点分十进制的IP字符串
    - dst: 转换后的结果,可以用int类型保存,正好4个字节
 
const char *inet_ntop(int af, const void *src, char *dst, socken_t size);
    - af: 地址族 AF_INET AF_INET6
    - src: 需要转换的ip的整数的地址
    - dst: 转换成IP地址字符串保存的地方 char ip[16];
    - size: 第三个参数的大小(数组的大小)
    - 返回值:返回转换后的数据的地址,和dst一样

 

14.TCP通信流程。
// 服务器端(被动接受连接的角色)
1. 创建一个用于监听的套接字(文件描述符)
2. 将这个监听文件描述符和本地的IP和端口绑定(IP和端口就是服务器的地址信息)
       - 客户端连接服务器端的时候用的就是这个IP和端口
3. 设置监听,监听的fd开始工作
4. 阻塞等待,当有客户端发起连接,解除阻塞,接收客户端的连接,会得到一个和客户端通信的套接字(新的fd)
5. 通信
        - 接收数据
        - 发送数据
6. 通信结束,断开连接
 
// 客户端
1. 创建用于连接的套接字(fd)
2. 连接服务器,需要指定连接服务器的IP和端口
3. 连接成功,客户端可以直接和服务器通信
        - 接收数据
        - 发送数据
4. 通信结束,断开连接
 
15.套接字函数
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
int socket(int domain, int type, int protocol);
    - 作用:创建一个套接字
    - domain: 协议族,F_UNIX 本地套接字通信;AF_INET IPv4;AF_INET6 IPv6
    - type: 通信过程中使用的协议类型,SOCK_STREAM: 流式协议;SOCK_DGRAM: 报式协议
    - protocol: 具体的协议,一般为0,SOCK_STREAM: 流式协议默认使用TCP;SOCK_DGRAM: 报式协议默认使用UDP
    - 返回值:成功返回文件描述符,操作单是内核缓冲区;失败返回-1并设置errno
 
int bind(int sockfd, const struct *sockaddr, socklen_t *addrlen);
    - 作用:绑定,将fd和本地的IP和端口进行绑定
    - sockfd: 通过socket函数得到的文件描述符
    - addr: 需要绑定的socket地址,这个地址封装了ip和端口号的信息
    - addrlen: 第二个参数结构体占的内存大小
    - 返回值:成功返回文件描述符,操作的是内核缓冲区;失败返回-1并设置errno
 
int listen(int sockfd, int backlog);
    - 作用: 监听这个socket上的连接
    - sockfd: 通过socket函数得到的文件描述符
    - backlog: 未连接和已连接的和的最大值,有未连接和已连接的2个队列,一旦accept()之后,将从已连接队列中剔除?
    - 返回值:成功返回文件描述符,操作单是内核缓冲区;失败返回-1并设置errno
 
int accept(int sockfd, const struct *sockaddr, socklen_t *addrlen);
    - 作用:接收客户端连接,默认是阻塞函数,阻塞等待客户端的连接
    - sockfd: 用于监听的文件描述符
    - addr: 传出参数,记录连接成功后的客户端的地址信息(ip,port)
    - addrlen: 第二个参数占的内存大小
    - 返回值:成功返回用于通信的文件描述符;失败返回-1并设置errno
 
int connect(int sockfd, const struct *sockaddr, socklen_t addrlen);
    - 作用:客户端连接服务器
    - sockfd: 用于通信的文件描述符
    - addr: 客户端要连接的服务器的地址信息
    - addrlen: 第二个参数占的内存大小
    - 返回值:成功返回0;失败返回-1并设置errno
 
ssize_t write(int fd, const void *buf, size_t count);
ssize_t read(int fd, void *buf, size_t count);

 

16.滑动窗口理解。
  • 窗口理解为缓冲区大小
  • 滑动窗口的大小会随着发送和接收数据而变化
  • 通信双方都有发送缓冲区和接收缓冲区
发送方的缓冲区:
    白色格子:空闲的空间
    灰色格子:数据已经发送,但还是未被接收
    紫色格子:还没有发送出去的数据
 
接收方的缓冲区:
    白色格子:还可以接收数据的空闲空间
    紫色格子:已接收的数据
 
 
17.TCP三次握手和四次挥手。
  • 建立连接三次握手,断开连接四次挥手。
  • 标志位SYN=1和FIN=1,要消耗一个序号。
  • 四次挥手发生在断开连接时,在程序中调用close()会使用TCP协议进行4次挥手。客户端和服务器端都可以主动发起断开连接,谁先调用close()谁就是发起。
 
 
 
 
posted @ 2021-08-09 21:13  萌新的学习之路  阅读(45)  评论(0编辑  收藏  举报