【Linux网络编程】Socket Api函数
【Linux网络编程】Socket Api函数
TCP/IP 协议族
TCP/IP 协议族有 sockaddr_in
和 sockaddr_in6
两个专用的 socket 地址结构体,它们分别用于 IPv4 和 IPv6,在此只将 IPv4,如下为 struct sockaddr_in
:
struct sockaddr_in {
sa_family_t sin_family; // 地址族:AF_INET
u_int16_t sin_port; // 端口号,要用网络字节序表示
struct in_addr sin_addr; // IPv4地址结构体,见下面
};
struct in_addr {
u_int32_t s_addr; // IPv4地址,需要用网络字节序表示
};
所有专用 socket 地址结构体如 sockaddr_in
类型的变量在实际使用时都需要转化为通用的 socket 地址类型 sockaddr
(强制转换即可)。
创建 socket
socket 是一个可读、可写、可控制与可关闭的文件描述符。使用 socket 系统调用可创建一个 socket,在 #include <sys/types.h>
与 #include <sys/socket.h>
中:
int socket(int domain, int type, int protocol);
- domain:IP 地址类型,AF_INET 表示 IPv4,如果使用 IPv6 则是 AF_INET6。
- type:数据传输方式,SOCK_STREAM 表示流服务,用于 TCP,SOCK_DGRAM 表示数据报,用于 UDP。
- protocol:一般为 0,依据 type 自动推倒协议类型。
socket 系统调用成功时返回一个 socket 文件描述符,失败则返回 -1,并设置 errno。
命名 socket
在创建 socket 后,虽然指定了协议族,但是并未指定该协议族使用哪个具体的 socket 地址,由此将一个 socket 与 socket 地址绑定则称为给 socket 命名。命名 socket 的系统调用为 bind
:
int bind(int sockfd, const struct sockaddr* my_addr, socklen_t addrlen);
bind 将 my_addr 所指的 socket 地址分配给未命名的 sockfd 文件描述符,addrlen 参数指出该 socket 地址的长度。
bind 成功返回 0,失败则返回 -1 并设置 errno。
监听 socket
socket 被命名后,还不能马上接受客户的连接,需要使用 listen 的系统调用来创建一个监听队列以存放待处理的客户连接:
int listen(int sockfd, int backlog);
sockfd 表示指定被监听的 socket。backlog 参数提示内核监听队列的最大长度。而如果监听队列的长度超过 backlog,服务器将不再接受新的客户连接。建议 backlog 设置为 128。
listen 成功返回 0,失败返回 -1 并设置 errno。
接受连接
使用 accept 系统调用从 listen 监听队列中接受一个连接:
int accept(int sockfd, struct sockaddr* addr, socklen_t* addrlen);
sockfd 是执行过 listen 系统调用的监听 socket。addr是一个新的 socket 地址,用来获取被接受连接的远端 socket 地址,该 socket 地址的长度有由 addrlen 指出。
accept成功时返回一个新的连接 socket,该 socket 唯一地标识了被接受的这个连接,服务器可通过读写该 socket 来与被接受连接对应的客户端通信。accept 失败时返回 -1 并设置 errno。
服务器:接受连接,客户端:被接受连接。