Linux Socket 编程

1 篇文章 0 订阅
1 篇文章 0 订阅
本文档详细介绍了Linux Socket编程的各个步骤,包括getaddrinfo、socket、setsockopt、bind、listen和accept等关键操作。重点讲解了如何利用setsockopt实现地址复用,以便在服务端重启时能快速绑定原有地址,避免‘地址已被使用’的错误。
摘要由CSDN通过智能技术生成

目录

getaddrinfo

包含头文件:

<netdb.h>

函数原型:

int getaddrinfo(const char *hostname, const char *service, const struct addrinfo *hints, struct addrinfo **result);

参数说明:

hostname:主机名或者地址串(IPv4的点分十进制串或者IPv6的16进制串)

service:服务名可以是十进制的端口号,也可以是已定义的服务名称,如 FTP、HTTP 等

hints:可以是空指针,也可以是一个指向某个 addrinfo 结构体的指针,在这个结构中填入关于期望返回的信息的暗示。

result:通过 result 指针参数返回一个指向 addrinfo 结构体链表的指针。

返回值:0 代表成功,非 0 代表出错。

Details:

hostname:实际上这个参数是用来指定地址的(IPv4 或 IPv6)。如果传入的值是主机名称,比如 localhost,那么会在 /etc/hosts 文件中查找 “localhost” 所对应的端口号。因此,可以手动编辑 /etc/hosts 文件,添加其它的主机名称并指定地址,然后在这里的 hostname 参数中就可以指定主机名称来映射到地址了。

service:类似于 hostname 参数,当传入服务名称时会查找 /etc/services 文件来确定需要的端口号。

hints 通常需要设置的是 ai_familyai_socktypeai_flagsai_protocol 四项。

  • ai_family 代表地址结构类型,AF_INET4AF_INET6 分别指代 IPv4 和 IPv6,而 AF_UNSPEC 则代表不指定。
  • ai_socktypeSOCK_STREAMSOCK_DGRAM 两种,分别对应了 TCP 协议和 UDP 协议。
  • ai_flags 设置为 AI_PASSIVE 时,表示返回的结果将用于监听绑定。服务端通常设置为 AI_PASSIVE,客户端通常设置为 AI_CANONNAME
  • ai_protocol 通常设置为 0,表示允许返回任意类型的协议。

result:一个 addrinfo 链表(结构体 addrinfo 含有一个名为 nextaddrinfo 指针)。该链表包含所有符合参数 hostnameservice 要求的地址。bash 命令 host 可以检查一个域名所对应的地址,如 host tencent.com 将返回域名 “tencent.com” 所对应的地址。由于实际使用 getaddrinfo() 函数时,常用 for 循环 for (auto p = result; p != nullptr; p = p->ai.next;) 来遍历符合要求的 addrinfo 链表,但如果没有任何符合要求的地址时 getaddrinfo() 不会对 result 做任何更改,所以如果声明 result 指针时没有对其初始化为 nullptr,访问 p->ai.next 时就会出现 segmentation fault 错误。

freeaddrinfo(addrinfo **result)getaddrinfo函数返回的 result 所指向的内存地址是由系统开辟的,因此在使用完 addrinfo 后要调用 freeaddrinfo 释放内存空间,参数为指向 addrinfo 链表的首节点的指针。

socket

包含头文件
<netdb.h>
函数原型
int socket(int domain, int sock_type, int protocol);
参数说明
三个参数分别用来指定地址类型、连接类型和协议类型。分别对应 addrinfo 结构体中的 ai_familyai_socktypeai_protocol,因此可用 getaddrinfo 函数所返回的 result 来指定。
返回值 返回一个 socket 句柄(或 socket 描述符),一个小整数。
Details
在使用完 socket 句柄后需要对其进行释放。如 bindlisten 失败后,记得 close(sock)close 函数定义在 <zconf.h> 中。

setsockfd

::setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))

设置 sock 的选项。上述代码是为了复用地址。对服务端来说,该选项设置后,可以立即重启服务器。(对于普通 TCP 连接,在服务端关闭了 sock 后,该 sock 进入 TIME_WAIT 状态,其生命周期长达十几秒。关闭服务器后,如果立即重启,那么服务端所要绑定的地址仍然存在数个 TIME_WAIT 状态的连接,因而出现“地址已被使用”的错误,需要等待 TIME_WAIT 状态的连接全部被回收后才能重启服务器。设置了地址复用后,如果 bind 时存在的连接只有 TIME_OUT 状态的,那么可以进行重绑定。如果存在其它状态的则仍然会抛出“地址已被使用”的错误。)

bind

包含头文件
<netdb.h>
函数原型
int bind(int sock, const sockaddr *addr, socklen_t len);
参数说明
socksocket 句柄。
addr:一个指向 sockaddr 结构体的指针。一般使用 getaddrinfo 所设置的 resultai_addr 成员。
len:一般使用 getaddrinfo 所设置的 resultai_addrlen 成员。
返回值:0 代表成功,非 0 代表失败。

listen

包含头文件
<netdb.h>
函数原型
int listen(int sock_fd, int n);
参数说明
sock_fdsocket 句柄。
n:消息队列的最大长度。实际值为该参数与系统最大值中较小的那个。在 Linux 下,位于 /proc/sys/net/core/somaxcon 中。具体工作模式详见 accept 函数。
返回值:0 代表成功,非 0 代表失败。

accept

包含头文件
int accept(int sock_fd, sockaddr *client, socklen_t *len);
函数原型
sock_fdsocket 句柄。
client:客户端的地址。使用时应先初始化一个 sockaddr 结构体,然后传入它的地址。
len:调用时传入初始化的 sockaddr 结构体的长度,调用后被设置为能表示客户端地址的最小字节数。如果该值大于传入时设置的大小,那么将缩短为传入时指定的大小。比如初始化一个正常的 sockaddr 并传入,但 len 参数被初始化为指向整数 0 的指针,那么该函数将写入 0 字节到 sockaddr 结构体中,也就是不写。
返回值:返回一个整数,该整数为一个 socket 句柄,代表这个连接所对应的 socket
Details
listen 一个 socket 套接字后,会在指定的端口开始监听。每有一个连接的请求被收到,都会将其放入消息队列中。调用 accept 函数会从消息队列中取出一个进行处理。如果队列为空,则阻塞代码运行。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值