Socket
Socket 起源于 Unix,而 Unix 基本哲学之一就是“一切皆文件”,都可以用 “打开open –> 读写write/read –> 关闭close” 模式来操作。Socket 可以理解为一种特殊的文件。
Socket 的基本操作
socket(...)
//成功返回文件(套接字)描述符;出错返回-1
int socket(int domain, int type, int protocol);
domain
:协议族(family),确定通信的特征,包括地址格式。常用的协议族有:AF_INET、AF_INET6、AF_UNIX、AF_UPSPEC
等。
协议族决定了 socket 的地址类型:如
AF_INET
决定了要用ipv4地址(32位)与端口号(16位)的组合、AF_UNIX
决定了要用一个绝对路径作为地址。
type
:指定 socket 类型,进一步确定通信特征。常用的类型有:SOCK_STREAM、SOCK_DGRAM、SOCK_RAW、SOCK_PACKET、SOCK_SEQPACKET
等。protocol
:通信协议,常用的协议有:IPPROTO_TCP、IPPROTO_UDP、IPPROTO_IP、IPPROTO_IPV6、IPPROTO_ICMP、IPPROTO_ROW
等。protocol
需要与type
对应,protocol
为0
时,会自动选择type
类型对应的默认协议。
bind(...)
当我们调用 socket(domain, type, protocol)
创建一个 socket 时,返回的 socket 描述符存在于协议族(address family,AF_XXX)空间中,但没有一个具体的地址。如果想要给它赋值一个地址(ip+端口),就必须调用 bind()
函数(服务端通常使用),或者调用 connect()
、listen()
时系统会自动随机分配一个端口(客户端通常使用)。
//成功返回0;出错返回-1
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
sockfd
:即 socket 描述符,是通过socket()
函数返回的套接字唯一标识符addr
:一个const struct sockaddr*
指针,指向要绑定的地址。这个结构根据创建 socket 时地址类型的不同而不同.addrlen
:对应地址的长度
通常服务器在启动时都会绑定一个地址(如 127.0.0.1:80 ),客户可以通过这个地址来连接服务器。而客户端就不用指定,系统会自动分配一个端口号和自身 ip 地址组合。这就是为什么通常服务端在
listen()
之前会调用bind()
,而客户端就不用,而是在connnect()
时由系统随机生成一个。
主机字节序就是我们平常所说的大端和小端模式:不同的CPU有不同的字节序,这些字节序是指整数在内存中保存的顺序。
- 小端(Little-Endian)就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
- 大端(Big-Endian)就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
例子:在内存中双字0x01020304
的存储方式
内存地址 4000 4001 4002 4003
LE 04 03 02 01
BE 01 02 03 04
网络字节序:网络字节顺序是TCP/IP中规定好的一种数据表示格式,它与具体的CPU类型、操作系统等无关,从而可以保证数据在不同主机之间传输时能够被正确解释。网络字节顺序采用big endian排序方式。
如4个字节的32 bit值以下面的次序传输:首先是0~7bit,其次8~15bit,然后16~23bit,最后是24~31bit。
在将一个地址绑定到socket时,务必要将主机字节序的地址转换为网络字节序,否则可能会引发血案,导致很多莫名其妙的问题。
listen(...)、connect(...) 函数
//sockfd:需要监听的socket
//backlog:该socket可以排队的最大连接数
//成功返回0;失败返回-1
int listen(int sockfd, int backlog);
//sockfd:客户端的socket
//addr:服务器的socket地址
//addrlen:服务器地址长度
//成功返回0;失败返回-1
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
- 作为一个服务器,在调用
socket()
、bind()
之后就会调用listen()
来监听这个 socket; - 作为一个客户端,这时会调用
connect()
来发出连接请求。
accept(...) 函数
参考:https://blog.csdn.net/zhoucheng05_13/article/details/100162888