TCP套接字编写,多进程多线程版本 Linux网络通信( 二 )


重点:套接字本质上也是一个文件描述符,指向的是一个“网络文件” 。普通文件的文件缓冲区对应的是磁盘,数据先写入文件缓冲区,再刷新到磁盘,“网络文件”的文件缓冲区对应的是网卡,它会把文件缓冲区的数据刷新到网卡,然后发送到网络中 。创建一个套接字做的工作就是打开一个文件,接下来就是要将该文件和网络关联起来,这就是绑定的操作,完成了绑定,文件缓冲区的数据才知道往哪刷新 。
网络字节序我们已经知道,内存中的多字节数据相对于内存地址有着大端和小端的区分 。同样,网络数据流同样有大端和小端的区分 。
思考一下,如何定义网络数据流的地址呢?
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出,接收主机把从网络上接到的字节一次保存在接收缓冲区中,也就是按照内存地址从低到高的顺序保存 。
网络数据流的地址应该这样规定:先发出的数据是低地址,后发出的数据是高地址 。

  • 大端字节序: 高位存放在低地址,低位存放在高地址
  • 小端字节序: 低位存放在低地址,高位存放在高地址

TCP套接字编写,多进程多线程版本 Linux网络通信

文章插图
如果双方主机的数据在内存存储的字节序不同,就会造成接收方收到的数据出现偏差,所以为了解决这个问题,又有了下面的规定:
  • TCP/IP协议规定,网络数据流采用大端字节序,不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据
  • 所以如果发送的主机是小端机,就需要把要发送的数据先转为大端,再进行发送,如果是大端,就可以直接进行发送 。
为了方便我们进行网络程序的代码编写,有下面几个API提供给我们用来做网络字节序和主机字节序的转换,如下:
#include <arpa/inet.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);说明:
  • h代表的是host,n代表的是network,s代表的是16位的短整型,l代表的是32位长整形
  • 如果主机是小端字节序,函数会对参数进行处理,进行大小端转换
  • 如果主机是大端字节序,函数不会对这些参数处理,直接返回
注意:在编程中我们需要自行进行大小端转化的就只有三个:ip地址,传输数据和端口,这两个数据需要我们进行大端的转化,其他的在计算机组包的时候会自动给我们转化 。
Socket常见的API常用的有以下几个,后面会具体的介绍
// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)int socket(int domain, int type, int protocol);// 绑定端口号 (TCP/UDP, 服务器)int bind(int socket, const struct sockaddr *address,socklen_t address_len);// 开始监听socket (TCP, 服务器)int listen(int socket, int backlog);// 接收请求 (TCP, 服务器)int accept(int socket, struct sockaddr* address,socklen_t* address_len);// 建立连接 (TCP, 客户端)int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);Sockaddr结构体
TCP套接字编写,多进程多线程版本 Linux网络通信

文章插图