Linux网络编程系列之服务器编程——阻塞IO模型

news2025/1/19 20:14:41

Linux网络编程系列  (够吃,管饱)

        1、Linux网络编程系列之网络编程基础

        2、Linux网络编程系列之TCP协议编程

        3、Linux网络编程系列之UDP协议编程

        4、Linux网络编程系列之UDP广播

        5、Linux网络编程系列之UDP组播

        6、Linux网络编程系列之服务器编程——阻塞IO模型

        7、Linux网络编程系列之服务器编程——非阻塞IO模型

        8、Linux网络编程系列之服务器编程——多路复用模型

        9、Linux网络编程系列之服务器编程——信号驱动模型

一、什么是阻塞IO模型

        服务器阻塞IO模型是一种IO模型,其中服务器在处理INGRESS和EGRESS网络数据流时阻塞,并且无法处理其他连接请求。当服务器接收到一个连接请求时,它将读取数据直到读取完成,然后进行处理并发送响应,这期间,该连接请求将会阻塞其他连接请求的处理。

二、特性

        1、阻塞IO调用,当服务器没有数据可读或者没有缓冲区可写入时,服务器将被阻塞。

        2、每个连接都需要创建一个新的线程或进程来处理,因此服务器开销和资源占用会很大。

        3、每个连接需要消耗一定的内存资源来存储相关信息,如连接状态和IO缓冲区等。

        4、无法处理大量并发连接请求,可能会导致连接的延迟和响应时间过长。

        5、对于大数据传输,阻塞IO可能会一次性读取所有数据并占用大量内存,从而导致服务器崩溃或性能下降。

        6、由于阻塞IO模型无法实时处理并发连接请求,因此无法适应高并发、高吞吐量的应用场景。

三、使用场景

        1、小规模的网络应用,如小型HTTP服务器、FTP服务器等。

        2、对并发连接数量要求不高的网络应用,如内部OA系统、ERP系统等。

        3、数据传输量较小的网络应用,如即时聊天应用、邮件系统等。

        4、对实时响应要求不高的网络应用,如批处理任务、数据备份等。

        5、对于资源受限的系统,如嵌入式系统、移动设备等,阻塞IO模型也可以用于网络应用。

四、模型框架(通信流程)

        1、建立套接字。使用socket()

        2、设置端口复用。使用setsockopt()

        3、绑定自己的IP地址和端口号。使用bind()

        4、设置监听。使用listen()

        5、循环阻塞等待,接收新的客户端连接。使用accept()

        6、为连接上来的客户端创建一条线程。使用pthread_create()

        7、关闭套接字。使用close()

五、相关函数API接口

        这里TCP服务通信的API在本系列其他博客中已经有大量讲解,这里省略,忘记了朋友可以点击本文开头上面对应的链接查看。

六、案例

        使用阻塞IO模型结合TCP协议,完成服务器通信演示,使用nc命令模拟客户端。

// 阻塞IO模型TCP服务器的案例

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>       
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <pthread.h>

#define MAX_LISTEN  50  // 最大能处理的连接数
#define SERVER_IP   "192.168.64.128"    // 记得改为自己IP
#define SERVER_PORT 20000   // 不能超过65535,也不要低于1000,防止端口误用

struct ClientInfo
{
    int fd;
    uint16_t port;
    char ip[20];
};


// 线程的例程函数
void *recv_routinue(void *arg)
{
    int ret = 0;
    char recv_msg[128] = {0};
    struct ClientInfo client = *((struct ClientInfo*)arg);

    pthread_detach(pthread_self()); // 设置强制分离

    while(1)
    {
        memset(recv_msg, 0, sizeof(recv_msg));
        ret = recv(client.fd, recv_msg, sizeof(recv_msg), 0);
        if(ret == 0)
        {
            printf("[%s:%d] disconnect\n", client.ip, client.port);
            pthread_exit(0);
        }
        else if(ret > 0)
        {
            printf("[%s:%d] send data: %s\n", client.ip, client.port, recv_msg);
        }
    }
}


int main(int argc, char *argv[])
{
    // 1、建立套接字,指定IPV4网络地址,TCP协议
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if(sockfd == -1)
    {
        perror("socket fail");
        return -1;
    }

    // 2、设置端口复用(推荐)
    int optval = 1; // 这里设置为端口复用,所以随便写一个值
    int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));
    if(ret == -1)
    {
        perror("setsockopt fail");
        close(sockfd);
        return -1;
    }

    // 3、绑定自己的IP地址和端口号(不可以省略)
    struct sockaddr_in server_addr = {0};
    socklen_t addr_len = sizeof(struct sockaddr);
    server_addr.sin_family = AF_INET;   // 指定协议为IPV4地址协议
    server_addr.sin_port = htons(SERVER_PORT);  // 端口号
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); // IP地址
    
    ret = bind(sockfd, (struct sockaddr*)&server_addr, addr_len);
    if(ret == -1)
    {
        perror("bind fail");
        close(sockfd);
        return -1;
    }

    // 4、设置监听
    ret = listen(sockfd, MAX_LISTEN);
    if(ret == -1)
    {
        perror("listen fail");
        close(sockfd);
        return -1;
    }

    uint16_t port = 0;
    char ip[20] = {0};
    struct sockaddr_in client_addr = {0};

    printf("wait client connect...\n");
    while(1)
    {
        // 5、接受连接请求
        int new_client_fd = accept(sockfd, (struct sockaddr*)&client_addr, &addr_len);
        if(new_client_fd == -1)
        {
            perror("accept fail");
            close(sockfd);
            return -1;
        }
        else
        {
            memset(ip, 0, sizeof(ip));
            strcpy(ip, inet_ntoa(client_addr.sin_addr));
            port = ntohs(client_addr.sin_port);
            printf("[%s:%d] connect\n", ip, port);

            struct ClientInfo client = {0};
            client.fd = new_client_fd;
            client.port = port;
            strcpy(client.ip, ip);

            // 创建线程,一个客户端对应一个线程
            pthread_t tid;
            pthread_create(&tid, NULL, recv_routinue, (void*)&client);
        }
    }

    // 7、关闭套接字
    close(sockfd);

    return 0;
}

七、总结

        阻塞IO模型适用于系统资源有限,小规模通信的场景,无法适应高并发、高吞吐量的应用场景。通常做法是一个客户端对应一个线程,这样极度消耗系统资源,因此也无法处理大规模的客户端连接请求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095649.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Stream流中的 max()和 sorted()方法

需求&#xff1a;某个公司的开发部门&#xff0c;分为开发 一部 和 二部 &#xff0c;现在需要进行年中数据结算。分析&#xff1a; 员工信息至少包含了&#xff08;名称、性别、工资、奖金、处罚记录&#xff09;开发一部有 4 个员工、开发二部有 5 名员工分别筛选出 2 个部门…

1.2 向量的长度与点积

一、向量的点积 两个向量 v ( v 1 , v 2 ) \boldsymbol v(v_1,v_2) v(v1​,v2​) 与 w ( w 1 , w 2 ) \boldsymbol w(w_1,w_2) w(w1​,w2​)的点积或内积是数字 v ⋅ w \boldsymbol v\cdot\boldsymbol w v⋅w&#xff1a; v ⋅ w v 1 w 1 v 2 w 2 ( 1.2.1 ) \boldsymbo…

【Agora UID 踩坑记录 Java 数据类型】

目录 负数二进制表示Java中32位无符号数的取法项目踩坑记录Java 0xffffffff隐式类型转换的坑 负数二进制表示 由于计算机中数据都以二进制表示&#xff0c;而负数的二级制是根据正数二进制取补码&#xff08;补码就是先取反码&#xff0c;然后加1&#xff09;得到&#xff0c;…

关于Gym变成Gymnasium

根据网页搜索的gym官网&#xff0c;发现如下网站https://www.gymlibrary.dev/ 刚进页面时 翻译一下&#xff0c;意思就是 Gym 的所有开发都已迁移到 Gymnasium,这是 Farama 基金会中的一个新软件包,由过去 18 个月来维护 Gym 的同一团队开发人员维护。如果您已经在使用最新版…

Java基础(运算符篇)

一、算术运算符 正号-负号加法-减法*乘法/除法%模运算&#xff08;取余&#xff09;自增--自减 算术运算符的使用比较简单&#xff0c;只需要注意一些细节。 tips&#xff1a; 加号&#xff08; &#xff09;除了可以作为正号&#xff0c;还可以用于字符串拼接。 public c…

解读下SWD协议以及其应用

SWD协议原理 SWD&#xff08;Serial Wire Debug&#xff09;协议是一种用于ARM Cortex微控制器的调试接口协议。它定义了主机计算机与目标设备之间通过SWD线进行通信的格式和规范。 SWD协议使用两根线进行通信&#xff1a;SWDIO&#xff08;Serial Wire Debug I/O&#xff09…

跳石板(牛客)

目录 一、题目 二、代码 &#xff08;一&#xff09;解法一&#xff1a;超时了 &#xff08;二&#xff09;优化 一、题目 跳石板_牛客题霸_牛客网 二、代码 &#xff08;一&#xff09;解法一&#xff1a;超时了 #include <climits> #include <iostream> …

python的pyecharts第三方模块绘制高端统计图表

pyecharts库 python的pyecharts库是一个用于生成 Echarts 图表的python第三方类库&#xff0c;可以绘制很高端的统计图表以便展示数据。 安装方法 pip安装 pip install pyecharts或者github拉取下载安装 git clone https://github.com/pyecharts/pyecharts.git cd pyechar…

Android 内容提供者和内容观察者:数据共享和实时更新的完美组合

任务要求 一个作为ContentProvider提供联系人数据另一个作为Observer监听联系人数据的变化&#xff1a; 1、创建ContactProvider项目&#xff1b; 2、在ContactProvider项目中用Sqlite数据库实现联系人的读写功能&#xff1b; 3、在ContactProvider项目中通过ContentProvid…

1.安装 docker 容器并配置镜像加速器

1.2.1 实验环境准备 实验环境&#xff1a; rockylinux8.8 可以去官网下载 下载 Rocky | Rocky Linux 主机名&#xff1a; xuegod63 主机 ip: 192.168.1.63&#xff08;这个 ip 大家可以根据自己所在环境去配置&#xff0c;配置成静态 IP&#xff09; 2g 内存、2vCPU、50G 硬…

诊断DLL——CAPL_DLL集成安全访问算法

文章目录 前言一、CAPL DLL简介DLL生成C2338报错解决方案:二、添加27服务解锁算法三、CAPL调用dll前言 在实际诊断工程应用中,如UDS刷写——27服务,经常会遇到一些Seed2Key的算法问题,为了安全保密,这个算法的源码不便公开,我们可以将其打包成DLL,然后在CANoe诊断控制面…

树莓派4b配置通过smbus2使用LCD灯

出现报错&#xff1a; FileNotFoundError: [Errno 2] No such file or directory: ‘/dev/i2c-1’ 则说明没有打开I2C&#xff0c;可通过如下步骤进行设置 1、打开树莓派配置 sudo raspi-config2、进入Interface Options&#xff0c;配置I2C允许 目前很多python3版本已经不…

【LeetCode热题100】--121.买卖股票的最佳时机

121.买卖股票的最佳时机 class Solution {public int maxProfit(int[] prices) {int minprice Integer.MAX_VALUE;int maxprofit 0;for(int i 0;i<prices.length;i){if(prices[i] < minprice){minprice prices[i]; //找到最小值}else if(prices[i] - minprice > ma…

C++指针解读(7)-- 指针和函数

前面我们讲过用指针变量作为函数参数。这里讲指向函数的指针变量和返回指针的函数。 1、指向函数的指针变量 跟变量一样&#xff0c;函数也会存储在内存空间中&#xff0c;函数的内存空间有一个起始地址&#xff0c;每次调用函数时就从该入口地址开始执行函数代码。 既然函数…

Wordpress自定义小工具logo调用设置(可视化)

在主题开发中&#xff0c;需要调用网站的logo&#xff0c;最简单的办法就是用wp自带的函数&#xff0c;那就是the_custom_logo()&#xff0c;使用它还可以通过后台-自定义-logo&#xff0c;边修改边预览&#xff0c;还是很香的。 自定义徽标支持应首先使用add_theme_support()添…

【后端】韩顺平Java学习笔记(基础篇01)

因为之前有c基础&#xff0c;所以差不多一样的就简写了owo 来源&#xff1a;韩顺平 零基础30天学会Java 目录 I. 控制结构&#xff08;简&#xff09; 一、介绍 1. 顺序 → 从上到下执行&#xff0c;无跳转 2. 分支 → 单、双、多、嵌套 1&#xff09;单&#xff0c;即…

【GO入门】环境配置及Vscode配置

1 GO环境配置 欢迎来到Go的世界&#xff0c;让我们开始探索吧&#xff01; Go是一种新的语言&#xff0c;一种并发的、带垃圾回收的、快速编译的语言。它具有以下特点&#xff1a; 它可以在一台计算机上用几秒钟的时间编译一个大型的Go程序。Go为软件构造提供了一种模型&…

langchain callback学习

文章目录 一.quickstart二.Async callbacks三.把回调消息写入文件如何提取出来正则表达式官方的方法 一.quickstart 官方文档在此&#xff1a;https://python.langchain.com/docs/modules/callbacks/ 发现自己之前用langchain都是纯纯只是跑通&#xff0c;要能灵活使用还是得深…

freefilesync文件同步软件

下载 下载链接 https://freefilesync.org/download.php 往下拉&#xff0c;看到下载的链接 下载windows版本 下载地址&#xff1a; https://freefilesync.org/download/FreeFileSync_13.0_Windows_Setup.exe 直接复制到浏览器中访问就能下载 安装 双击安装包&#xff0c;一路默…

总结:JavaEE的Servlet中HttpServletRequest请求对象调用各种API方法结果示例

总结&#xff1a;JavaEE的Servlet中HttpServletRequest请求对象调用各种API方法结果示例 一方法调用顺序是按照英文字母顺序从A-Z二该示例可以用作servlet中request的API参考&#xff0c;从而知道该如何获取哪些路径参数等等三Servlet的API版本5.0.0、JSP的API版本&#xff1a;…