目录
预备知识
网络字节序
网络字节序和主机字节序转换的库函数
socket编程接口
socket常见API
sockaddr结构
套接字的种类
预备知识
1.在IP数据包头部中,有两个IP地址,分别叫做源IP地址和目的IP地址。
2.端口号:是传输层协议的内容
- 端口号是一个2字节16位的整数。
- 端口号用来标识一个进程,告诉操作系统,当前的这个数据要交给哪个进程处理。
- IP地址能够唯一标识一台主机,端口号能够标识该主机上的唯一一个进程,因此IP地址 + 端口号能够标识网络上的某一台主机的某一个进程。
- 一个端口号只能被一个进程占用。
问: 进程ID即PID表示唯一一个进程,此处的端口号也表示唯一一个进程,为什么还要有端口号的存在?
从技术角度上,pid可以取代端口号,但是不是所有的进程都要网络通信,但所有进程必须要有pid,端口号的出现实现了系统和网络功能的解耦。
PS:一个进程可以绑定多个端口号,但是一个端口号不能被多个进程绑定,因为要通过端口号找到唯一一个进程。
3.传输层协议(UDP和TCP)的数据段中有两个端口号,分别叫做源端口号和目的端口号,就是在描述“数据是谁发的,发给谁的”。
网络字节序
内存中的多字节数据相对于内存地址有大端和小端之分,磁盘文件中的多字节数据相对于文件中的便宜地址也有大端小端之分,网络数据流同样有大小端之分。
发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出。
接受主机把从网络上收到的字节依次保存在接受缓冲区,也是按内存地址从低到高的顺序保存。
网络数据流的地址应该这样规定:先发出的数据是低地址,后发出的数据是高地址。
TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节。
因此,不管这台主机是大端机还是小端机,都会按照这个TCP/IP规定的网络字节序来发送和 接收数据
即
网络字节序和主机字节序转换的库函数
#include <arpa/inet.h>
//主机字节序转网络字节序
uint32_t htonl (uint32_t hostlong);
uint16_t htons (uint16_t hostshort);
//网络字节序转主机字节序
uint32_t ntohl (uint32_t netlong);
uint16_t ntohl (uint16_t netshort);
socket编程接口
socket常见API
//创建 socket 文件描述符 (TCP / UDP , 客户端 + 服务器)
int socket (int domain, int type, int protocol);
//绑定端口 (TCP / UDP ,服务器)
int bind (int socket, cosnt struct sockaddr* address, scoklen_t address_len);
//开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
//接收请求 (TCP, 服务器)
int accept (int scoket, struct sockaddr* address,socklen_t address_len);
//建立连接(TCP,客户端)
int connect (int sockfd, cosnt struct sockaddr* addr, scoklen_t address_len) ;
sockaddr结构
socket API 是一层抽象的网络编程接口,适用于各种底层网络协议,如 IPv4, IPv6,UNIX Domain Socket, 然而各种网络协议的地址格式并不相同。
套接字的种类
下述三个结构分别为原始套接字、网络套接字、域间套接字
- IPv4, IPv6的地址格式定义在<netinet/in.h>中,IPv4地址用 sockaddr_in结构体表示,包括16位地址类型,16位端口号和32位IP地址。
- IPv4, IPv6地址类型分别定义为常数 AF_INET、AF_INET6 ,这样只要取到某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容。
- socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性。
struct sockaddr
{
__SOCKADDR_COMMON (sa_); /* Common data: address family and length. */
char sa_data[14]; /* Address data. */
};
struct sockaddr_in
{
__SOCKADDR_COMMON (sin_); /*包含地址类型*/
in_port_t sin_port; /* 端口号 */
struct in_addr sin_addr; /* IP地址 */
/* Pad to size of `struct sockaddr'. */
unsigned char sin_zero[sizeof (struct sockaddr) -
__SOCKADDR_COMMON_SIZE -
sizeof (in_port_t) -
sizeof (struct in_addr)];
};
in_addr结构
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr; /* in_addr 用来表示一个IPv4的IP地址,其实就是一个32位整数 */
};