网络编程

网络编程

概念

TCP:用来检测网络传输中差错的传输控制协议,可靠传输协议

IP:专门负责对不同网络进行互联的互联网协议IP,不可靠传输协议

网络采用分层的思想:

  • 每一层实现不同的功能,对上层的数据做透明传输
  • 每一层向上层提供服务,同时使用下层提供的服务

两种体系结构:

OSITCP/IP层级
应用层应用层高层
表示层
会话层
传输层传输层底层(内核)
网络层网络层
数据链路层
物理层网络接口与物理层

网络接口与物理层(Link Layer):屏蔽硬件差异(驱动),提供统一的接口,使用struct net_device描述底层设备

网络层(Internet Layer):端到端的传输(从设备到设备),也叫做IP层

传输层(Transport Layer):决定数据包应该交给哪一个任务处理

应用层(Application Layer):协议层,有FTP、HTTP、DNS等协议

各层日常需要掌握的协议:

  • 网络接口与物理层:
    • MAC地址:48位全球唯一,网络设备的身份标识
    • ARP/RARP:ARP:IP地址---->MAC地址, RARP:MAC地址---->IP地址
    • PPP协议:拨号协议
  • 网络层:
    • IP协议(分为IPv4和IPv6)
    • ICMP:Internet管理控制协议
    • IGMP:Internet分组管理协议
  • 传输层:
    • TCP:提供面向连接的,一对一的可靠数据传输的协议
    • UDP:提供不可靠,无连接的尽力传输协议,但是效率高
    • SCTP:TCP增强版,提供面向连接的,多对一或多对多的可靠传输协议
  • 应用层:
    • 网页访问协议:HTTP/HTTPS
    • 邮件收发协议:POP3(收)/SMTP(发)、IMAP(可接受邮件的一部分)
    • FTP
    • Telnet/SSH:远程登陆
    • NTP:网络时钟协议
    • SNMP:简单网络管理协议(实现对网络设备的集中式管理)(开源)
    • RTP/RTSP:用传输音视频的协议(安防监控)

可靠:数据无误,数据无丢失,数据无失序,数据无重复到达的通信

网络的封包和拆包:

  • 封包:
    • 应用层有一个数据data
    • 传输层依照协议给数据加一个头TCP头|data
    • 网络层依照协议给数据加一个头IP头|TCP头|data
    • 网络接口与物理层给数据加一个头和一个尾以太网头|IP头|TCP头|data|CRC验证,此时组成了一个完整的包
  • 拆包:
    • 和封包反序,中间路由器会替换包头
以太网头IP头TCP头dataCRC验证
14字节20字节20字节1460字节4字节

CRC是硬件产生和校验的

MTU:Max Transfer Unit,最大传输单元,与网络类型有关,以太网MTU = 1500
MSS:MAXIUM Segmum Size,真正的用户数据有多大,以太网MSS = 1460


预备知识

socket IP地址 端口号 字节序

Socket:

  • socket是一个编程的接口(用户态与内核态之间),是一种特殊的文件描述符(可对其执行IO操作函数,比如:read(),write())
  • 代表网络编程的一种资源

socket类型:

  • 流式套接字(SOCK_STREAM):唯一对应TCP
  • 数据报套接字(SOCK_DGRAM):唯一对应UDP
  • 原始套接字(SOCK_RAW):对应多个协议,传输时穿透传输层,可以对低层次协议直接访问,如:IP、ICMP

IP地址

IP地址分为IPv4和IPv6,IPv4最终都会转换为32位二进制数来表示

  • IPv4:采用32位二进制数来表示 点分形式:192.168.1.1
  • IPv6:采用了128位二进制数来表示
  • mobileIPv6:local IP(本地注册的IP), roam IP(漫游IP)
  • 特殊IP:
    • 局域网IP:192.XXX.XXX.XXX 10.XXX.XXX.XXX
    • 广播IP:XXX.XXX.XXX.255 255.255.255.255(全网广播)
    • 组播IP:224.XXX.XXX.XXX~239.XXX.XXX.XXX

NAT 转发包??

端口号

区分一台主机收到数据包应该转交给哪个任务

  • 16位二进制数字(1-65535)
  • 已用端口:1~1023(FTP: 21, SSH: 22, HTTP: 80, HTTPS: 469),不建议使用
  • 保留端口:1024~5000(不建议使用)
  • 可以使用:5000~65535
  • UTP端口与TCP端口独立

网络中的通信是IP地址+端口号来决定

IP数据流走向图解 ??

字节序

字节序是指不同的CPU访问内存中的多字节数据的时候,存在字节序的问题(大小端的问题),访问字符不存在大小端问题

0x12345678

高端-----低端

内存高端内存低端字节序
12345678大端
56781234小端

一般来说:

  • X86/ARM:小端
  • powerpc/mips,ARM作为路由器:大端模式

网络传输的时候采用大端模式

本地字节序、网络字节序:

  • 传输时,在网络中间传输时使用网络字节序,在两端需要分别转换位本地字节序
  • 本地字节序转网络字节序:
    • u_long htonl(u_long hostlong); h host本地 n network网络 ulong 4字节
    • u_short htons(u_short short);short 2字节
  • 网络字节序转本地字节序:
    • u_long ntohl(u_long hostlong);
    • u_short ntohs(u_short short);

IP地址的转换:

  • in_addr_t inet_addr(const char *cp);
    • cp是点分形式的IP地址,结果是32位二进制数,内部包含字节序转换
    • 仅用于IPv4
    • 出错返回-1
    • 此函数不能用于255.255.255.255的转换
  • int inet_pton(int af, const char *src, void *dst);
    • 适用于IPv4和IPv6
    • 能正确处理255.255.255.255的转换问题
    • 参数:
      • af:地址协议族(AF_INET或AF_INET6)
      • src:p是一个指针src(填写点分形式的IP地址【IPv4】或以冒号分隔的IP地址【IPv6】)
      • dst:转换的结果给到dst
    • 返回1成功

TCP编程的API

socket() bind() listen() accept() connect()

socket()

函数原型:int socket(int domain, int type, int protocol)

函数头文件:

  • #include <sys/types.h> /* See NOTES */
  • #include <sys/socket.h>

函数功能:创建一个主动套接字

函数参数:

  • domain:
    • AF_INET IPv4 Internet protocols ip(7)
    • AF_INET6 IPv6 Internet protocols ipv6(7)
    • AF_LOCAL Local communication unix(7)
    • AF_NETLINK Kernel user interface device netlink(7)
    • AF_PACKET Low level packet interface packet(7)
  • type:
    • SOCK_STREAM
    • SOCK_DGRAM
    • SOCK_RAW
  • protocol:一般填0,原始套接字编程时需要填充

函数返回值:成功返回文件描述符,失败返回-1


bind()

函数原型:int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数头文件:

  • #include <sys/types.h> /* See NOTES */
  • #include <sys/socket.h>

函数功能:为套接字绑定IP信息

函数参数:

  • sockfd:通过socket()函数拿到的fd
  • addr:采用struct sockaddr的结构体变量的地址
  • addrlen:地址的长度

通用结构体:

struct sockaddr {
   sa_family_t sa_family;     //2字节
   char        sa_data[14];   //14字节
}

基于Internet通信的结构体

struct sockaddr_in {
               sa_family_t    sin_family; /* address family: AF_INET 2字节*/
               in_port_t      sin_port;   /* port in network byte order 2字节*/
               struct in_addr sin_addr;   /* internet address 4字节*/
               //sin_zero[8] 填充8字节
           };

           /* Internet address. */
           struct in_addr {
               uint32_t       s_addr;     /* address in network byte order 4字节*/
           };

sin_addr可以设置为INADDY_ANY,使得服务器端可以在任意IP上运行,从本机任意网卡接收信息

实际使用的时候用sockaddr_in类型,然后将sockaddr_in强转成sockaddr类型,填入函数

   //绑定bind
   //2.1填充sockaddr_in结构体
   bzero(&sin, sizeof(sin));//清空sin
   sin.sin_family = AF_INET;
#if 0
   sin.sin_port = htons(SERV_PORT);//将本地字节序的端口号转变为网络字节序的端口号
#else
   sin.addr.s_addr = inet_addr(SERV_IP_ADDR);//IPv4的IP地址转换
   int ret = inet_pton(AF_INET, SERV_IP_ADDR, (void *)&sin.sin_addr_s_addr);
   if (ret != 1)
   {
      perror("inet_pton error");
      exit(1);
   }

   //2.2绑定
   ret = bind(fd, (struct sockaddr *)&sin, sizeof(sin));
   if (ret < 0)
   {
      perror("bind error");
      exit(1);
   }

函数返回值:成功返回0,失败返回-1


listen()

函数原型:int listen(int sockfd, int backlog)

函数头文件:

  • #include <sys/types.h> /* See NOTES */
  • #include <sys/socket.h>

函数功能:把主动套接字(客户端)变为被动套接字(服务器端)

函数参数:

  • sockfd:socket()返回的文件描述符
  • backlog:同时允许几路客户端和服务器正在连接的过程(正在3次握手)
    • 一般填5,ARM最大为8

内核中服务器的套接字fd会维护两个链表:

1.正在三次握手的客户端链表(数量 = 2 * backlog + 1)

2.已经建立好连接的客户端链表(已经完成三次握手分配好了newfd)

函数返回值:成功返回0,失败返回-1


accept()

函数原型:int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

函数头文件:

  • #include <sys/types.h> /* See NOTES */
  • #include <sys/socket.h>

函数功能:阻塞等待客户端的连接请求

函数参数:

  • sockfd:经过socket()创建,bind(),listen()设置过的文件描述符
  • addr:接收客户端的信息(IP地址、端口号)
  • addrlen:

函数返回值:成功返回已经建立好连接的一个新fd(newfd),然后就可以进行具体的读和写,失败返回-1

本身的fd可以继续等待要与服务器建立连接的客户端


connect()

函数原型:int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

函数头文件:

  • #include <sys/types.h> /* See NOTES */
  • #include <sys/socket.h>

函数功能:将客户端连接至服务器

函数参数:

  • sockfd:由函数socket()创建的主动套接字
  • addr:包含地址信息和端口信息的结构体指针
  • addrlen:addr的长度

函数返回值:成功返回0,失败返回-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值