C语言 网络编程(十五)套接字选项设置

简介: `setsockopt()`函数用于设置套接字选项,如重复使用地址(`SO_REUSEADDR`)、端口(`SO_REUSEPORT`)及超时时间(`SO_RCVTIMEO`)。其参数包括套接字描述符、协议级别、选项名称、选项值及其长度。成功返回0,失败返回-1并设置`errno`。示例展示了如何创建TCP服务器并设置相关选项。配套的`getsockopt()`函数用于获取这些选项的值。

setsockopt() 函数

setsockopt() 函数用于设置套接字选项。

语法

#include <sys/socket.h>

int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

参数

  • sockfd:一个有效的套接字描述符。
  • level:选项所在的协议级别

    • SOL_SOCKET:是 socket 级别的选项,所有套接字通用。
    • IPPROTO_TCP:是 TCP 协议级别的选项。
    • IPPROTO_UDP:是 UDP 协议级别的选项。
    • IPPROTO_IP:是 IP 协议级别的选项。
  • optname:要设置的选项名

    - SO_REUSEADDR:允许重复使用本地地址。
    - SO_REUSEPORT:允许多个套接字绑定到同一端口。
    - SO_KEEPALIVE:保持连接。
    - SO_LINGER:关闭套接字时,是否等待数据发送完成。
    - SO_RCVTIMEO:接收超时时间。
    - SO_SNDTIMEO:发送超时时间。
    - SO_RCVBUF:接收缓冲区大小。
    - SO_SNDBUF:发送缓冲区大小。
    - SO_BROADCAST:允许发送广播数据。
    - SO_OOBINLINE:接收带外数据。
    - SO_TYPE:获取套接字类型。
    
    • TCP的选项:
      • TCP_NODELAY:禁用 Nagle 算法。
      • TCP_MAXSEG:最大报文段长度。
      • TCP_CORK:启用 TCP_CORK 模式。
      • TCP_DEFER_ACCEPT:延迟接受。
      • TCP_INFO:获取 TCP 信息。
      • TCP_QUICKACK:快速回应 ACK。
      • TCP_SYNCNT:同步序列号。
      • TCP_WINDOW_CLAMP:窗口大小限制。
      • TCP_MAXRT:最大重传时间。
      • TCP_USER_TIMEOUT:用户超时。
      • TCP_CONGESTION:获取拥塞控制状态。
    • IP的选项:
      • IP_TOS:设置 IP 类型。
      • IP_TTL:设置 IP 生存时间。
      • IP_HDRINCL:包含 IP 头部。
      • IP_OPTIONS:设置 IP 选项。
      • IP_MULTICAST_IF:设置多播接口。
      • IP_MULTICAST_TTL:设置多播 TTL。
      • IP_MULTICAST_LOOP:设置多播环回。
      • IP_ADD_MEMBERSHIP:加入多播组。
      • IP_DROP_MEMBERSHIP:离开多播组。
      • IP_BLOCK_SOURCE:阻止源地址。
      • IP_UNBLOCK_SOURCE:解除阻止源地址。
    • UDP的选项:
      • UDP_NOCHECKSUM:禁用
      • UDP_CHECKSUM:启用 UDP 校验和。
      • UDP_DEFER_ACCEPT:延迟接受。
      • UDP_MEM_INFO:获取 UDP 内存信息。
      • UDP_MTU_DISCOVER:获取 MTU 发现。
      • UDP_RECVMMSG:接收多包数据
      • UDP_SENDMMSG:发送多包数据。
      • UDP_SEGMENT:设置 UDP 分段。
      • UDP_SNDBUF:设置发送缓冲区大小。
      • UDP_RECVBUF:设置接收缓冲区大小。
      • UDP_MULTICAST_IF:设置多播接口。
      • UDP_MULTICAST_TTL:设置多播 TTL。
      • UDP_MULTICAST_LOOP:设置多播环回。
      • UDP_ADD_MEMBERSHIP:加入多播组。
      • UDP_DROP_MEMBERSHIP:离开多播组。
      • UDP_BLOCK_SOURCE:阻止源地址。
      • UDP_UNBLOCK_SOURCE:解除阻止源地址。
  • optval:指向存放选项值的指针。

  • optlen:选项值的长度。

返回值

  • 成功:返回 0。
  • 出错:返回 -1,并设置 errno 变量。
  • 注意:setsockopt() 函数设置的选项值是临时的,只对当前套接字有效,关闭套接字后,设置的选项值就会失效。

示例

这个案例展示了如何创建一个简单的TCP服务器,并使用 setsockopt() 函数设置套接字的选项。
具体来说,它设置了套接字的 SO_REUSEADDR 和 SO_REUSEPORT 选项,以及接收数据的超时选项 SO_RCVTIMEO。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 8080
#define BUFSIZE 1024

int main() {
   
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFSIZE] = {
   0};
    struct timeval timeout;

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
   
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    int opt = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
   
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    // 设置超时选项
    timeout.tv_sec = 5;  // 5秒
    timeout.tv_usec = 0;
    if (setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
   
        perror("setsockopt timeout");
        exit(EXIT_FAILURE);
    }

    // 绑定套接字
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
   
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听套接字
    if (listen(server_fd, 3) < 0) {
   
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
   
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // 读取数据
    int valread = read(new_socket, buffer, BUFSIZE);
    if (valread < 0) {
   
        perror("read");
    } else {
   
        printf("Received message: %s\n", buffer);
    }

    // 关闭套接字
    close(new_socket);
    close(server_fd);

    return 0;
}

getsockopt() 函数

getsockopt() 函数用于获取套接字选项。

语法

#include <sys/socket.h>

int getsockopt(int sockfd, int level, int optname, void *optval, socklen_t *optlen);

参数

  • sockfd:一个有效的套接字描述符。
  • level:选项所在的协议级别

    • SOL_SOCKET:是 socket 级别的选项,所有套接字通用。
    • IPPROTO_TCP:是 TCP 协议级别的选项。
    • IPPROTO_UDP:是 UDP 协议级别的选项。
    • IPPROTO_IP:是 IP 协议级别的选项。
  • optname:要获取的选项名

    • SO_REUSEADDR:允许重复使用本地地址。
    • SO_REUSEPORT:允许多个套接字绑定到同一端口。
    • SO_KEEPALIVE:保持连接。
    • SO_LINGER:关闭套接字时,是否等待数据发送完成。
    • SO_RCVTIMEO:接收超时时间。
    • SO_SNDTIMEO:发送超时时间。
    • SO_RCVBUF:接收缓冲区大小。
    • SO_SNDBUF:发送缓冲区大小。
    • SO_BROADCAST:允许发送广播数据。
    • SO_OOBINLINE:接收带外数据。
    • SO_TYPE:获取套接字类型。
  • optval:指向存放选项值的指针。
  • optlen:指向存放选项值的长度的指针。

返回值

  • 成功:返回 0。
  • 出错:返回 -1,并设置 errno 变量。

示例

创建一个简单的TCP服务器,并使用 getsockopt() 函数获取套接字的选项。
具体来说,它获取了接收数据的超时选项 SO_RCVTIMEO,并打印出超时设置的秒数和微秒数。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 8080
#define BUFSIZE 1024

int main() {
   
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);
    char buffer[BUFSIZE] = {
   0};
    struct timeval timeout;
    socklen_t len;

    // 创建套接字
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
   
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // 设置套接字选项
    int opt = 1;
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
   
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

    // 设置超时选项
    timeout.tv_sec = 5;  // 5秒
    timeout.tv_usec = 0;
    if (setsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0) {
   
        perror("setsockopt timeout");
        exit(EXIT_FAILURE);
    }

    // 获取超时选项
    len = sizeof(timeout);
    if (getsockopt(server_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, &len) < 0) {
   
        perror("getsockopt timeout");
        exit(EXIT_FAILURE);
    }

    printf("Timeout setting: %ld seconds, %ld microseconds\n", timeout.tv_sec, timeout.tv_usec);

    // 绑定套接字
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
   
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 监听套接字
    if (listen(server_fd, 3) < 0) {
   
        perror("listen");
        exit(EXIT_FAILURE);
    }

    // 接受连接
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
   
        perror("accept");
        exit(EXIT_FAILURE);
    }

    // 读取数据
    int valread = read(new_socket, buffer, BUFSIZE);
    if (valread < 0) {
   
        perror("read");
    } else {
   
        printf("Received message: %s\n", buffer);
    }

    // 关闭套接字
    close(new_socket);
    close(server_fd);

    return 0;
}
相关文章
|
11月前
|
Web App开发 缓存 负载均衡
为什么要在网络设置静态代理ip?
随着科技和互联网的发展,越来越多企业需要使用代理服务器。设置静态代理IP可提高安全性、保护用户IP地址,实现地域性访问、缓存加速及负载均衡等优势。具体配置方法包括在Windows、macOS操作系统或浏览器中进行网络设置,输入代理服务器的地址和端口。通过合理设置代理IP,用户能更好地管理网络流量,提升隐私与性能。
369 37
|
11月前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
409 20
|
10月前
|
虚拟化 网络虚拟化 Windows
导入虚拟机到Hyper-V环境时,理解并配置网络适配器设置是确保网络通信的关键
在Hyper-V环境中,正确配置虚拟机的网络适配器是确保其网络通信的关键。需先启用Hyper-V功能并创建虚拟交换机。接着,在Hyper-V管理器中选择目标虚拟机,添加或配置网络适配器,选择合适的虚拟交换机(外部、内部或私有),并根据需求配置VLAN、MAC地址等选项。最后,启动虚拟机并验证网络连接,确保其能正常访问外部网络、与主机及其他虚拟机通信。常见问题包括无法访问外部网络或获取IP地址,需检查虚拟交换机和适配器设置。
|
缓存 负载均衡 安全
Swift中的网络代理设置与数据传输
Swift中的网络代理设置与数据传输
|
11月前
|
监控 关系型数据库 MySQL
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
350 0
|
存储 网络协议 物联网
C 语言物联网开发之网络通信与数据传输难题
本文探讨了C语言在物联网开发中遇到的网络通信与数据传输挑战,分析了常见问题并提出了优化策略,旨在提高数据传输效率和系统稳定性。
|
网络协议 物联网 数据处理
C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势
本文探讨了C语言在网络通信程序实现中的应用,介绍了网络通信的基本概念、C语言的特点及其在网络通信中的优势。文章详细讲解了使用C语言实现网络通信程序的基本步骤,包括TCP和UDP通信程序的实现,并讨论了关键技术、优化方法及未来发展趋势,旨在帮助读者掌握C语言在网络通信中的应用技巧。
371 2
|
监控 安全 网络安全
Elasticsearch集群的网络设置
Elasticsearch集群的网络设置
428 3
|
网络协议 Linux
使用nmcli命令设置IP地址并排查网络故障
nmcli 是一个功能强大的网络管理工具,通过它可以轻松配置IP地址、网关和DNS,同时也能快速排查网络故障。通过正确使用nmcli命令,可以确保网络配置的准确性和稳定性,提高系统管理的效率。希望本文提供的详细步骤和示例能够帮助您更好地掌握nmcli的使用方法,并有效解决实际工作中的网络问题。
1119 2
|
Ubuntu 网络安全 数据安全/隐私保护
阿里云国际版如何设置网络控制面板
阿里云国际版如何设置网络控制面板