文章目录
- 网络编程预备知识
- 认识端口号
- 理解源端口号和目的端口号
- 认识TCP协议和UDP协议
- 网络字节序
- sockaddr结构
- 1.socket 常见API
- 2.sockaddr结构
网络编程预备知识
认识端口号
端口号(port)是传输层协议的内容.
端口号是一个2字节16位的整数;
端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
一个端口号只能被一个进程占用.
既然端口号是用来标识一个进程,而我们之前学习进程的时候,pid也可以标识一个进程,那他们之间有什么关系呢?
端口号可以标识一个进程,pid也可以标识一个进程,但是一个端口号只能标识一个进程,而一个进程可以被多个端口号标识,而进程pid与进程是一一对应的。
并且,我们可以通过我们身边的例子来理解,例如我们在出生之后都会有一个身份证号来标识一个,但是在学校的时候通常使用学号来标识一个人,工作的时候通常使用工号来表示一个人,并不是所有的进程都会进行网络通信,反过来只有一少部分进程进行网络通信,大部分都是本地进程,所以使用pid来标识网络通信是不合适的。
理解源端口号和目的端口号
上一篇文章提到了IP地址的作用,通过IP地址和MAC地址可以标识全网唯一的一台机器,而这里的端口号可以唯一的确定一台主机中唯一的一个进程。
我们需要明确的是:
进行网络通信,并不只是两台主机建立联系,而主要任务是在建立联系之后,我们进行进程间通信,将一个进程的数据通过网络传送给另外一个进程,所以与之前的匿名管道,命名管道,信号量,共享内存等进程间通信的方式比较,只是通过网络进行传输而已。
传输层协议(TCP和UDP)的数据段中有两个端口号, 分别叫做源端口号和目的端口号. 就是在描述 “数据是谁发的, 要发给谁”;
认识TCP协议和UDP协议
此处我们也是对UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识;
传输层协议
无连接
不可靠传输
面向数据报
此处我们先对TCP(Transmission Control Protocol 传输控制协议)有一个直观的认识;
传输层协议
有连接
可靠传输
面向字节流
网络字节序
我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?
其实,网络中的数据流传输都是通过大端方式的,但是可能我们的主机是小端,所以我们就需要 引入几个接口来实现大小端的转换:
记忆方法:
这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回 ;
如果主机是大端字节序,这些 函数不做转换,将参数原封不动地返回。
如何区分大小端?
大端就是将高位字节存在低地址处,低位字节存在高地址处。
小端就是将高位字节存在高地址处,低位字节存在低地址处。
sockaddr结构
1.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);
后边在使用时会介绍这些接口。
2.sockaddr结构
socket API是一层抽象的网络编程接口,适用于各种底层网络协议,如IPv4、IPv6,以及后面要讲的UNIX Domain Socket. 然而, 各种网络协议的地址格式并不相同,例如我们不仅可以通过这套接口进行网络之间通信,也可以进行域间套接字通信,所以为了保持接口一致性,设计出了不同的结构,在传参时,传入不同的结构即可。
sockaddr_in结构体用于跨网络通信,sockaddr_un结构体用于本地通信,之所以可以在传入参数时可以通过不同参数来确定网络间通信或者本地通信,因为sockaddr_in和sockaddr_un前两个字节是相同的,是用来标定协议家族的,所以我们要对结构体进行填充,在调用时进行强转成sockaddr类型再传入。
sockaddr结构
sockaddr_in结构