Linux网络编程笔记 第12章 套接字选项

本文详细探讨了Linux网络编程中的套接字选项,包括getsocketopt()/setsocketopt()、ioctl() 和 fcntl() 的使用。重点讲解了SOL_SOCKET、IPPROTO_IP和IPPROTO_TCP协议族的选项,如SO_BROADCAST、IP_TOS和TCP_NODELAY等,并提供了相关操作示例,旨在帮助开发者更好地理解和控制网络连接行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本章主要学习getsocketopt()/setsocketopt()、ioctl() 、fcntl()

getsocketopt()/setsocketopt()

getsockopt():获得套接字选项设置情况

setsockopt():设置套接字选项的函数

#include <sys/types.h>
#include <sys/socket.h>
int getsockopt(int s, int level, int optname, void *optval, socklen_t
*optlen);
int setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen);

s:将要获取或者设置的套接字描述符,可以通过socket()函数获得

level:选项所在协议层。

optname:选项名。

optval:操作的内存缓冲区

optlen:第4个参数的长度

返回:成功:0,失败:-1

 

SOL_SOCKET 协议族选项

SO_BROADCAST

广播默认禁止,需要时打开,广播使用UDP套接字,其含义是允许将数据发送到子网网络的每个主机上。

#define YES 1 /*设置有效*/
#define NO 0 /*设置无效*/
int s; /*套接字变量*/
int err; /*错误值*/
int optval = YES; /*将选项设置为有效*/
s = socket(AF_INET, SOCK_DGRAM,0); /*建立套接字*/
err = setsockopt( /*设置选项*/
    s,
    SOL_SOCKET,
    SO_BROADCAST, /*SO_BROADCAST 选项*/
    &optval, /*值为有效*/
    sizeof(optval)); /*值的长度*/
if(err) /*判断是否发生错误*/
    perror("setsockopt"); /*打印错误信息*/

SO_DEBUG

表示允许调试套接字,打开此选项时,Linux内核程序跟踪在此套接字上的发送和接收的数据,并将调试信息放到一个环形缓冲区中。仅支持TCP

#define YES 1 /*设置有效*/
#define NO 0 /*设置无效*/
int s; /*套接字变量*/
int err; /*错误值*/
int optval = YES; /*将选项设置为有效*/
s = socket(AF_INET,SOCK_STREAM,0); /*建立一个TCP套接字*/
err = setsockopt( /*设置选项*/
    s,
    SOL_SOCKET,
    SO_DEBUG, /*SO_BROADCAST 选项*/
    &optval, /*值为有效*/
    sizeof(optval)); /*值的长度*/

SO_DONTROUTE

选项设置后,网络数据不通过网关发送,只能发送给直接连接的主机或者用一个子网内的主机。

SO_KEEPALIVE

用于设置TCP连接的保持,设置SO_KEEPALIVE 选项后,如果在两个小时内没有数据通信时, TCP会自动发送一个活动探测数据报文,对方必须对此进行响应;若收到ACK,两小时后再发,若收到RST,对方重启或崩溃,连接断开;若无响应,间隔75秒再发,还无响应就断开

#define YES 1 /*设置有效*/
#define NO 0 /*设置无效*/
int s; /*套接字变量*/
int err; /*错误值*/
int optval = YES; /*将选项设置为有效*/
s = socket(AF_INET, SOCK_DGRAM,0); /*建立套接字*/
err = setsockopt( /*设置选项*/
    s,
    SOL_SOCKET,
    SO_KEEPALIVE, /*SO_KEEPALIVE选项*/
    &optval, /*值为有效*/
    sizeof(optval)); /*值的长度*/
if(err) /*判断是否发生错误*/
    perror("setsockopt"); /*打印错误信息*/

SO_LINGER

用于设置TCP连接关闭时的行为方式,就是关闭流式连接时,发送缓冲区中的数据如何处理。

选项SO_LINGER的操作是通过结构struct linger来进行的

struct linger {
int l_onoff; /*是否设置延时关闭,0:否,1:时*/  
int l_linger; /*超时时间*/
};
#define YES 1 /*设置有效*/
#define NO 0 /*设置无效*/
int s; /*套接字变量*/
int err; /*错误值*/
struct linger optval; /*建立一个1inger类型的套接字选项变量*/
optval.l_onoff = YES; /*设置linger生效*/
optval.l_linger = 60; /*linger 超时时间为60s*/
s = socket(AF_INET, SOCK_DGRAM,0); /*建立套接字*/
err = setsockopt( /*设置选项*/
    s,
    SOL_SOCKET,
    SO_LINGER, /*SO LINGER 选项*/
    &optval, /*值为有效*/
    sizeof(optval)); /*值的长度*/
if(err) /*判断是否发生错误*/
    perror("setsockopt"); /*打印错误信息*/

以上,在调用close()函数后,在60s之内允许发送数据,当缓冲区内的数据发送完毕后,会正常关闭;不能正常发送数据则返回错误。

SO_OOBINLINE

带外数据不再通过另外的通道获得,带外数据放入正常数据流,

#define YES 1 /*设置有效*/
#define NO 0 /*设置无效*/
int s; /*套接字变量*/
int err; /*错误值*/
int optval = YES; /*将选项设置为有效*/
s = socket(AF_INET, SOCK_DGRAM,0); /*建立套接字*/
err = setsockopt( /*设置选项*/
    s,
    SOL_SOCKET,
    SO_OOBINLINE, /*SO_OOBINLINE选项*/
    &optval, /*值为有效*/
    sizeof(optval)); /*值的长度*/
if(err) /*判断是否发生错误*/
    perror("setsockopt"); /*打印错误信息*/

在设置选项之后,带外数据就会与一般数据一起接收。在这种方式下,所接收的越界数据与通常数据相同,即增加了带宽。

SO_RCVBUF 和 SO_SNDBUF

用于操作发送缓冲区和接收缓冲区的大小

在UDP连接中,由于它是无状态连接,发送缓冲区在数据通过网络设备发送后就可以丢弃,不用保存。而接收缓冲区则需要保存数据直到应用程序读取,由于UDP没有流量控制,当缓冲区过小时,发送端局部时间内会产生爆发性数据传输,由于接收端来不及读取数据,很容易造成缓冲区溢出,将原来的数据覆盖,淹没接收端。因此使用UDP连接时,需要将接收的缓冲区调整为比较大的值,

在TCP 连接中,接收缓冲区大小就是滑动窗口大小,而滑动窗口的协商是在建立连接时通过SYN获得的。对于客户端,接收缓冲区的大小要在connect()函数调用之前进行设置;对于服务器,需要在listen()之前进行设置接收缓冲区的大小,

例子

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
int main(int argc,char **argv)
{
    int err = -1; /*返回值*/
    int s = -1; /*socket描述符*/
    int snd_size = 0; /*发送缓冲区大小*/
    int rcv_size = 0; /*接收缓冲区大小*/
    socklen_t optlen; /*选项值长度*/
    /* 建立一个TCP套接字*/
    s = socket(PF_INET,SOCK_STREAM,0);
    if( s == -1){
        printf("建立套接字错误\n");
        return -1;
    }
    /*
    * 先读取缓冲区设置的情况
    * 获得原始发送缓冲区大小
    */
    optlen = sizeof(snd_size);
    err = getsockopt(s, SOL_SOCKET, SO_SNDBUF,&snd_size, &optlen);
    if(err){
        printf("获取发送缓冲区大小错误\n");
    }
    /*
    * 打印原始缓冲区设置情况
    */
    printf("发送缓冲区原始大小为: %d 字节\n",snd_size);
    printf("接收缓冲区原始大小为: %d 字节\n",rcv_size);
    /*
    * 获得原始接收缓冲区大小
    */
    optlen = sizeof(rcv_size);
    err = getsockopt(s, SOL_SOCKET, SO_RCVBUF, &rcv_size, &optlen);
    if(err){
        printf("获取接收缓冲区大小错误\n");
    }
    /*
    * 设置发送缓冲区大小
    */
    snd_size = 4096; /*发送缓冲区大小为8K*/
    optlen = sizeof(snd_size);
    err = setsockopt(s, SOL_SOCKET, SO_SNDBUF, &snd_size, optlen);
    if(err){
        printf("设置发送缓冲区大小错误\n");
    }
    /*
    * 设置接收缓冲区大小
    */
    rcv_size = 8192; /*接收缓冲区大小为8K*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值