socket 到底是什么?
connect -> accept 好像有点问题, 应该是 connect -> listen.
服务端初始化过程:
- 初始化 socket
- bind: ip + port
- listen: 转化 socket 为 “服务端 socket”
- 服务端阻塞在 accept
- 数据传输
客户端初始化过程:
- 初始化 socket
- 执行 connect 发起连接 (tcp 三次握手)
- 数据传输
以上所有的操作,都是通过 socket 来完成的。无论是客户端的 connect,还是服务端的 accept,或者 read/write 操作等,socket 是我们用来建立连接,传输数据的唯一途径。
更好地理解 socket:一个更直观的解释
打电话.
socket 貌似是方便网络编程的 api.
socket 的发展历史
伯克利的研究者们设想用 socket 的概念,屏蔽掉底层协议栈的差别。
套接字地址格式
通用套接字地址格式
套接字的通用地址结构:
/* POSIX.1g 规范规定了地址族为2字节的值. */
typedef unsigned short int sa_family_t;
/* 描述通用套接字地址 */
struct sockaddr{
sa_family_t sa_family; /* 地址族. 16-bit*/
char sa_data[14]; /* 具体的地址值 112-bit */
};
地址族:
- AF_LOCAL:表示的是本地地址,对应的是 Unix 套接字,这种情况一般用于本地 socket 通信,很多情况下也可以写成 AF_UNIX、AF_FILE;
- AF_INET:因特网使用的 IPv4 地址;
- AF_INET6:因特网使用的 IPv6 地址。
缩写:
- AF: Address Family
- PF: Protocol Family
- PF_INET
- PF_INET6
用 AF_xxx 这样的值来初始化 socket 地址,用 PF_xxx 这样的值来初始化 socket.
在
/* 各种地址族的宏定义 */
#define AF_UNSPEC PF_UNSPEC
#define AF_LOCAL PF_LOCAL
#define AF_UNIX PF_UNIX
#define AF_FILE PF_FILE
#define AF_INET PF_INET
#define AF_AX25 PF_AX25
#define AF_IPX PF_IPX
#define AF_APPLETALK PF_APPLETALK
#define AF_NETROM PF_NETROM
#define AF_BRIDGE PF_BRIDGE
#define AF_ATMPVC PF_ATMPVC
#define AF_X25 PF_X25
#define AF_INET6 PF_INET6
IPv4 套接字格式地址
常用的 IPv4 地址族的结构:
/* IPV4套接字地址,32bit值. */
typedef uint32_t in_addr_t;
struct in_addr
{
in_addr_t s_addr;
};
/* 描述IPV4的套接字地址格式 */
struct sockaddr_in
{
sa_family_t sin_family; /* 16-bit */
in_port_t sin_port; /* 端口号 16-bit*/
struct in_addr sin_addr; /* Internet address. 32-bit */
/* 这里仅仅用作占位符,不做实际用处 */
unsigned char sin_zero[8];
};
- sin_family: 对于 IPv4 其值为 AF_INET
glibc 定义的保留端口:
/* Standard well-known ports. */
enum
{
IPPORT_ECHO = 7, /* Echo service. */
IPPORT_DISCARD = 9, /* Discard transmissions service. */
IPPORT_SYSTAT = 11, /* System status service. */
IPPORT_DAYTIME = 13, /* Time of day service. */
IPPORT_NETSTAT = 15, /* Network status service. */
IPPORT_FTP = 21, /* File Transfer Protocol. */
IPPORT_TELNET = 23, /* Telnet protocol. */
IPPORT_SMTP = 25, /* Simple Mail Transfer Protocol. */
IPPORT_TIMESERVER = 37, /* Timeserver service. */
IPPORT_NAMESERVER = 42, /* Domain Name Service. */
IPPORT_WHOIS = 43, /* Internet Whois service. */
IPPORT_MTP = 57,
IPPORT_TFTP = 69, /* Trivial File Transfer Protocol. */
IPPORT_RJE = 77,
IPPORT_FINGER = 79, /* Finger service. */
IPPORT_TTYLINK = 87,
IPPORT_SUPDUP = 95, /* SUPDUP protocol. */
IPPORT_EXECSERVER = 512, /* execd service. */
IPPORT_LOGINSERVER = 513, /* rlogind service. */
IPPORT_CMDSERVER = 514,
IPPORT_EFSSERVER = 520,
/* UDP ports. */
IPPORT_BIFFUDP = 512,
IPPORT_WHOSERVER = 513,
IPPORT_ROUTESERVER = 520,
/* Ports less than this value are reserved for privileged processes. */
IPPORT_RESERVED = 1024,
/* Ports greater this value are reserved for (non-privileged) servers. */
IPPORT_USERRESERVED = 5000
IPv6 套接字地址格式
IPv6 的地址结构:
struct sockaddr_in6
{
sa_family_t sin6_family; /* 16-bit */
in_port_t sin6_port; /* 传输端口号 # 16-bit */
uint32_t sin6_flowinfo; /* IPv6流控信息 32-bit*/
struct in6_addr sin6_addr; /* IPv6地址128-bit */
uint32_t sin6_scope_id; /* IPv6域ID 32-bit */
};
- 该结构为 28B
- 流控信息和域 ID 先不用管
- sin6_family: AF_INET6
本地套接字格式
struct sockaddr_un {
unsigned short sun_family; /* 固定为 AF_LOCAL */
char sun_path[108]; /* 路径名 */
};
几种套接字地址格式比较
精选留言
业余爱好者
unix系统有一种一统天下的简洁之美:一切皆文件,socket也是文件。
1.像sock_addr的结构体里描述的那样,几种套接字都要有地址族和地址两个字段。这容易理解,你要与外部通信,肯定要至少告诉计算机对方的地址和使用的是哪一种地址。与远程计算机的通信还需要一个端口号。而本地socket的不同之处在于不需要端口号,那么就有了问题2;
2.本地socket本质上是在访问本地的文件系统,所以自然不需要端口。远程socket是直接将一段字节流发送到远程计算机的一个进程,而远程计算机可能同时有多个进程在监听,所以用端口号标定要发给哪一个进程。
作者回复: 回答的很好,给你点赞
Mark
AF_xxx 这样的值来初始化 socket 地址,用 PF_xxx 这样的值来初始化 socket。
请教老师,这一句具体怎么理解?
作者回复: //socket地址初始化 servaddr.sin_family = AF_INET;
//socket初始化
listenfd = socket(PF_INET, SOCK_STREAM, 0);