目录
sockaddr , sockaddr_in , in_addr区别
简单对比TCP和UDP
TCP
TCP协议是TCP/IP协议栈中的典型协议, 它是一个传输控制协议, 特性是面向连接, 可靠传输, 面向字节流
面向连接:主要是通过三次握手和四次挥手来进行一个连接管理, 并且通过状态信息标记连接当中的状态变化来维持这个连接.
可靠传输:主要是为了保证数据可靠的到达对端, 主要是连接之后再进行数据通信, 连接建立之后通过确认应答机制以及超时重传机制保证数据能够到达对端, 通过协议字段的序号和确认序号进行包序管理, 保证数据有序的到达对端, 通过校验和来校验数据的一致性, 不一致则数据丢弃, 要求重传.
TCP为了保证可靠传输牺牲了一定的性能, 因此我们要提高性能, 使用滑动窗口机制来避免丢包重传, 主要有流量控制, 避免因为发送数据过快而接收处理过慢导致的接收缓冲区满溢而导致丢包, 以及拥塞控制, 以一种慢启动快增长的方式向对方发送数据, 避免因为网络状况而导致的大量丢包, 还有快速重传机制, 接收数据过程中如果接收到了后面的数据但是前面的数据没有接收到, 就给发送方连传三条重传请求, 要求对端进行重传, 通过这种方式避免丢包造成的性能下降, 同时也引入了捎带应答机制, 是我们发送数据的时候将确认回复一块放进去, 来减少不必要的空包头的传输, 并且使用延迟应答机制, 保证网络吞吐量过大的情况下传输速度不会降低
面向字节流: TCP调用接口send发送数据, 将数据放到发送缓冲区中, 接收的时候放到接收缓冲区中, 操作系统选择合适的时机取出合适的大小(MSS), 将数据发送/接收, 数据收发并没有限制大小, 所以传输比较灵活, 但是会由一个缺陷就是数据粘包问题, 主要是因为在传输层对数据的边界不敏感, 因此我们可以在应用层进行处理, 处理方法可以以特殊字符进行间隔, 可以数据定长, 还可以在应用层协议头中定义数据长度.
UDP
无连接: 通信的时候不需要建立连接, 只需要知道对方地址信息, 就可以发送数据
不可靠: 通信过程中, 并不保证数据安全可靠以及有序的到达对端
面向数据报: 因为定义了报文长度, 因此sendto在发送的时候, 数据一到达发送缓冲区就会封装头部发送出去, 用户recvfrom的时候不会出现半条或者多条数据的情况
创建套接字实质
创建套接字的实质:创建套接字实际就是在内核中创建了一个struct socket{..};在这个结构体中有两个缓冲区,一个是接受缓存区,一个是发送缓冲区,操作系统的职责实际上,是将网卡接收到的数据,进行端口辨认,拷贝到不同的socket缓存区,程序员在调用的操作系统定义的接口(sendto,recvfrom)实际上就是和socket缓存区打交道。
socket应用编程接口详解(包括UDP&TCP编程接口)
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *addr,socklen_t add_len);
// 开始监听socket (TCP, 服务器)
int listen(int sockfd, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int sockfd struct sockaddr* addr,socklen_t* add_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen)
//发送函数(一般用在UDP 客户端,服务端)
ssize_t sendto (int sockfd,const void *buf,int flags,const struct sockaddr *dest_adddr,sockle_t addrlen);
//接收函数 (一般用在UDP 客户端,服务端)
ssize_t recvfrom(int sockfd,void* buf.size_t len,int flags,struct sockaddr* src_addr,socklen_t addrlen) ;
//发送函数 (一般用在TCP 客户端,服务端)
ssize_t send(int sockfd, void *buf, size_t len int flags)
//接收函数 (一般使用在TCP 客户端,服务端)
ssize_t recv(int sockfd, void *buf, size_t len int flags)
基本TCP&UDP编程接口详解:
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol); 包含在 sys/types.h 或者sys/socket.h
domain:地址域,传入的是协议的版本
网络层::AF_ INET --> ipv4版本的ip协议
网络层:AF_ INET6 --> ipv6版本的ip协议
type:套接字的类型
传输层: tcp/udp
SOCK_ STREAM:流式套接字--》默认对应的协议: tcp,不枝持udp
SOCK_ DGRAM:数据报套接字--》默认对应的协议: udp,不支持tcp
protocol:协议类型
0 :采套接字对应的默认类型
IPPROTO_ TCP-->6
IPPROTO_ UDP-->17
返回值:返回套接字的操作句柄,实际上就是一个文件描述符,称为套接字描述符
eg:
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *addr,socklen_t addr_len);包含在 sys/types.h 或者sys/socket.h
socket: 套接字操作句柄,上面 socket函数返回值。
addr:通用的socket地址,下面会详讲。
addr_len:地址信息长度
返回值:成功 0 失败-1
sockaddr , sockaddr_in , in_addr区别
其实sockaddr 和sockaddr_in 二者的占用的内存大小是一致的,因此可以互相转化,从这个意义上说,他们并无区别。
sockaddr常用于bind、connect、recvfrom、sendto等函数的参数,指明地址信息。是一种通用的套接字地址。
sockaddr_in 是internet环境下套接字的地址形式。所以在网络编程中我们会对sockaddr_in结构体进行操作。使用sockaddr_in来建立所需的信息,最后使用类型转化就可以了。
虽然socket api的接口是sockaddr, 但是我们真正在基于IPv4编程时, 使用的数据结构是sockaddr_in; 这个结构里主要有三部分信息: 地址类型, 端口号, IP地址.一般先把sockaddr_in变量赋值后,强制类型转换后传入用soc