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;
}
相关文章
|
1月前
|
网络协议 Unix C语言
C语言 网络编程(十六)广播和组播
广播和组播是网络通信的重要方式。广播允许一台主机向子网内所有主机发送数据包,常用于局域网内的消息传播;组播则将数据包发送给特定的一组主机,适用于视频会议等应用场景。广播地址如 `192.168.1.255` 用于同一子网的所有主机。组播地址如 `224.0.0.0` 至 `239.255.255.255` 标识特定主机群。C语言示例展示了如何通过 UDP 实现广播和组播通信。此外,UNIX域套接字用于同一机器上进程间的高效通信。
|
1月前
|
网络协议 C语言
C语言 网络编程(十三)并发的TCP服务端-以进程完成功能
这段代码实现了一个基于TCP协议的多进程并发服务端和客户端程序。服务端通过创建子进程来处理多个客户端连接,解决了粘包问题,并支持不定长数据传输。客户端则循环发送数据并接收服务端回传的信息,同样处理了粘包问题。程序通过自定义的数据长度前缀确保了数据的完整性和准确性。
|
1月前
|
网络协议 C语言
C语言 网络编程(十一)TCP通信创建流程---服务端
在服务器流程中,新增了绑定IP地址与端口号、建立监听队列及接受连接并创建新文件描述符等步骤。`bind`函数用于绑定IP地址与端口,`listen`函数建立监听队列并设置监听状态,`accept`函数则接受连接请求并创建新的文件描述符用于数据传输。套接字状态包括关闭(CLOSED)、同步发送(SYN-SENT)、同步接收(SYN-RECEIVE)和已建立连接(ESTABLISHED)。示例代码展示了TCP服务端程序如何初始化socket、绑定地址、监听连接请求以及接收和发送数据。
|
1月前
|
网络协议 C语言
C语言 网络编程(十四)并发的TCP服务端-以线程完成功能
这段代码实现了一个基于TCP协议的多线程服务器和客户端程序,服务器端通过为每个客户端创建独立的线程来处理并发请求,解决了粘包问题并支持不定长数据传输。服务器监听在IP地址`172.17.140.183`的`8080`端口上,接收客户端发来的数据,并将接收到的消息添加“-回传”后返回给客户端。客户端则可以循环输入并发送数据,同时接收服务器回传的信息。当输入“exit”时,客户端会结束与服务器的通信并关闭连接。
|
1月前
|
C语言
C语言 网络编程(八)并发的UDP服务端 以进程完成功能
这段代码展示了如何使用多进程处理 UDP 客户端和服务端通信。客户端通过发送登录请求与服务端建立连接,并与服务端新建的子进程进行数据交换。服务端则负责接收请求,验证登录信息,并创建子进程处理客户端的具体请求。子进程会创建一个新的套接字与客户端通信,实现数据收发功能。此方案有效利用了多进程的优势,提高了系统的并发处理能力。
|
1月前
|
网络协议 C语言
C语言 网络编程(十二)TCP通信创建-粘包
TCP通信中的“粘包”现象指的是由于协议特性,发送方的数据包被拆分并在接收方按序组装,导致多个数据包粘连或单个数据包分割。为避免粘包,可采用定长数据包或先传送数据长度再传送数据的方式。示例代码展示了通过在发送前添加数据长度信息,并在接收时先读取长度后读取数据的具体实现方法。此方案适用于长度不固定的数据传输场景。
|
1月前
|
C语言
C语言 网络编程(七)UDP通信创建流程
本文档详细介绍了使用 UDP 协议进行通信的过程,包括创建套接字、发送与接收消息等关键步骤。首先,通过 `socket()` 函数创建套接字,并设置相应的参数。接着,使用 `sendto()` 函数向指定地址发送数据。为了绑定地址,需要调用 `bind()` 函数。接收端则通过 `recvfrom()` 函数接收数据并获取发送方的地址信息。文档还提供了完整的代码示例,展示了如何实现 UDP 的发送端和服务端功能。
|
15天前
|
网络协议
关于套接字socket的网络通信。&聊天系统 聊天软件
关于套接字socket的网络通信。&聊天系统 聊天软件
|
1月前
|
网络协议 C语言
C语言 网络编程(十)TCP通信创建流程---客户端
在TCP通信中,客户端需通过一系列步骤与服务器建立连接并进行数据传输。首先使用 `socket()` 函数创建一个流式套接字,然后通过 `connect()` 函数连接服务器。连接成功后,可以使用 `send()` 和 `recv()` 函数进行数据发送和接收。最后展示了一个完整的客户端示例代码,实现了与服务器的通信过程。
|
1月前
|
C语言
C语言 网络编程(九)并发的UDP服务端 以线程完成功能
这是一个基于UDP协议的客户端和服务端程序,其中服务端采用多线程并发处理客户端请求。客户端通过UDP向服务端发送登录请求,并根据登录结果与服务端的新子线程进行后续交互。服务端在主线程中接收客户端请求并创建新线程处理登录验证及后续通信,子线程创建新的套接字并与客户端进行数据交换。该程序展示了如何利用线程和UDP实现简单的并发服务器架构。