首页 > 其他分享 >服务器开发——setsockopt函数

服务器开发——setsockopt函数

时间:2024-07-08 17:08:16浏览次数:11  
标签:serv setsockopt addr listen int fd 服务器 include 函数

setsockopt()

setsockopt() 是一个用于设置套接字选项的 Unix 系统调用。它允许程序员修改套接字的行为,以适应不同的网络环境和应用程序需求。

1. 函数介绍

函数原型:

#include <sys/socket.h>  
/**
 * level:选项所在的协议层。例如,SOL_SOCKET 表示套接字层,IPPROTO_TCP 或 IPPROTO_IP 表示 TCP 或 IP 层。
 * optname:要设置的选项的名称。每个协议层都定义了自己的一组选项。
 * optval:指向一个变量的指针,该变量包含选项的新值。这个变量的类型取决于 optname 的值。
 * @return 成功(0);失败(-1)
*/
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);

使用实例:

int opt = 1;  
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) < 0) {  
    perror("setsockopt(SO_REUSEADDR)");  
    // 错误处理  
}

2.常见参数介绍

2.1 SO_REUSEADDR

1. 介绍TIME_WAIT

四次挥手:
在这里插入图片描述

当服务器和客户端建立连接以后,如果服务器关闭了客户端的连接,服务器处于TIME_WAIT状态。此时关闭服务器,再次开启服务器会发现bind()函数调用失败。
也就是,服务器关闭后短时间内无法再次打开。

2. 测试代码

1.服务器端:

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

#define SERV_PORT 9000

int main(int argc,char** argv)
{
    int listenfd = socket(AF_INET,SOCK_STREAM,0);
    struct sockaddr_in serv_addr;
    memset(&serv_addr,0,sizeof(serv_addr));

    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(SERV_PORT);
    serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    int ret=0;

    int opt = 1;
    //setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    ret = bind(listenfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
    if(ret==-1){
        printf("bind()函数调用失败\n");
        return -1;
    }


    ret = listen(listenfd,32);
    if(ret==-1){
        printf("listen()函数调用失败\n");
        return -1;
    }

    int connfd;
    const char* pcontent = "I sent sth to client!";
    for(;;){
        printf("服务器进入等待状态!\n");
        connfd = accept(listenfd,(struct sockaddr*)NULL,NULL);
        int n = write(connfd,pcontent,strlen(pcontent));
        printf("数据写入成功,connfd=%d,写入数据量为%d\n",connfd,n);
        close(connfd);
    }
    close(listenfd);
    return 0;
}

在这里插入图片描述

2.客户端:


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


#define SERV_PORT 9000    //要连接到的服务器端口,服务器必须在这个端口上listen着

int main(int argc, char *const *argv)
{    
    //这些演示代码的写法都是固定套路,一般都这么写
    int sockfd = socket(AF_INET, SOCK_STREAM, 0); //创建客户端的socket,大家可以暂时不用管这里的参数是什么,知道这个函数大概做什么就行

    struct sockaddr_in serv_addr; 
    memset(&serv_addr,0,sizeof(serv_addr));

    //设置要连接到的服务器的信息
    serv_addr.sin_family = AF_INET;                //选择协议族为IPV4
    serv_addr.sin_port = htons(SERV_PORT);         //连接到的服务器端口,服务器监听这个地址

    if(inet_pton(AF_INET,"192.168.0.126",&serv_addr.sin_addr)<=0)
    {
        printf("调用inet_pton()失败,退出!\n");
        exit(-1);
    }

    if(connect(sockfd,(struct sockaddr*)&serv_addr,sizeof(serv_addr)) < 0)
    {
        printf("调用connect()失败,退出!\n");
        exit(-1);
    }

    printf("client开始读取数据!\n");
    int n;
    char recvline[1000+1];
    while(( n = read(sockfd,recvline,1000)) > 0)
    {
        printf("读取的数据数目为%d\n",n);
        recvline[n]=0;
        printf("收到的内容为:%s\n",recvline);
    }
    close(sockfd);
    printf("程序执行完毕,退出!\n");
    return 0;
}

在这里插入图片描述

2.2 SO_REUSEPORT

1.多进程端口复用

在多进程开发中,我们可以使用多个进程监听同一个IP:PORT,由操作系统分配传入的数据包,充分利用多核CPU,从而提高了整体的系统性能和吞吐量。

2.代码

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

void create_and_listen(int port) {
    int listen_fd;
    struct sockaddr_in addr;

    listen_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_fd < 0) {
        perror("socket");
        exit(EXIT_FAILURE);
    }

    // 没有设置 SO_REUSEPORT  选项
    
    /*
    int opt = 1;
    if (setsockopt(listen_fd, SOL_SOCKET, SO_REUSEPORT , &opt, sizeof(opt)) < 0) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    */
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = htonl(INADDR_ANY);
    addr.sin_port = htons(port);

    if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        perror("bind");
        close(listen_fd);
        exit(EXIT_FAILURE);
    }

    if (listen(listen_fd, SOMAXCONN) < 0) {
        perror("listen");
        close(listen_fd);
        exit(EXIT_FAILURE);
    }

    printf("Listening on port %d\n", port);

    while (1) {
        int conn_fd = accept(listen_fd, NULL, NULL);
        if (conn_fd < 0) {
            perror("accept");
            close(listen_fd);
            exit(EXIT_FAILURE);
        }

        // 处理连接的代码
        close(conn_fd);
    }

    close(listen_fd);
}

int main() {
    int port = 5000;

    for (int i = 0; i < 4; i++) {
        pid_t pid = fork();
        if (pid < 0) {
            perror("fork");
            exit(EXIT_FAILURE);
        } else if (pid == 0) {
            // 子进程
            create_and_listen(port);
            exit(0);
        }
    }

    // 父进程等待子进程退出
    while (wait(NULL) > 0);

    return 0;
}


没有开启SO_REUSEPORT 的时候:
在这里插入图片描述
只有一个进程可以绑定到这个套接字。


开启后:
在这里插入图片描述
有多个进程可以绑定到这个套接字。

标签:serv,setsockopt,addr,listen,int,fd,服务器,include,函数
From: https://www.cnblogs.com/xvxing/p/18290355

相关文章

  • CentOS7云服务器环境搭建
    一、下载、更新依赖1、更新系统版本至7.9yumupdate2、下载Vimyuminstallvim-y3、下载gcc(C语言环境,redis依赖它)yuminstallgcc软件统一安装在/usr/local/software目录下,源码统一解压缩在/usr/local/source二、Java参考:CSDN1、下载java1.8_202压缩包wgethtt......
  • 不定时修改Linux服务器端口和密码
    最近总是不想动,服务器的安全又不得不考虑,有时候还会忘记修改服务器的端口和密码,就诞生了下面的Shell脚本。脚本包含了日志记录,备份SSH文件,修改SSH端口,修改SSH密码,更新防火墙、发送加密邮件,设置定时任务。脚本目前只在Ubuntu系统测试,其它系统未测试,以下标红的信息一定要看。注意......
  • [UVM]IC验证自动结束仿真函数——uvm_top.set_timeout/set_report_max_quit_count
    Title:[UVM]IC验证自动结束仿真函数——uvm_top.set_timeout/set_report_max_quit_count文章目录1-前言2-uvm_top.set_timeout3-set_report_max_quit_count4-运用5-小结1-前言​数字IC验证过程中,需要运行不同Testcase,有些TC会因为TC配置、TB机制等原因,导致m......
  • SQL Server 实现类似CountIF的函数
    需求说明:我有一个客户表,还有一个客户的体验记录表,我需要汇总客户体验信息如下:客户名称,本周体验次数,本月体验次数,本年度体验次数,累计体验次数,首次体验时间,最近体验时间 信息,如何用一个SQL语句搞定:COUNT函数官方说明:指定COUNT返回唯一非Null值的数量。所以变相实现如下:S......
  • mac升级系统后ssh登录服务器问题
    报错信息:Unabletonegotiatewith111.111.113.86port123:nomatchinghostkeytypefound.Theiroffer:ssh-rsa分析:原因是MacosVentura13.0升级了ssh到9.0,ssl到3.3.6,而服务器上的sshd还是老版本;服务器上的老版本ssh和ssl无法和mac上的新版本ssh和ssl交互,新版本ss......
  • Ubuntu 22.04.4 LTS 安装 FreeRADIUS 3.0 和 Daloradius 2.2 搭建radius 认证服务器
    1ubuntu安装LAMP环境(安装nginx代替apache):Ubuntu22.04.4LTS安装phpapacheLAMP环境nginx-CSDN博客2安装freeradiussudoaptupdatesudoapt-getinstalllibmysqld-devsudoapt-getinstallfreeradius#先安装libmysqld-dev,否则启动可能报错Couldnotlink......
  • 数据分析入门指南Excel篇:各类Excel函数概览与详解(二)
    在当今数字化时代,数据已成为推动业务决策和创新的关键因素。而表格结构数据,作为最常见的数据存储形式之一,广泛应用于财务、物流、电商等多个领域。本文将基于提供的材料文本,深入探讨表格数据的处理与分析,特别是通过Excel等电子表格软件中的函数应用,实现数据的快速查询、统计......
  • Java工程中读取resources目录下properties文件的方式,从上图可知,当工程部署在服务器下
    Java工程中读取resources目录下properties文件的方式,从上图可知,当工程部署在服务器下时,配置文件以及代码都是在对应的classes文件夹下二、具体读取方法1、当需要读取当前路径下的properties文件时,即在本地没有部署到具体服务器上的情况:Filefile=newFile(“src/main/re......
  • 亚马逊云(AWS)云服务器在国内仍有很多人在用?
    在中国这个竞争激烈的云服务市场,亚马逊云(AWS)云服务器不仅站稳了脚跟,而且持续受到众多企业的青睐。究其原因,AWS凭借其无可比拟的全球影响力、技术创新力、以及对中国市场的深度理解,构建了一套难以抗拒的服务体系,让其在国内市场的地位坚不可摧。以下几点,正是AWS在国内市场持续受......
  • 如何使用AWS云服务器?
    亚马逊云服务器(AmazonEC2)作为一款强大的云计算服务,为企业和个人提供了灵活可扩展的虚拟服务器资源。如果你正在考虑购买亚马逊云服务器,不妨跟着下面的步骤,了解如何开始你的云端之旅。步骤一:注册AWS账号首先,访问亚马逊AWS官网(aws.amazon.com),并点击“创建免费账号”。按照页面......