
先做一个了解认识TCP协议TCPTransmission Control Protocol传输控制协议有一个直观的认识。传输层协议有连接先建立专属通道再传数据传完还要断开可靠传输面向字节流。认识UDP协议UDPUser Datagram Protocol用户数据报协议有一个直观的认识后面再详细讨论。传输层协议无连接不用提前建立通道直接发数据包发出去不管对方收没收到不可靠传输面向数据报。我们这里的可靠和不可靠我们把他们当作特点而不是优缺点因为只要可靠就会做更多的工作。因此UDP协议会更轻量化。网络字节序小端低字节权值放低地址小 小 小大端低字节(权值)放高地址跨主机通信时不管你电脑是大端还是小端发送前统一转成网络大端序接收后再转回本地主机序保证数据解析一致。先发出的数据是低地址后发出的数据是高地址。统一的接口上面那个struct sockaddr是基类下面两个是子类。sockaddr_instruct sockaddr_in { sa_family_t sin_family; /* address family: AF_INET */ in_port_t sin_port; /* port in network byte order */ struct in_addr sin_addr; /* internet address */ };1、sa_family_t sin_family作用指定通信协议簇IPv4 固定赋值AF_INET如果以后用 IPv6则使用AF_INET62、in_port_t sin_port类型uint16_t无符号短整型16‑bit存放端口号硬性规则必须是网络字节序大端序主机字节序转网络字节序函数htons(端口号)3、struct in_addr sin_addr 存放 IP 地址内层结构体定义struct in_addr{ in_addr_t s_addr; // 32位无符号整型网络字节序的IP };UDP套接字recvfrom网络编程里用来 “接收 UDP 数据” 的函数。因为 UDP无连接不知道谁发的所以必须用这个函数把 “数据 发送方地址” 一起拿回来。ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);sockfdUDP socket 文件描述符buf接收缓冲区len缓冲区最大字节数flags一般填0MSG_NONBLOCK非阻塞src_addr输出参数保存对端发送者 IP 端口addrlen传入 传出初始为结构体长度函数返回后是对方地址实际长度recvfrom返回值0读到的字节数量0对方正常关闭-1出错bindint bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockfdsocket () 返回的文件描述符UDP 为SOCK_DGRAMaddr指向sockaddr_in结构体存放本机 IP、端口addrlen地址结构体大小sizeof(struct sockaddr_in)bind的返回值成功返回0失败返回-1errno 保存错误bind和recvfrom互相配合使用。bind给套接字固定本机 IP 端口recvfrom在绑定好的端口上阻塞等待别人发过来的 UDP 数据包顺带拿到发送者地址二者是先 bind后 recvfrom整体工作流程UDP 服务端顺序绝对不能乱socket()创建 UDP 套接字文件描述符填充sockaddr_in本机 ip、监听端口bind () → 把 socket 绑定到指定端口操作系统就知道发到本机该端口的 UDP 数据包交给这个 socket调用recvfrom()在已经绑定好的端口阻塞监听、接收报文没有 bindsocket 没有固定端口客户端不知道往哪个端口发数据你自然收不到消息