<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>CalcGuide</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.calcguide.tech/</id>
  <link href="https://blog.calcguide.tech/" rel="alternate"/>
  <link href="https://blog.calcguide.tech/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, CalcGuide</rights>
  <subtitle>AI Coding · 技术分享 · 工具实践</subtitle>
  <title>CalcGuide 技术博客</title>
  <updated>2026-06-15T07:56:28.174Z</updated>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="AI编程" scheme="https://blog.calcguide.tech/categories/AI%E7%BC%96%E7%A8%8B/"/>
    <category term="AI Coding" scheme="https://blog.calcguide.tech/tags/AI-Coding/"/>
    <category term="Agent" scheme="https://blog.calcguide.tech/tags/Agent/"/>
    <category term="Claude Code" scheme="https://blog.calcguide.tech/tags/Claude-Code/"/>
    <category term="自动化" scheme="https://blog.calcguide.tech/tags/%E8%87%AA%E5%8A%A8%E5%8C%96/"/>
    <content>
      <![CDATA[<p>Claude Code 可以通过 -p 标志、权限绕过、循环模式和终端持久化的组合，实现数小时甚至整夜的无人值守运行。开发者社区已经形成了一套可靠的操作手册：容器化运行环境、使用 “Ralph Wiggum” 循环模式、安装四个关键 Hook 防止卡死、保持 CLAUDE.md 精简。</p><h2 id="一、消除人工干预的三种模式"><a href="#一、消除人工干预的三种模式" class="headerlink" title="一、消除人工干预的三种模式"></a>一、消除人工干预的三种模式</h2><p>Claude Code 提供三个级别的自主运行模式：</p><h3 id="模式-1：-p（print-pipe）标志"><a href="#模式-1：-p（print-pipe）标志" class="headerlink" title="模式 1：-p（print&#x2F;pipe）标志"></a>模式 1：-p（print&#x2F;pipe）标志</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">claude -p <span class="string">&quot;查找并修复 auth.py 中的 bug&quot;</span> --allowedTools <span class="string">&quot;Read,Edit,Bash&quot;</span></span><br></pre></td></tr></table></figure><h3 id="模式-2：–permission-mode-auto"><a href="#模式-2：–permission-mode-auto" class="headerlink" title="模式 2：–permission-mode auto"></a>模式 2：–permission-mode auto</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">claude --permission-mode auto -p <span class="string">&quot;重构认证模块&quot;</span></span><br></pre></td></tr></table></figure><h3 id="模式-3：–dangerously-skip-permissions"><a href="#模式-3：–dangerously-skip-permissions" class="headerlink" title="模式 3：–dangerously-skip-permissions"></a>模式 3：–dangerously-skip-permissions</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">claude --dangerously-skip-permissions -p <span class="string">&quot;构建这个功能&quot;</span></span><br></pre></td></tr></table></figure><h2 id="二、Ralph-Wiggum-循环"><a href="#二、Ralph-Wiggum-循环" class="headerlink" title="二、Ralph Wiggum 循环"></a>二、Ralph Wiggum 循环</h2><p>最经过实战验证的长时间自主工作模式——一个 bash while 循环持续向 Claude 喂相同的 prompt。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">while</span> <span class="literal">true</span>; <span class="keyword">do</span></span><br><span class="line">  claude --dangerously-skip-permissions -p <span class="string">&quot;<span class="subst">$(cat PROMPT.md)</span>&quot;</span></span><br><span class="line">  <span class="built_in">sleep</span> 1</span><br><span class="line"><span class="keyword">done</span></span><br></pre></td></tr></table></figure><h2 id="三、四个关键-Hook"><a href="#三、四个关键-Hook" class="headerlink" title="三、四个关键 Hook"></a>三、四个关键 Hook</h2><table><thead><tr><th>Hook</th><th>作用</th></tr></thead><tbody><tr><td>No-Ask-Human</td><td>阻止 AskUserQuestion 工具调用</td></tr><tr><td>Context Monitor</td><td>监控上下文，自动注入 &#x2F;compact</td></tr><tr><td>Syntax Check</td><td>文件编辑后立即语法检查</td></tr><tr><td>Decision Warn</td><td>标记破坏性命令</td></tr></tbody></table><h2 id="四、tmux-持久化"><a href="#四、tmux-持久化" class="headerlink" title="四、tmux 持久化"></a>四、tmux 持久化</h2><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">tmux new -s claude-work</span><br><span class="line">claude --permission-mode auto</span><br><span class="line"><span class="comment"># Ctrl+B D 分离</span></span><br><span class="line">tmux attach -t claude-work</span><br></pre></td></tr></table></figure><h2 id="五、快速启动清单"><a href="#五、快速启动清单" class="headerlink" title="五、快速启动清单"></a>五、快速启动清单</h2><ol><li><code>git add -A &amp;&amp; git commit -m &quot;pre-autonomous checkpoint&quot;</code></li><li><code>npx cc-safe-setup</code></li><li><code>tmux new -s overnight</code></li><li>启动循环，去睡觉</li></ol>]]>
    </content>
    <id>https://blog.calcguide.tech/2026/04/15/claude-code-autonomous-guide/</id>
    <link href="https://blog.calcguide.tech/2026/04/15/claude-code-autonomous-guide/"/>
    <published>2026-04-14T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Claude Code 可以通过 -p 标志、权限绕过、循环模式和终端持久化的组合，实现数小时甚至整夜的无人值守运行。开发者社区已经形成了一套可靠的操作手册：容器化运行环境、使用 “Ralph Wiggum” 循环模式、安装四个关键 Hook 防止卡死、保持 CLAUDE.]]>
    </summary>
    <title>让 Claude Code 在你睡觉时持续运行：完整实战指南</title>
    <updated>2026-06-15T07:56:28.174Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux命令" scheme="https://blog.calcguide.tech/categories/Linux%E5%91%BD%E4%BB%A4/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="China’s-Leading-AI-Tools-Transforming-the-Global-Tech-Landscape"><a href="#China’s-Leading-AI-Tools-Transforming-the-Global-Tech-Landscape" class="headerlink" title="China’s Leading AI Tools: Transforming the Global Tech Landscape"></a>China’s Leading AI Tools: Transforming the Global Tech Landscape</h1><p>In recent years, China has emerged as a global powerhouse in the field of artificial intelligence (AI). With significant investments in research and development, a vast pool of talented engineers, and a vibrant startup ecosystem, Chinese companies have developed a range of AI tools that are not only revolutionizing domestic industries but also making waves around the world. In this article, we will explore some of the most remarkable AI tools hailing from China, their features, applications, and the impact they are having on various sectors globally.</p><p>Understanding China’s AI Ascendancy</p><p>China’s rapid progress in AI is no accident. The government has been actively promoting AI development through strategic initiatives, pouring substantial funds into research institutions and startups. This support, combined with a large population that provides abundant data for training AI models, has created a fertile ground for innovation. Chinese tech giants and innovative startups alike have been quick to capitalize on these advantages, resulting in the creation of some truly game - changing AI tools.</p><p>Alibaba Cloud’s Qwen - A Multifaceted AI Powerhouse</p><h3 id="Natural-Language-Processing-Prowess"><a href="#Natural-Language-Processing-Prowess" class="headerlink" title="Natural Language Processing Prowess"></a>Natural Language Processing Prowess</h3><p>Alibaba Cloud’s Qwen is a leading language model with capabilities that rival the best in the world. It has been trained on an extensive corpus of text, enabling it to understand and generate human language with remarkable fluency. For example, in content creation, Qwen can generate high - quality articles, blog posts, and product descriptions. A marketing team in a global e - commerce company could use Qwen to quickly generate product descriptions in multiple languages, saving countless hours of manual writing.</p><h3 id="Industry-Specific-Applications"><a href="#Industry-Specific-Applications" class="headerlink" title="Industry - Specific Applications"></a>Industry - Specific Applications</h3><p>Qwen has been tailored for various industries. In the financial sector, it can analyze market trends, news articles, and financial reports to provide valuable insights for investment decisions. In healthcare, it can assist doctors in diagnosing diseases by analyzing patient symptoms and medical literature. A hospital in a developing country might use Qwen to help its doctors access the latest medical research and make more informed decisions, even if they have limited resources.</p><h3 id="Advantages-in-Multilingual-Support"><a href="#Advantages-in-Multilingual-Support" class="headerlink" title="Advantages in Multilingual Support"></a>Advantages in Multilingual Support</h3><p>One of Qwen’s stand - out features is its excellent multilingual support. With China’s growing global trade and business connections, Qwen can translate text accurately between multiple languages, breaking down language barriers. A multinational corporation with operations in China and other countries can use Qwen to communicate seamlessly with its international teams, ensuring that information is conveyed clearly and correctly.</p><p>ByteDance’s Cloud 雀 - Empowering Visual Creativity</p><h3 id="Image-and-Video-Generation"><a href="#Image-and-Video-Generation" class="headerlink" title="Image and Video Generation"></a>Image and Video Generation</h3><p>Cloud 雀，developed by ByteDance, is a powerful AI tool in the realm of visual content. It can generate high - resolution images and engaging videos from simple text prompts. For instance, a small advertising agency in Europe could use Cloud 雀 to quickly create eye - catching images for its clients’ social media campaigns. Instead of spending a fortune on professional photographers or graphic designers, they can simply describe the concept they want, and Cloud 雀 will bring it to life.</p><h3 id="Video-Editing-Made-Easy"><a href="#Video-Editing-Made-Easy" class="headerlink" title="Video Editing Made Easy"></a>Video Editing Made Easy</h3><p>In addition to generation, Cloud 雀 also simplifies video editing. It can automatically edit videos, adding transitions, music, and special effects based on the content. A content creator on YouTube, who is based in South America, can use Cloud 雀 to edit their vlogs more efficiently. They can input their raw footage and some basic instructions, and Cloud 雀 will produce a polished video ready for upload.</p><h3 id="Integration-with-Social-Media-Platforms"><a href="#Integration-with-Social-Media-Platforms" class="headerlink" title="Integration with Social Media Platforms"></a>Integration with Social Media Platforms</h3><p>ByteDance’s influence in the social media space means that Cloud 雀 can be easily integrated with popular platforms. This integration allows users to directly share their AI - created visual content on platforms like TikTok (which is owned by ByteDance) and other social media channels. A young influencer in Asia can use Cloud 雀 to create unique content and quickly share it with their followers, enhancing their online presence.</p><p>Tencent’s AI - Empowered Healthcare Solutions</p><h3 id="Medical-Image-Diagnosis"><a href="#Medical-Image-Diagnosis" class="headerlink" title="Medical Image Diagnosis"></a>Medical Image Diagnosis</h3><p>Tencent has developed AI tools that are making a significant impact in healthcare, particularly in medical image diagnosis. Their AI algorithms can analyze X - rays, MRIs, and CT scans with high accuracy, helping doctors detect diseases such as cancer and pneumonia at an early stage. In a rural hospital in Africa, where there may be a shortage of experienced radiologists, Tencent’s AI - based diagnostic tool can assist local doctors in interpreting medical images, potentially saving lives.</p><h3 id="Patient-Monitoring-and-Prediction"><a href="#Patient-Monitoring-and-Prediction" class="headerlink" title="Patient Monitoring and Prediction"></a>Patient Monitoring and Prediction</h3><p>Another aspect of Tencent’s healthcare AI is patient monitoring and prediction. The tool can analyze a patient’s vital signs, medical history, and lifestyle data to predict the likelihood of developing certain diseases or complications. A healthcare provider in North America can use this tool to proactively manage the health of their patients, intervening early to prevent serious health issues.</p><h3 id="Telemedicine-Support"><a href="#Telemedicine-Support" class="headerlink" title="Telemedicine Support"></a>Telemedicine Support</h3><p>With the rise of telemedicine, Tencent’s AI tools also play a crucial role. They can facilitate remote consultations by providing real - time translation (using language AI capabilities) during doctor - patient interactions, and by analyzing patient data collected at home through wearable devices. A patient in a remote area of Australia can consult with a specialist in China, with Tencent’s AI ensuring smooth communication and accurate diagnosis support.</p><p>DJI’s Intelligent Drone Technologies - AI in the Skies</p><h3 id="Autonomous-Flight-and-Obstacle-Avoidance"><a href="#Autonomous-Flight-and-Obstacle-Avoidance" class="headerlink" title="Autonomous Flight and Obstacle Avoidance"></a>Autonomous Flight and Obstacle Avoidance</h3><p>DJI, a world - renowned drone manufacturer based in China, has integrated AI into its drones to enable autonomous flight and advanced obstacle avoidance. Their drones can fly along pre - programmed routes, adjust their flight paths in real - time to avoid obstacles, and even land safely in challenging conditions. A wildlife conservation team in the Amazon rainforest can use DJI’s AI - equipped drones to monitor endangered species without disturbing their habitats. The drones can autonomously navigate through the dense forest, capturing valuable data on the animals’ behavior and population.</p><h3 id="Precision-Agriculture-Applications"><a href="#Precision-Agriculture-Applications" class="headerlink" title="Precision Agriculture Applications"></a>Precision Agriculture Applications</h3><p>In agriculture, DJI’s drones are being used for precision farming. The AI - powered drones can analyze crop health by capturing high - resolution images and using machine learning algorithms to detect signs of disease, nutrient deficiencies, or water stress. A large - scale farmer in the United States can use these drones to optimize their irrigation and fertilization schedules, increasing crop yields while reducing resource waste.</p><h3 id="Aerial-Photography-and-Filmmaking"><a href="#Aerial-Photography-and-Filmmaking" class="headerlink" title="Aerial Photography and Filmmaking"></a>Aerial Photography and Filmmaking</h3><p>For the creative industry, DJI’s drones offer AI - enhanced features for aerial photography and filmmaking. The drones can track moving subjects, maintain stable camera angles, and capture stunning footage. A film production company in Europe can use DJI drones to add unique aerial perspectives to their movies, enhancing the visual experience for the audience.</p><p>The Impact of Chinese AI Tools on Global Industries</p><h3 id="Transforming-Manufacturing"><a href="#Transforming-Manufacturing" class="headerlink" title="Transforming Manufacturing"></a>Transforming Manufacturing</h3><p>Chinese AI tools are revolutionizing the manufacturing sector globally. AI - powered robots and automation systems are being used to improve production efficiency, quality control, and supply chain management. For example, Foxconn, a major electronics manufacturer in China, has implemented AI - enabled robots in its factories. These robots can perform complex tasks with high precision, reducing errors and increasing production speed. This model is being replicated by manufacturing companies around the world, as they seek to stay competitive in the global market.</p><h3 id="Boosting-E-commerce"><a href="#Boosting-E-commerce" class="headerlink" title="Boosting E - commerce"></a>Boosting E - commerce</h3><p>In the e - commerce industry, Chinese AI tools are enhancing the customer experience. Recommendation engines powered by AI analyze customer browsing and purchase history to provide personalized product recommendations. Platforms like Alibaba’s Taobao use these AI - driven recommendation systems to help customers discover new products they may be interested in. This not only increases customer satisfaction but also boosts sales for merchants. E - commerce companies in other countries are looking to adopt similar AI - based strategies to improve their competitiveness.</p><h3 id="Advancing-Education"><a href="#Advancing-Education" class="headerlink" title="Advancing Education"></a>Advancing Education</h3><p>AI tools from China are also making inroads into the education sector. Intelligent tutoring systems can adapt to individual students’ learning styles and paces, providing personalized learning experiences. For example, some Chinese - developed AI - education platforms can analyze students’ performance on practice tests, identify areas of weakness, and provide targeted learning materials. Schools and educational institutions in different parts of the world are exploring the use of these AI - enabled educational tools to improve learning outcomes.</p><p>Challenges and Future Outlook</p><h3 id="Ethical-and-Regulatory-Concerns"><a href="#Ethical-and-Regulatory-Concerns" class="headerlink" title="Ethical and Regulatory Concerns"></a>Ethical and Regulatory Concerns</h3><p>As with any powerful technology, Chinese AI tools face ethical and regulatory challenges. Issues such as data privacy, algorithmic bias, and the potential for job displacement need to be carefully addressed. For example, as AI tools collect and analyze vast amounts of data, ensuring the privacy and security of this data is crucial. Governments around the world are starting to develop regulations to govern the use of AI, and Chinese companies will need to comply with these regulations while continuing to innovate.</p><h3 id="Global-Competition-and-Collaboration"><a href="#Global-Competition-and-Collaboration" class="headerlink" title="Global Competition and Collaboration"></a>Global Competition and Collaboration</h3><p>The global AI landscape is highly competitive, with companies from various countries vying for market share. Chinese AI companies will need to continue to differentiate themselves through innovation and high - quality products. At the same time, there is also room for collaboration. For example, in the fight against global challenges such as climate change, Chinese and international AI companies could work together to develop solutions. By sharing knowledge and resources, they can accelerate the development of AI - based technologies that benefit the entire world.</p><h3 id="Continued-Innovation-and-Expansion"><a href="#Continued-Innovation-and-Expansion" class="headerlink" title="Continued Innovation and Expansion"></a>Continued Innovation and Expansion</h3><p>Looking to the future, Chinese AI tools are expected to continue evolving and expanding into new areas. With ongoing research and development, we can anticipate even more advanced natural language processing, computer vision, and machine learning capabilities. Chinese companies may also explore new applications in emerging fields such as quantum computing and edge computing, further pushing the boundaries of what AI can achieve.</p><p>Conclusion</p><p>China’s leading AI tools are already making a significant impact on the global tech landscape. From language models that enable seamless communication to visual content creation tools that inspire creativity, and from healthcare solutions that save lives to intelligent drones that transform industries, these AI tools are enhancing productivity, improving lives, and driving innovation worldwide. As China continues to invest in AI research and development, and as Chinese companies navigate the challenges of the global market, we can expect even more remarkable AI tools to emerge in the future, further strengthening China’s position as a global AI leader.</p><p>FAQs</p><p>Are Chinese AI tools only applicable in China?</p><p>No, Chinese AI tools are designed to be used globally. Many of them offer multilingual support and are being adopted by companies and individuals in various countries across different industries.</p><p>How do Chinese AI tools compare to those from other countries?</p><p>Chinese AI tools are highly competitive. They often leverage China’s large data resources and advanced research capabilities. In some areas, such as natural language processing and visual content generation, Chinese AI tools are at the forefront of innovation.</p><p>What is the future of Chinese AI tool development?</p><p>The future looks bright. With continued government support, investment in R &amp; D, and a talented workforce, Chinese AI tools are expected to expand into new industries, improve existing capabilities, and contribute more to solving global challenges.</p><p>Do Chinese AI tools respect data privacy?</p><p>Chinese companies are increasingly aware of data privacy issues. They are implementing strict data protection measures and complying with international and domestic regulations to ensure the privacy and security of user data.</p><p>Can small businesses afford to use Chinese AI tools?</p><p>Many Chinese AI tools offer different pricing models, including options for small businesses. Some tools provide free - to - use basic versions or affordable subscription plans, making them accessible to businesses of all sizes.</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/13/2025-09-13-chinas-leading-ai-tools-transforming-the-global-tech-landscape/</id>
    <link href="https://blog.calcguide.tech/2025/09/13/2025-09-13-chinas-leading-ai-tools-transforming-the-global-tech-landscape/"/>
    <published>2025-09-12T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="China’s-Leading-AI-Tools-Transforming-the-Global-Tech-Landscape"><a href="#China’s-Leading-AI-Tools-Transforming-the-Global-Tech-Lan]]>
    </summary>
    <title>China's Leading AI Tools: Transforming the Global Tech Landscape</title>
    <updated>2026-06-15T07:56:28.174Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux命令" scheme="https://blog.calcguide.tech/categories/Linux%E5%91%BD%E4%BB%A4/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>5 AI Code Editors to Transform Your Development Workflow in 2025: A Global Guide</p><p>In 2025, the landscape of software development has been reshaped by AI-driven innovation—and nowhere is this more evident than in AI code editors. These tools have moved beyond basic code suggestions to become collaborative partners: they analyze your codebase, fix bugs with 90% accuracy, edit multiple files simultaneously, and even automate repetitive tasks. For developers across the globe—whether you’re a solo coder in Tokyo, a startup team in Berlin, or an enterprise engineer in Toronto—AI code editors save hours of work, reduce frustration, and let you focus on creative problem-solving.</p><p>This guide breaks down the top 5 AI code editors of 2025, each with unique strengths to fit different workflows, budgets, and technical needs. We’ll explore their key features, real-world use cases, pros and cons, and who they’re best suited for—so you can choose the tool that elevates your coding to the next level.</p><p>Why AI Code Editors Matter in 2025: The Global Developer’s Advantage</p><p>Before diving into the tools, let’s clarify why AI code editors have become non-negotiable for modern developers:</p><ul><li><p>Contextual intelligence: Unlike traditional editors, AI-powered tools understand your code’s structure, dependencies, and purpose—so suggestions aren’t just correct, but relevant to your project.</p></li><li><p>Time savings: Tasks that once took hours (e.g., debugging a complex error, writing boilerplate code, updating documentation) can now be done in minutes.</p></li><li><p>Reduced friction: No more switching between forums, documentation, and terminals—AI editors answer questions, run scripts, and fix issues directly in your workspace.</p></li><li><p>Global collaboration: For distributed teams, AI editors standardize coding styles, auto-generate context for new hires, and bridge language gaps (many support multilingual queries).</p></li></ul><p>In 2025, the best AI code editors don’t just “help” you code—they transform how you approach development. Let’s explore the top options.</p><ol><li>Cursor: The Go-To for Quick Edits and Comprehensive AI Assistance</li></ol><h3 id="What-Is-Cursor"><a href="#What-Is-Cursor" class="headerlink" title="What Is Cursor?"></a>What Is Cursor?</h3><p>Cursor is a lightweight, fast AI code editor built for developers who prioritize efficiency. It’s designed to handle everything from small bug fixes to building full applications—all with minimal setup. Developed with a focus on “code understanding,” Cursor doesn’t just generate snippets; it analyzes your entire project to provide context-aware solutions.</p><h3 id="Key-Features-2025-Update"><a href="#Key-Features-2025-Update" class="headerlink" title="Key Features (2025 Update)"></a>Key Features (2025 Update)</h3><ul><li><p>Code-Centric Chat: Chat directly with your source code to ask questions like, “Why is this function throwing an error?” or “Refactor this module to use TypeScript.” The AI references your project files to give precise answers.</p></li><li><p>Multi-File Editing: Edit or create multiple related files at once (e.g., update a React component and its corresponding test file) with a single instruction.</p></li><li><p>Bug Finder: Automatically scan your code for syntax errors, logical bugs, and performance issues—with step-by-step fixes.</p></li><li><p>Universal Autocomplete: Supports autocomplete for 50+ programming languages (Python, JavaScript, Rust, etc.) and file types (Markdown, JSON, YAML).</p></li><li><p>Terminal Integration: Get AI-powered autocomplete for terminal commands (e.g., Git, Docker, AWS CLI) to reduce typos and speed up workflow.</p></li></ul><h3 id="Real-World-Use-Case"><a href="#Real-World-Use-Case" class="headerlink" title="Real-World Use Case"></a>Real-World Use Case</h3><p>Maria, a frontend developer in Mexico City, uses Cursor to build tutorial projects for her YouTube channel. “When I need to create a sample e-commerce UI, I tell Cursor, ‘Build a React checkout form with validation and Redux integration,’” she says. “It generates the component, test file, and Redux slice—all in 2 minutes. I can focus on explaining the code instead of writing it.”</p><h3 id="Pros-and-Cons"><a href="#Pros-and-Cons" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>ProsConsBlazing fast (starts in &lt;3 seconds)Full features require a paid subscription ($15&#x2F;month for individuals)Intuitive interface (no steep learning curve)Limited offline functionality (relies on cloud AI models)Excellent for small-to-medium projectsLess optimized for monorepos with 1000+ filesSupports all major programming languages</p><h3 id="Who-Should-Use-Cursor"><a href="#Who-Should-Use-Cursor" class="headerlink" title="Who Should Use Cursor?"></a>Who Should Use Cursor?</h3><ul><li><p>Solo developers and content creators (tutorials, side projects)</p></li><li><p>Teams needing quick turnaround on small tasks (bug fixes, feature prototypes)</p></li><li><p>Beginners learning to code (AI chat explains concepts in plain language)</p></li></ul><ol start="2"><li>Windsurf: Autonomous Task Execution for Iterative Development</li></ol><h3 id="What-Is-Windsurf"><a href="#What-Is-Windsurf" class="headerlink" title="What Is Windsurf?"></a>What Is Windsurf?</h3><p>Windsurf is 2025’s breakout AI code editor, designed for developers who want AI to execute tasks independently—not just suggest code. Its “agentic workflow” lets the AI run scripts, check outputs, and iterate on solutions until your request is fully resolved. Think of it as a junior developer who works 24&#x2F;7 and never gets tired.</p><h3 id="Key-Features-2025-Update-1"><a href="#Key-Features-2025-Update-1" class="headerlink" title="Key Features (2025 Update)"></a>Key Features (2025 Update)</h3><p>Autonomous Agent Mode: Tell Windsurf a goal (e.g., “Train a Random Forest model for credit score prediction”), and it will:</p><ul><li><p>Create or edit necessary files (Python scripts, requirements.txt, data preprocessing code)</p></li><li><p>Run tests to validate functionality</p></li><li><p>Fix errors (e.g., missing dependencies, data formatting issues)</p></li><li><p>Document changes (adds comments, updates READMEs)</p></li><li><p>Interactive Iteration: If the first result isn’t perfect, you can refine it with follow-up prompts (“Add cross-validation” or “Optimize for imbalanced data”).</p></li><li><p>Type Hint &amp; Error Prevention: Automatically adds type hints, try-except blocks, and input validation to improve code quality.</p></li><li><p>GitOps Integration: Syncs with Git to commit changes, create branches, and even open pull requests—all from the editor.</p></li></ul><h3 id="Real-World-Use-Case-1"><a href="#Real-World-Use-Case-1" class="headerlink" title="Real-World Use Case"></a>Real-World Use Case</h3><p>Raj, a data scientist in Bangalore, uses Windsurf to build machine learning pipelines. “I used to spend 3 days setting up a model training workflow,” he says. “Now I tell Windsurf, ‘Build a pipeline that loads CSV data, imputes missing values, trains a model, and saves it with versioning.’ It does it in 30 minutes—including testing edge cases I would have missed.”</p><h3 id="Pros-and-Cons-1"><a href="#Pros-and-Cons-1" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>ProsConsAutonomous task execution (no manual step-by-step)Subscription-only ($20&#x2F;month; no free tier)Excellent for data science and backend projectsSteeper learning curve than CursorAutomatically documents changesUses more system resources (needs 8GB+ RAM)Integrates with Git and cloud platforms (AWS, GCP)</p><h3 id="Who-Should-Use-Windsurf"><a href="#Who-Should-Use-Windsurf" class="headerlink" title="Who Should Use Windsurf?"></a>Who Should Use Windsurf?</h3><ul><li><p>Data scientists and backend developers (complex, multi-step tasks)</p></li><li><p>Teams working on iterative projects (e.g., model tuning, API development)</p></li><li><p>Developers who want to automate repetitive workflows (e.g., setting up Docker containers)</p></li></ul><ol start="3"><li>VSCode (with GitHub Copilot): The Free, Ecosystem-Powered Workhorse</li></ol><h3 id="What-Is-VSCode-GitHub-Copilot"><a href="#What-Is-VSCode-GitHub-Copilot" class="headerlink" title="What Is VSCode + GitHub Copilot?"></a>What Is VSCode + GitHub Copilot?</h3><p>In 2025, Microsoft made a game-changing move: GitHub Copilot is now free for all VSCode users (previously a $19&#x2F;month subscription). VSCode—already the most popular code editor globally—now comes with built-in AI capabilities, making it accessible to developers of all budgets. Copilot integrates seamlessly with VSCode’s ecosystem, including extensions, terminals, and GitHub.</p><h3 id="Key-Features-2025-Update-2"><a href="#Key-Features-2025-Update-2" class="headerlink" title="Key Features (2025 Update)"></a>Key Features (2025 Update)</h3><ul><li><p>Free GitHub Copilot: Generates code, fixes bugs, and explains logic—no subscription required. Supports 100+ languages, from Python to COBOL.</p></li><li><p>Ecosystem Integration: Copilot works across GitHub (pull requests, issues), VSCode extensions (e.g., Docker, Kubernetes), and even the terminal (Copilot CLI for command suggestions).</p></li><li><p>Context-Aware Suggestions: Analyzes your open files, Git history, and project structure to provide relevant code snippets.</p></li><li><p>Multilingual Support: Ask questions or give instructions in 20+ languages (Spanish, Hindi, Japanese) for global teams.</p></li></ul><h3 id="Real-World-Use-Case-2"><a href="#Real-World-Use-Case-2" class="headerlink" title="Real-World Use Case"></a>Real-World Use Case</h3><p>Aisha, a junior developer in Nairobi, uses VSCode + Copilot to learn and contribute to open-source projects. “I’m new to React, so when I’m working on a PR, I ask Copilot, ‘Explain how this hook works,’” she says. “It breaks it down in simple terms, and the free access means I don’t have to choose between learning tools and paying rent.”</p><h3 id="Pros-and-Cons-2"><a href="#Pros-and-Cons-2" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>ProsCons100% free (no hidden costs)Less accurate than paid tools (occasional irrelevant suggestions)Massive ecosystem (10k+ extensions)Limited autonomous task execution (needs more manual guidance)Works offline for basic tasksSlower response times during peak hoursIntegrates with GitHub (pull requests, issues)</p><h3 id="Who-Should-Use-VSCode-GitHub-Copilot"><a href="#Who-Should-Use-VSCode-GitHub-Copilot" class="headerlink" title="Who Should Use VSCode + GitHub Copilot?"></a>Who Should Use VSCode + GitHub Copilot?</h3><ul><li><p>Beginners and students (free access, learning resources)</p></li><li><p>Teams on a tight budget (no subscription fees)</p></li><li><p>Developers who rely on VSCode extensions (e.g., frontend devs using ESLint, Prettier)</p></li><li><p>Open-source contributors (seamless GitHub integration)</p></li></ul><ol start="4"><li>Zed: The Rust-Powered Speed Demon for Performance-Conscious Devs</li></ol><h3 id="What-Is-Zed"><a href="#What-Is-Zed" class="headerlink" title="What Is Zed?"></a>What Is Zed?</h3><p>Zed is 2025’s fastest AI code editor—built entirely with Rust (a language known for speed and reliability). It leverages multiple CPU cores and your GPU to deliver real-time AI responses, even for large codebases. Zed is popular among developers who hate waiting: its AI suggestions appear in &lt;100ms, and it can handle monorepos with 10,000+ files without lag.</p><h3 id="Key-Features-2025-Update-3"><a href="#Key-Features-2025-Update-3" class="headerlink" title="Key Features (2025 Update)"></a>Key Features (2025 Update)</h3><ul><li><p>Blazing Fast Performance: Rust’s memory efficiency and GPU acceleration mean Zed runs 2–3x faster than VSCode or Cursor.</p></li><li><p>Flexible AI Integration: Use Zed’s built-in AI, connect to external models (Anthropic Claude 3.5, OpenAI GPT-4o), or run LLMs locally via Ollama (for privacy-sensitive projects).</p></li><li><p>Multi-User Collaboration: Real-time co-editing with AI assistance—great for distributed teams (e.g., a developer in London and a teammate in Sydney working on the same file).</p></li><li><p>Customizable Workspace: Tailor the UI, keybindings, and AI behavior to your workflow (e.g., disable autocomplete for specific files).</p></li></ul><h3 id="Real-World-Use-Case-3"><a href="#Real-World-Use-Case-3" class="headerlink" title="Real-World Use Case"></a>Real-World Use Case</h3><p>Liam, a backend engineer at a fintech startup in Toronto, uses Zed for a monorepo with 5,000+ Python files. “With VSCode, opening the repo took 5 minutes and autocomplete lagged,” he says. “Zed opens in 30 seconds, and AI suggestions pop up instantly—even when I’m editing a file with 1,000 lines of code. It’s a game-changer for productivity.”</p><h3 id="Pros-and-Cons-3"><a href="#Pros-and-Cons-3" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>ProsConsFastest AI response times ( &lt;100ms)AI features are less polished than Cursor&#x2F;WindsurfHandles large monorepos with easeLimited mobile support (no iPad&#x2F;Android app)Supports local LLMs (privacy-focused)Free tier has usage limits (100 AI queries&#x2F;day)Real-time co-editingPaid plan is $12&#x2F;month</p><h3 id="Who-Should-Use-Zed"><a href="#Who-Should-Use-Zed" class="headerlink" title="Who Should Use Zed?"></a>Who Should Use Zed?</h3><ul><li><p>Developers working on large codebases (monorepos, enterprise projects)</p></li><li><p>Rust enthusiasts (Zed’s codebase is open-source and Rust-focused)</p></li><li><p>Teams needing real-time collaboration (e.g., startup squads)</p></li><li><p>Privacy-conscious developers (local LLM support)</p></li></ul><ol start="5"><li>PearAI: The VSCode-Based Tool with Potential (Needs Improvement)</li></ol><h3 id="What-Is-PearAI"><a href="#What-Is-PearAI" class="headerlink" title="What Is PearAI?"></a>What Is PearAI?</h3><p>PearAI is an AI code editor built as an extension for VSCode—targeting developers who want to customize their AI setup. It lets you connect to your own AI models (via API or local deployment) instead of relying on the editor’s built-in models. While PearAI has potential, it’s still maturing: its 2025 update fixed some bugs but hasn’t closed the gap with leading tools.</p><h3 id="Key-Features-2025-Update-4"><a href="#Key-Features-2025-Update-4" class="headerlink" title="Key Features (2025 Update)"></a>Key Features (2025 Update)</h3><ul><li><p>Custom AI Integration: Connect to any LLM (e.g., OpenAI GPT-4o, Mistral, Llama 3) via API, or run models locally (e.g., Llama 3 70B on your laptop).</p></li><li><p>Context-Aware Chat: Ask questions about your codebase (e.g., “Where is the user authentication logic?”) and get answers based on open files.</p></li><li><p>Autocomplete &amp; Refactoring: Basic AI-powered suggestions for code completion and refactoring (e.g., converting a function to a class).</p></li><li><p>Team Sharing: Save custom AI configurations (e.g., model API keys, prompt templates) and share them with your team.</p></li></ul><h3 id="Real-World-Use-Case-4"><a href="#Real-World-Use-Case-4" class="headerlink" title="Real-World Use Case"></a>Real-World Use Case</h3><p>Carlos, a DevOps engineer in Madrid, uses PearAI with a local Llama 3 model for sensitive infrastructure code. “I can’t send production Dockerfiles to cloud AI models,” he says. “PearAI lets me run Llama 3 on my machine, so all code stays local. It’s not as fast as Zed, but it solves a critical privacy problem.”</p><h3 id="Pros-and-Cons-4"><a href="#Pros-and-Cons-4" class="headerlink" title="Pros and Cons"></a>Pros and Cons</h3><p>ProsConsCustom AI model support (local&#x2F;cloud)Slow response times (1–2 seconds per suggestion)Integrates with VSCode (familiar interface)Fewer features than competitors (no multi-file editing)Privacy-focused (local LLM option)Complicated setup (needs API key&#x2F;config for custom models)Free tier available (limited features)Infrequent updates (last major release was 3 months ago)</p><h3 id="Who-Should-Use-PearAI"><a href="#Who-Should-Use-PearAI" class="headerlink" title="Who Should Use PearAI?"></a>Who Should Use PearAI?</h3><ul><li><p>Developers needing custom AI models (e.g., local LLMs, enterprise-specific models)</p></li><li><p>VSCode loyalists who don’t want to switch editors</p></li><li><p>Privacy-focused teams (e.g., healthcare, finance)</p></li><li><p>Developers willing to trade polish for customization</p></li></ul><p>2025 AI Code Editor Comparison: Choose the Right Tool for You</p><p>To simplify your decision, here’s a side-by-side comparison of the top 5 tools:</p><p>FeatureCursorWindsurfVSCode + CopilotZedPearAIPrice$15&#x2F;month (free tier: 50 queries&#x2F;day)$20&#x2F;month (no free tier)FreeFree (100 queries&#x2F;day); $12&#x2F;month (unlimited)Free (basic); $10&#x2F;month (custom models)SpeedFast ( &lt;500ms)Medium (1–1.5s)Medium (1–2s)Fastest ( &lt;100ms)Slow (1–2s)AI AutonomyLow (needs guidance)High (runs tasks independently)Low (basic suggestions)Medium (some autonomy)Low (basic suggestions)Best ForQuick edits, tutorialsData science, backendBeginners, free usersLarge codebases, speedCustom models, privacyOffline SupportLimitedNoBasicYes (local LLMs)Yes (local LLMs)</p><p>Conclusion: Elevate Your Coding with AI in 2025</p><p>AI code editors are no longer “nice-to-have”—they’re essential tools for staying competitive in 2025’s fast-paced development landscape. Whether you prioritize speed (Zed), autonomy (Windsurf), cost (VSCode + Copilot), or customization (PearAI), there’s a tool that fits your workflow.</p><p>Here’s a final recap to guide your choice:</p><ul><li><p>Choose Cursor if you want fast, intuitive AI for small-to-medium projects.</p></li><li><p>Choose Windsurf if you need AI to run complex, multi-step tasks independently.</p></li><li><p>Choose VSCode + Copilot if you’re on a budget or already use VSCode.</p></li><li><p>Choose Zed if you work on large codebases and hate waiting for AI responses.</p></li><li><p>Choose PearAI if you need custom AI models (local or cloud) and don’t mind a less polished experience.</p></li></ul><p>No matter which tool you pick, the goal is the same: let AI handle the repetitive, time-consuming work so you can focus on what matters most—building innovative software that solves real problems. Try one (or more!) today and see how AI transforms your coding workflow.</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/13/2025-09-13-5-ai-code-editors/</id>
    <link href="https://blog.calcguide.tech/2025/09/13/2025-09-13-5-ai-code-editors/"/>
    <published>2025-09-12T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>5 AI Code Editors to Transform Your Development Workflow in 2025: A Global Guide</p>
<p>In 2025, the landscape of software development ha]]>
    </summary>
    <title>5 AI Code Editors to Transform Your Development Workflow in 2025: A Global Guide</title>
    <updated>2026-06-15T07:56:28.173Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux命令" scheme="https://blog.calcguide.tech/categories/Linux%E5%91%BD%E4%BB%A4/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>Qoder: The Agentic Coding Platform Transforming Professional Software Development Globally</p><p>In the fast-paced world of professional software development, teams and individual developers are constantly seeking tools that can streamline workflows, enhance collaboration, and automate complex tasks. Enter Qoder – an innovative agentic coding platform designed to revolutionize how software is built, documented, and maintained. Whether you’re a solo developer tackling a passion project, a team lead managing a cross-functional engineering team, or an open-source maintainer coordinating contributors worldwide, Qoder brings a suite of powerful features to help you think deeper, code smarter, and build better.</p><p>What Is Qoder, and Why Does It Matter for Developers?</p><p>At its core, Qoder is an agentic coding platform tailored for professional software development. Unlike basic code suggestion tools that offer piecemeal lines of code, Qoder unites three key pillars to deliver end-to-end value: enhanced context engineering, intelligent AI agents, and in-repo documentation. This combination allows the platform to deeply understand your codebase, adapt to your project’s unique needs, and automate tasks that once required hours of manual work.</p><p>For developers and teams across the globe, Qoder addresses critical pain points in the software development lifecycle:</p><ul><li><p>Disconnected context: Many tools fail to maintain a consistent understanding of a codebase’s structure, dependencies, and coding standards across sessions. Qoder’s persistent memory solves this by preserving project-specific context.</p></li><li><p>Outdated documentation: Keeping docs in sync with code is a constant battle. Qoder’s auto-updated Repo Wiki eliminates this chore, ensuring documentation always reflects the latest codebase changes.</p></li><li><p>Inefficient task delegation: Complex tasks like building a new feature or refactoring legacy code often require manual orchestration. Qoder’s Quest Mode lets you delegate these tasks to AI agents asynchronously, freeing you to focus on high-impact work.</p></li><li><p>Tool fragmentation: Developers waste time switching between Git clients, documentation tools, and AI models. Qoder integrates seamlessly with Git&#x2F;GitHub, supports top AI models (Claude, GPT, Gemini), and runs on Windows and macOS – all in one unified workspace.</p></li></ul><p>Qoder’s Top Features: Built for Global Development Teams</p><p>Qoder’s feature set is designed to solve real-world challenges faced by developers everywhere. Each tool is engineered to work in harmony, creating a cohesive workflow that adapts to your team’s size, project type, and technical stack. Let’s break down the platform’s most impactful capabilities:</p><h3 id="1-Agentic-Coding-Platform-AI-Agents-That-Handle-Structured-Tasks"><a href="#1-Agentic-Coding-Platform-AI-Agents-That-Handle-Structured-Tasks" class="headerlink" title="1. Agentic Coding Platform: AI Agents That Handle Structured Tasks"></a>1. Agentic Coding Platform: AI Agents That Handle Structured Tasks</h3><p>Qoder’s intelligent AI agents are more than just code generators – they’re collaborative partners that tackle structured development tasks. Unlike tools that suggest isolated code snippets, these agents can:</p><ul><li><p>Refactor entire modules while preserving functionality and adhering to your coding style.</p></li><li><p>Debug complex issues by cross-referencing codebase context and error logs.</p></li><li><p>Implement multi-step features (e.g., adding user authentication, integrating a third-party API) with minimal human oversight.</p></li><li><p>Generate unit tests that cover edge cases, ensuring code reliability.</p></li></ul><p>This is a game-changer for teams in time zones across the globe: a developer in Tokyo can delegate a task to an AI agent at the end of their day, and a colleague in New York can review the completed work first thing in the morning – no manual handoff required.</p><h3 id="2-Enhanced-Context-Engineering-AI-That-Truly-Understands-Your-Code"><a href="#2-Enhanced-Context-Engineering-AI-That-Truly-Understands-Your-Code" class="headerlink" title="2. Enhanced Context Engineering: AI That Truly Understands Your Code"></a>2. Enhanced Context Engineering: AI That Truly Understands Your Code</h3><p>The biggest limitation of many AI coding tools is their lack of deep context. Qoder solves this with enhanced context engineering – a system that aggregates and updates information from multiple sources (code files, Git history, documentation, and team guidelines) to build a holistic view of your codebase.</p><p>For example, if you ask Qoder to “optimize the checkout flow,” the platform doesn’t just generate generic optimization code. It:</p><ul><li><p>Reviews the existing checkout logic, including dependencies on payment gateways and user data models.</p></li><li><p>References your team’s coding standards (stored in Qoder’s Memory) to ensure consistency.</p></li><li><p>Checks the Repo Wiki for documentation on past checkout-related updates.</p></li><li><p>Considers recent Git commits to avoid conflicting with ongoing work.</p></li></ul><p>This level of context ensures AI suggestions are not just correct, but relevant to your project – a critical advantage for global teams working on complex, custom codebases.</p><h3 id="3-Quest-Mode-Asynchronous-Task-Delegation-for-Busy-Teams"><a href="#3-Quest-Mode-Asynchronous-Task-Delegation-for-Busy-Teams" class="headerlink" title="3. Quest Mode: Asynchronous Task Delegation for Busy Teams"></a>3. Quest Mode: Asynchronous Task Delegation for Busy Teams</h3><p>One of Qoder’s most popular features is Quest Mode – a tool that lets you delegate complex, time-consuming tasks to AI agents and receive complete, ready-to-use results. Unlike real-time AI chat, Quest Mode is asynchronous, meaning you can set a task and come back later to find it done.</p><p>How it works:</p><p>Define the task (e.g., “Build a user profile API endpoint with input validation and error handling”).</p><p>Add context (e.g., “Use our existing Express.js framework, follow the REST API guidelines in the Repo Wiki, and integrate with the user database”).</p><p>Submit the “Quest” to Qoder’s AI agents.</p><p>Receive a notification when the task is complete – including code, tests, and a summary of changes.</p><p>This is ideal for:</p><ul><li><p>Solo developers who need to multitask (e.g., delegate API development while designing a UI).</p></li><li><p>Global teams working across time zones (e.g., a London-based developer delegates a task before logging off, and a Sydney-based teammate reviews it the next day).</p></li><li><p>Team leads who want to free up senior developers from repetitive work (e.g., delegating boilerplate code generation to AI).</p></li></ul><h3 id="4-Repo-Wiki-Auto-Updated-Documentation-That-Lives-With-Your-Code"><a href="#4-Repo-Wiki-Auto-Updated-Documentation-That-Lives-With-Your-Code" class="headerlink" title="4. Repo Wiki: Auto-Updated Documentation That Lives With Your Code"></a>4. Repo Wiki: Auto-Updated Documentation That Lives With Your Code</h3><p>Outdated documentation is a universal frustration for developers. Qoder’s Repo Wiki eliminates this problem by automatically generating and updating documentation that lives directly in your repository. Unlike static wikis (e.g., Confluence pages that are forgotten after launch), the Repo Wiki:</p><ul><li><p>Updates in real time when you make code changes (e.g., if you add a new function to a utility file, the Wiki automatically adds documentation for that function).</p></li><li><p>Syncs bidirectionally with GitHub Wiki – so if you update the Repo Wiki in Qoder, the changes appear in GitHub, and vice versa.</p></li><li><p>Is accessible to AI agents, chat, and the CLI – ensuring AI suggestions and team decisions are always based on the latest docs.</p></li></ul><p>For example, if a new hire in Toronto joins your team, they don’t need to spend hours reading outdated READMEs or pinging teammates for clarification. They can open the Repo Wiki to find:</p><ul><li><p>Auto-generated architecture diagrams of the codebase.</p></li><li><p>Up-to-date API references with example requests&#x2F;responses.</p></li><li><p>Step-by-step guides for setting up the local development environment.</p></li><li><p>Notes on past bugs and how they were resolved.</p></li></ul><p>This not only speeds up onboarding but also reduces knowledge silos – a key benefit for distributed teams.</p><h3 id="5-Live-Project-Context-Memory-Consistent-Guidance-Across-Sessions"><a href="#5-Live-Project-Context-Memory-Consistent-Guidance-Across-Sessions" class="headerlink" title="5. Live Project Context &amp; Memory: Consistent Guidance Across Sessions"></a>5. Live Project Context &amp; Memory: Consistent Guidance Across Sessions</h3><p>Qoder’s persistent Memory system stores project-specific information (coding standards, team guidelines, tool preferences, and past decisions) so that every AI interaction is consistent – even if you log off and come back weeks later.</p><p>For example, if your team decides “we use ESLint with Airbnb rules” or “all database queries must go through the data access layer,” you can save these guidelines to Memory. From that point on:</p><ul><li><p>AI agents will automatically follow these rules when generating code.</p></li><li><p>New team members will see these guidelines in the Repo Wiki and AI suggestions.</p></li><li><p>The CLI will flag code that violates these standards during development.</p></li></ul><p>This consistency is invaluable for global teams where members may have different coding backgrounds or join mid-project. It ensures everyone – from a junior developer in Mumbai to a senior engineer in Toronto – is working from the same playbook.</p><h3 id="6-Git-GitHub-Integration-Seamless-Collaboration-for-Distributed-Teams"><a href="#6-Git-GitHub-Integration-Seamless-Collaboration-for-Distributed-Teams" class="headerlink" title="6. Git&#x2F;GitHub Integration: Seamless Collaboration for Distributed Teams"></a>6. Git&#x2F;GitHub Integration: Seamless Collaboration for Distributed Teams</h3><p>Qoder integrates seamlessly with Git and GitHub – the most widely used version control tools in the world. This integration ensures your code, documentation, and context stay in sync across your team’s workflow:</p><ul><li><p>The Repo Wiki is stored in your Git repository, so it’s version-controlled alongside your code.</p></li><li><p>Changes to the Repo Wiki in Qoder sync automatically to GitHub Wiki, and vice versa.</p></li><li><p>AI agents can reference Git history (e.g., “Who last modified this file?” or “What was the purpose of this commit?”) to make more informed decisions.</p></li><li><p>You can trigger AI tasks (e.g., “Review this pull request”) directly from GitHub.</p></li></ul><p>For distributed teams, this integration eliminates the need to switch between tools – everything you need to code, document, and collaborate is in one place.</p><h3 id="7-Multi-Model-AI-Engine-Flexibility-for-Every-Project"><a href="#7-Multi-Model-AI-Engine-Flexibility-for-Every-Project" class="headerlink" title="7. Multi-Model AI Engine: Flexibility for Every Project"></a>7. Multi-Model AI Engine: Flexibility for Every Project</h3><p>Qoder doesn’t lock you into a single AI model. Its multi-model AI engine supports three of the most powerful models for coding: Claude (Anthropic), GPT (OpenAI), and Gemini (Google). This flexibility lets you choose the model that best fits your project’s needs:</p><ul><li><p>Claude: Ideal for long-form tasks (e.g., refactoring a large codebase) thanks to its extended context window.</p></li><li><p>GPT: Great for general coding tasks (e.g., generating boilerplate code, debugging) with its strong understanding of common programming languages.</p></li><li><p>Gemini: Excels at tasks involving multiple languages or emerging technologies (e.g., integrating AI models into your code).</p></li></ul><p>You can even switch models per project – for example, using Claude for a legacy code refactor and GPT for building a new React component. This level of flexibility is rare in coding tools and ensures Qoder adapts to your team’s technical preferences.</p><h3 id="8-Cross-Platform-Support-Run-Qoder-Anywhere"><a href="#8-Cross-Platform-Support-Run-Qoder-Anywhere" class="headerlink" title="8. Cross-Platform Support: Run Qoder Anywhere"></a>8. Cross-Platform Support: Run Qoder Anywhere</h3><p>Qoder is built for global developers, which means it works on the operating systems you use. The platform offers installers for Windows and macOS, with a consistent user experience across both. Whether you’re a Windows user in Berlin or a macOS user in Tokyo, you’ll have access to all of Qoder’s features without compatibility issues.</p><p>Who Uses Qoder? Real-World Use Cases for Global Teams</p><p>Qoder’s versatility makes it a fit for nearly every role and project type in software development. Here are the most common use cases, with examples of how global teams are leveraging the platform:</p><h3 id="1-Solo-Developers-Multitask-Without-Sacrificing-Quality"><a href="#1-Solo-Developers-Multitask-Without-Sacrificing-Quality" class="headerlink" title="1. Solo Developers: Multitask Without Sacrificing Quality"></a>1. Solo Developers: Multitask Without Sacrificing Quality</h3><p>Solo developers often wear multiple hats – from coding to documentation to testing. Qoder helps them work more efficiently by:</p><ul><li><p>Delegating multi-step tasks (e.g., “Build a login system with JWT authentication”) to AI agents via Quest Mode.</p></li><li><p>Auto-generating documentation so they don’t have to stop coding to update READMEs.</p></li><li><p>Providing context-aware suggestions that align with their personal coding style (stored in Memory).</p></li></ul><p>For example, a solo developer in Brazil building an e-commerce app can use Quest Mode to delegate the payment gateway integration while they design the product catalog UI. By the time they finish the UI, the payment code is ready to test – cutting their development time in half.</p><h3 id="2-Team-Leads-Engineering-Managers-Streamline-Collaboration-and-Enforce-Standards"><a href="#2-Team-Leads-Engineering-Managers-Streamline-Collaboration-and-Enforce-Standards" class="headerlink" title="2. Team Leads &amp; Engineering Managers: Streamline Collaboration and Enforce Standards"></a>2. Team Leads &amp; Engineering Managers: Streamline Collaboration and Enforce Standards</h3><p>Team leads overseeing distributed teams face the challenge of keeping everyone aligned. Qoder solves this by:</p><ul><li><p>Using Memory to enforce consistent coding standards (e.g., “All React components must use functional hooks”) across the team.</p></li><li><p>Providing real-time visibility into AI-assisted tasks (e.g., “Which team members have delegated tasks via Quest Mode?”).</p></li><li><p>Simplifying code reviews by ensuring documentation (in Repo Wiki) and code are always in sync.</p></li></ul><p>A team lead in London managing a team of 10 developers across India, Canada, and Australia can use Qoder to:</p><ul><li><p>Set global guidelines in Memory (e.g., “We use TypeScript for all new frontend code”).</p></li><li><p>Monitor Quest Mode tasks to ensure no one is stuck on repetitive work.</p></li><li><p>Share the Repo Wiki with stakeholders to keep them updated on progress – no manual status reports needed.</p></li></ul><h3 id="3-New-Hires-Onboarding-Ramp-Up-Fast-No-Matter-Where-You-Are"><a href="#3-New-Hires-Onboarding-Ramp-Up-Fast-No-Matter-Where-You-Are" class="headerlink" title="3. New Hires &amp; Onboarding: Ramp Up Fast, No Matter Where You Are"></a>3. New Hires &amp; Onboarding: Ramp Up Fast, No Matter Where You Are</h3><p>Onboarding new developers to a complex codebase can take weeks – especially for remote hires. Qoder’s Repo Wiki and context-aware AI cut this time down significantly:</p><ul><li><p>New hires can use the Repo Wiki to access auto-generated architecture overviews, API references, and setup guides.</p></li><li><p>AI agents can answer questions like “How does the user authentication flow work?” or “Where is the payment logic stored?” in real time.</p></li><li><p>Memory ensures new hires receive suggestions that align with the team’s standards from day one.</p></li></ul><p>A new developer in Singapore joining a U.S.-based team can use Qoder to:</p><ul><li><p>Set up their local environment in hours (instead of days) using the Repo Wiki’s step-by-step guide.</p></li><li><p>Ask the AI to explain a complex module without pinging a senior developer in a different time zone.</p></li><li><p>Contribute code within their first week, thanks to context-aware suggestions.</p></li></ul><h3 id="4-Open-Source-Maintainers-Keep-Contributors-Informed"><a href="#4-Open-Source-Maintainers-Keep-Contributors-Informed" class="headerlink" title="4. Open-Source Maintainers: Keep Contributors Informed"></a>4. Open-Source Maintainers: Keep Contributors Informed</h3><p>Open-source maintainers rely on clear documentation to attract and retain contributors. Qoder’s Repo Wiki makes this easy by:</p><ul><li><p>Auto-updating docs when code changes, so contributors always have accurate information.</p></li><li><p>Syncing with GitHub Wiki, so docs are accessible to anyone visiting the repo.</p></li><li><p>Letting maintainers delegate routine tasks (e.g., “Review this PR for code style”) to AI agents.</p></li></ul><p>A maintainer of a popular open-source library in Germany can use Qoder to:</p><ul><li><p>Ensure the README and API docs are always up to date, even as contributors from around the world submit PRs.</p></li><li><p>Use Quest Mode to generate a “contributor’s guide” based on past PR feedback.</p></li><li><p>Reduce the time spent on code reviews by having AI agents flag style issues first.</p></li></ul><h3 id="5-API-Developers-Tech-Writers-Keep-Docs-in-Sync-With-Code"><a href="#5-API-Developers-Tech-Writers-Keep-Docs-in-Sync-With-Code" class="headerlink" title="5. API Developers &amp; Tech Writers: Keep Docs in Sync With Code"></a>5. API Developers &amp; Tech Writers: Keep Docs in Sync With Code</h3><p>Tech writers and API developers spend hours updating documentation to match code changes. Qoder’s Repo Wiki automates this process:</p><ul><li><p>When an API endpoint is added or modified, the Repo Wiki automatically updates the API reference (including parameters, response codes, and examples).</p></li><li><p>AI agents can generate draft documentation for new endpoints, which tech writers can refine.</p></li><li><p>Docs sync with GitHub, so external users always have access to the latest API info.</p></li></ul><p>A tech writer in Canada working with an API team in India can use Qoder to:</p><ul><li><p>Avoid manually updating API docs every time the team makes a change.</p></li><li><p>Access the Repo Wiki to find context about why an endpoint was modified (e.g., “This change fixes a bug in the payment flow”).</p></li><li><p>Collaborate with the team in real time, even across time zones.</p></li></ul><p>Qoder Pricing: Free Access During Public Preview</p><p>For developers and teams looking to try Qoder, the platform offers free access during its public preview – no credit card required. This includes:</p><ul><li><p>All currently available features (including Quest Mode, Repo Wiki, and multi-model AI support).</p></li><li><p>A “pro-level experience” during testing, with no restrictions on core functionality.</p></li><li><p>Usage limits to ensure fair access for all users (details are available on the Qoder website).</p></li></ul><p>This free preview is a great opportunity for global teams to test Qoder’s capabilities on real projects, without any financial commitment. As the platform evolves, Qoder plans to introduce paid plans – but for now, anyone can sign up and start using the tool.</p><p>Qoder Alternatives: How It Stands Out</p><p>While there are other coding tools on the market, Qoder’s focus on agentic workflows, context engineering, and in-repo documentation sets it apart. Here’s how it compares to popular alternatives:</p><p>ToolKey FocusHow Qoder DiffersCodeiumReal-time code suggestionsQoder offers asynchronous task delegation (Quest Mode) and auto-updated documentation, while Codeium focuses on inline suggestions.QuestflowAI agent orchestration for workflowsQuestflow is designed for general workflow automation, while Qoder is built specifically for software development (with Git integration, code context, and multi-model AI).CodiumAIAI-powered code quality toolsCodiumAI focuses on testing and quality assurance, while Qoder offers end-to-end workflow support (documentation, task delegation, context management).CoderabbitAI-driven code reviewsCoderabbit specializes in PR reviews, while Qoder integrates code reviews with documentation, context, and task automation.</p><p>For developers who need more than just code suggestions – who want a tool that understands their codebase, automates complex tasks, and keeps docs up to date – Qoder is the clear choice.</p><p>How to Get Started With Qoder</p><p>Getting started with Qoder is simple, regardless of your location or technical stack:</p><p>Visit the Qoder website: Go to opentools.ai&#x2F;tools&#x2F;qoder to learn more about the platform.</p><p>Download the installer: Choose the version for Windows or macOS (both are free during the public preview).</p><p>Connect your Git&#x2F;GitHub repo: Link Qoder to your repository to let the platform build context and generate the Repo Wiki.</p><p>Set up your Memory: Add coding standards, team guidelines, or project-specific notes to ensure AI suggestions are consistent.</p><p>Start using features: Try Quest Mode for task delegation, explore the Repo Wiki for documentation, or use the AI chat to ask codebase questions.</p><p>Qoder’s onboarding process is designed to be intuitive – even for developers new to AI coding tools. If you run into issues, the platform offers support via its website (with troubleshooting guides and a community forum).</p><p>Conclusion: Qoder – The Future of Global Software Development</p><p>In a world where software teams are increasingly distributed, and development cycles are getting shorter, Qoder provides a much-needed solution: a tool that unites AI, context, and documentation to make coding more efficient, collaborative, and consistent.</p><p>Whether you’re a solo developer in a small town or a team lead managing engineers across five continents, Qoder’s features – from Quest Mode to Repo Wiki to multi-model AI – are built to adapt to your needs. And with free access during the public preview, there’s no better time to try it.</p><p>Join the growing community of global developers using Qoder to streamline their workflows, reduce manual work, and build better software. Visit opentools.ai&#x2F;tools&#x2F;qoder today to get started.</p><p>阿里Qoder vs. Cursor vs. Trae：2025年AI编程工具终极对决与深度避坑指南随着AI编程赛道进入 - 掘金</p><p><a href="https://opentools.ai/tools/qoder">https://opentools.ai/tools/qoder</a></p><p>Top 10 AI Code Editors in 2025 - DEV Community</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/13/2025-09-13-qoder-ai-code-ide/</id>
    <link href="https://blog.calcguide.tech/2025/09/13/2025-09-13-qoder-ai-code-ide/"/>
    <published>2025-09-12T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>Qoder: The Agentic Coding Platform Transforming Professional Software Development Globally</p>
<p>In the fast-paced world of professional]]>
    </summary>
    <title>Qoder: The Agentic Coding Platform Transforming Professional Software Development Globally</title>
    <updated>2026-06-15T07:56:28.174Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="AI编程" scheme="https://blog.calcguide.tech/categories/AI%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>阿里免费AI-IDE Qoder快速入门</p><p>开始使用</p><h1 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h1><p>本主题将引导您以个人用户身份使用 Qoder 核心功能的动手项目。最后，您将熟悉它的下一个编辑建议 （NES）、内联聊天和 AI 聊天——人工智能辅助编码的关键工具。</p><blockquote><p>Qoder 个人版目前可供所有用户免费试用。试用期可能会发生变化。有关最新信息，请查看产品更新。</p></blockquote><p>Qoder IDE 用户指南 - 完整使用教程和最佳实践 | 智能编程助手</p><p>Qoder IDE - AI-Powered Coding Platform for Real Development</p><p>Qoder Reviews, Alternatives, and Pricing updated September 2025</p><p>下载并安装 Qoder</p><p>从 <a href="https://qoder.com/download">https://qoder.com/download</a> 下载安装程序。</p><p>双击该文件开始安装。</p><p>通过双击 Qoder IDE 图标启动 Qoder。</p><p>2</p><p>登录</p><p>在 Qoder IDE 的右上角，单击用户图标或使用键盘快捷键（ （macOS）或 （Windows）），然后选择登录。⌘⇧,Ctrlshift,</p><p>在出现的网页上：</p><ul><li><p>点击底部的注册并完成注册过程，或</p></li><li><p>使用您的 Google 或 GitHub 帐户直接注册。</p></li></ul><p>返回 Qoder IDE。您现在可以自由使用所有功能。</p><p>3</p><p>打开项目</p><p>选择使用本地项目或从 GitHub 克隆示例。</p><ul><li><p>使用本地项目单击打开或使用键盘快捷键：</p></li><li><p>macOS：O⌘</p></li><li><p>窗户：OCtrl</p></li><li><p>浏览到项目文件夹，选择一个文件，然后将其打开。</p></li></ul><p>克隆项目</p><ul><li>单击克隆存储库。</li></ul><p>在顶部的搜索栏中：</p><ul><li><p>输入项目 URL，然后单击从 URL 克隆，或</p></li><li><p>单击“从 GitHub 克隆”，然后按照提示进行作。</p></li></ul><p>完成克隆项目的步骤。</p><p>4</p><p>探索功能</p><ul><li>触发 NES</li></ul><p>NES 通过在您的光标处提供智能、上下文感知的编辑，帮助您开始 AI 辅助编码。</p><p>输入部分代码片段或自然语言的代码请求。示例：“初始化列表。</p><p>按 （macOS） 或 （Windows）。建议将自动出现。⌥PAltP</p><p>按 Tab 键接受建议。</p><p>NES 支持多行编辑和无缝自动完成。</p><ul><li>发起内联聊天</li></ul><p>使用内联聊天直接在代码上下文中获取 AI 帮助。</p><p>在 Qoder 代码编辑器中，按 （macOS） 或 （Windows）。将打开“内联聊天”窗口。⌘ICtrlI</p><p>键入您的请求，然后按 Enter。示例：“添加用于处理文件更新的方法。</p><p>要应用 AI 生成的代码，请按 （macOS） 或 （Windows）。⌘⏎ CtrlEnter</p><ul><li>开始 AI 聊天</li></ul><p>使用 AI 聊天面板或按 （macOS） 或 （Windows） 在询问或代理模式下执行更广泛的任务。⌘L CtrlL</p><p>在右侧的 AI 聊天面板中，输入您的请求。示例：“为此函数创建测试并运行它们。</p><p>按 Enter 键。AI 代理将生成包含相关测试用例的测试文件。</p><p>单击“根据提示运行”，或按 （macOS） 或 （Windows） 执行测试。⌘⏎CtrlEnter</p><p>Get Started</p><h1 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h1><p>This topic walks you through a hands-on project using Qoder’s core features as an individual user. By the end, you’ll be familiar with its Next Edit Suggestions (NES), Inline Chat, and AI Chat—key tools for AI-assisted coding.</p><blockquote><p>Qoder Individual Edition is currently available as a free trial for all users. The trial duration is subject to change. For the latest information, please check product updates.</p></blockquote><p>1</p><p>Download and install Qoder</p><p>Download the installer from <a href="https://qoder.com/download">https://qoder.com/download</a>.</p><p>Double-click the file to begin installation.</p><p>Launch Qoder by double-clicking the Qoder IDE icon.</p><p>2</p><p>Sign in</p><p>In the upper-right corner of your Qoder IDE, click the user icon or use the keyboard shortcut ( （macOS）or (Windows)), and select Sign in.⌘⇧,Ctrlshift,</p><p>On the web page that appears:</p><ul><li><p>Click Sign up at the bottom and complete the registration process, or</p></li><li><p>Use your Google or GitHub account to sign up directly.</p></li></ul><p>Return to the Qoder IDE. You can now use all features freely.</p><p>3</p><p>Open a project</p><p>Choose to work with an local project or clone a sample from GitHub.</p><ul><li><p>Use a local projectClick Open or use the keyboard shortcut:</p></li><li><p>macOS:  O ⌘</p></li><li><p>Windows: O Ctrl</p></li><li><p>Browse to your project folder, select a file, and open it.</p></li></ul><p>Clone a project</p><ul><li>Click Clone repo.</li></ul><p>In the search bar at the top:</p><ul><li><p>Enter a project URL and click Clone from URL, or</p></li><li><p>Click Clone from GitHub and follow the prompts.</p></li></ul><p>Complete the steps to clone the project.</p><p>4</p><p>Explore features</p><ul><li>Trigger an NES</li></ul><p>NES helps you get started with AI-assisted coding by offering intelligent, context-aware edits right at your cursor.</p><p>Enter a partial code snippet or a code request in natural language. Example: “Initialize a list.”</p><p>Press  (macOS) or   (Windows). Suggestions will appear automatically.⌥PAltP</p><p>Press Tab to accept a suggestion.</p><p>NES supports multi-line edits, and seamless autocomplete.</p><ul><li>Initiate an inline chat</li></ul><p>Use Inline Chat to get AI help directly within your code context.</p><p>In the Qoder code editor, press  (macOS) or (Windows). The Inline Chat window will open.⌘ICtrlI</p><p>Type your request and press Enter. Example: “Add a method for handling file updates.”</p><p>To apply the AI-generated code, press   (macOS) or  (Windows).⌘⏎ CtrlEnter</p><ul><li>Start an AI chat</li></ul><p>Use the AI Chat panel or press (macOS) or (Windows) for broader tasks in Ask or Agent mode.⌘L CtrlL</p><p>In the AI Chat panel on the right, enter your request. Example: “Create tests for this function and run them.”</p><p>Press Enter. The AI agent will generate a test file with relevant test cases.</p><p>Click Run as prompted, or press   (macOS) or  (Windows) to execute the tests.⌘⏎CtrlEnter</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/11/2025-09-11-%E9%98%BF%E9%87%8C%E5%85%8D%E8%B4%B9ai-ide-qoder%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/</id>
    <link href="https://blog.calcguide.tech/2025/09/11/2025-09-11-%E9%98%BF%E9%87%8C%E5%85%8D%E8%B4%B9ai-ide-qoder%E5%BF%AB%E9%80%9F%E5%85%A5%E9%97%A8/"/>
    <published>2025-09-10T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>阿里免费AI-IDE Qoder快速入门</p>
<p>开始使用</p>
<h1 id="快速入门"><a href="#快速入门" class="headerlink" title="快速入门"></a>快速入门</h1><p>本主题将引导您以个人用户身份使用 Qoder]]>
    </summary>
    <title>阿里免费AI-IDE Qoder快速入门</title>
    <updated>2026-06-15T07:56:28.173Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getdents - 获取目录项</p><h3 id="函数介绍"><a href="#函数介绍" class="headerlink" title="函数介绍"></a>函数介绍</h3><p>getdents系统调用用于读取目录文件的内容，获取目录中的文件项信息。它返回原始的目录项结构，需要手动解析。这是一个低级别的目录读取函数。</p><h3 id="函数原型"><a href="#函数原型" class="headerlink" title="函数原型"></a>函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;dirent.h&gt;</span><br><span class="line">#include &lt;sys/syscall.h&gt;</span><br><span class="line"></span><br><span class="line">int getdents(unsigned int fd, struct linux_dirent *dirp, unsigned int count);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="功能"><a href="#功能" class="headerlink" title="功能"></a>功能</h3><p>从目录文件描述符中读取目录项信息。</p><h3 id="参数"><a href="#参数" class="headerlink" title="参数"></a>参数</h3><ul><li><p>unsigned int fd: 目录文件描述符（通过opendir或open获得）</p></li><li><p>struct linux_dirent *dirp: 指向存储目录项的缓冲区</p></li><li><p>unsigned int count: 缓冲区大小（字节）</p></li></ul><h3 id="返回值"><a href="#返回值" class="headerlink" title="返回值"></a>返回值</h3><ul><li>成功时返回读取的字节数</li></ul><p>失败时返回-1，并设置errno：</p><ul><li><p>EBADF: 文件描述符无效</p></li><li><p>EFAULT: 缓冲区地址无效</p></li><li><p>EINVAL: 参数无效</p></li><li><p>ENOENT: 目录不存在</p></li></ul><h3 id="相似函数"><a href="#相似函数" class="headerlink" title="相似函数"></a>相似函数</h3><ul><li><p>readdir(): 标准C库函数，更易使用</p></li><li><p>opendir(), closedir(): 打开和关闭目录</p></li><li><p>getdents64(): 64位版本，支持大文件</p></li></ul><h3 id="示例代码"><a href="#示例代码" class="headerlink" title="示例代码"></a>示例代码</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br><span class="line">300</span><br><span class="line">301</span><br><span class="line">302</span><br><span class="line">303</span><br><span class="line">304</span><br><span class="line">305</span><br><span class="line">306</span><br><span class="line">307</span><br><span class="line">308</span><br><span class="line">309</span><br><span class="line">310</span><br><span class="line">311</span><br><span class="line">312</span><br><span class="line">313</span><br><span class="line">314</span><br><span class="line">315</span><br><span class="line">316</span><br><span class="line">317</span><br><span class="line">318</span><br><span class="line">319</span><br><span class="line">320</span><br><span class="line">321</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;sys/stat.h&gt;</span><br><span class="line">#include &lt;sys/syscall.h&gt;</span><br><span class="line">#include &lt;linux/types.h&gt;</span><br><span class="line"></span><br><span class="line">// 目录项结构体定义</span><br><span class="line">struct linux_dirent &#123;</span><br><span class="line">    long d_ino;              // inode号</span><br><span class="line">    __kernel_off_t d_off;    // 到下一个目录项的偏移</span><br><span class="line">    unsigned short d_reclen; // 当前目录项长度</span><br><span class="line">    char d_name&amp;#91;];           // 文件名（以null结尾）</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    char buf&amp;#91;4096];</span><br><span class="line">    int nread;</span><br><span class="line">    char *p;</span><br><span class="line">    struct linux_dirent *d;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== Getdents函数示例 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 示例1: 基本的目录读取操作</span><br><span class="line">    printf(&quot;\n示例1: 基本的目录读取操作\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 打开当前目录</span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd == -1) &#123;</span><br><span class="line">        perror(&quot;打开当前目录失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;成功打开当前目录，文件描述符: %d\n&quot;, fd);</span><br><span class="line">    </span><br><span class="line">    // 使用getdents读取目录内容</span><br><span class="line">    printf(&quot;读取目录内容:\n&quot;);</span><br><span class="line">    while (1) &#123;</span><br><span class="line">        nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">        if (nread == -1) &#123;</span><br><span class="line">            perror(&quot;getdents失败&quot;);</span><br><span class="line">            close(fd);</span><br><span class="line">            exit(EXIT_FAILURE);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        if (nread == 0)  // 没有更多的目录项</span><br><span class="line">            break;</span><br><span class="line">        </span><br><span class="line">        // 解析目录项</span><br><span class="line">        for (p = buf; p &lt; buf + nread;) &#123;</span><br><span class="line">            d = (struct linux_dirent *)p;</span><br><span class="line">            </span><br><span class="line">            // 显示目录项信息</span><br><span class="line">            printf(&quot;  inode: %ld, &quot;, d-&gt;d_ino);</span><br><span class="line">            printf(&quot;长度: %d, &quot;, d-&gt;d_reclen);</span><br><span class="line">            printf(&quot;名称: %s\n&quot;, d-&gt;d_name);</span><br><span class="line">            </span><br><span class="line">            p += d-&gt;d_reclen;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    close(fd);</span><br><span class="line">    </span><br><span class="line">    // 示例2: 创建测试目录和文件进行演示</span><br><span class="line">    printf(&quot;\n示例2: 创建测试环境进行演示\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 创建测试目录</span><br><span class="line">    if (mkdir(&quot;test_getdents_dir&quot;, 0755) == -1 &amp;&amp; errno != EEXIST) &#123;</span><br><span class="line">        perror(&quot;创建测试目录失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;创建测试目录: test_getdents_dir\n&quot;);</span><br><span class="line">        </span><br><span class="line">        // 在测试目录中创建一些文件</span><br><span class="line">        chdir(&quot;test_getdents_dir&quot;);</span><br><span class="line">        </span><br><span class="line">        // 创建测试文件</span><br><span class="line">        int test_files&amp;#91;] = &#123;1, 2, 3, 4, 5&#125;;</span><br><span class="line">        for (int i = 0; i &lt; 5; i++) &#123;</span><br><span class="line">            char filename&amp;#91;20];</span><br><span class="line">            sprintf(filename, &quot;test_file_%d.txt&quot;, test_files&amp;#91;i]);</span><br><span class="line">            int file_fd = open(filename, O_CREAT | O_WRONLY, 0644);</span><br><span class="line">            if (file_fd != -1) &#123;</span><br><span class="line">                const char *content = &quot;Test file content&quot;;</span><br><span class="line">                write(file_fd, content, strlen(content));</span><br><span class="line">                close(file_fd);</span><br><span class="line">                printf(&quot;创建测试文件: %s\n&quot;, filename);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 创建子目录</span><br><span class="line">        if (mkdir(&quot;subdir&quot;, 0755) == -1 &amp;&amp; errno != EEXIST) &#123;</span><br><span class="line">            perror(&quot;创建子目录失败&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;创建子目录: subdir\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 打开测试目录</span><br><span class="line">        fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">        if (fd != -1) &#123;</span><br><span class="line">            printf(&quot;\n读取测试目录内容:\n&quot;);</span><br><span class="line">            </span><br><span class="line">            while (1) &#123;</span><br><span class="line">                nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">                if (nread == -1) &#123;</span><br><span class="line">                    perror(&quot;getdents失败&quot;);</span><br><span class="line">                    break;</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                if (nread == 0)</span><br><span class="line">                    break;</span><br><span class="line">                </span><br><span class="line">                // 解析并显示目录项</span><br><span class="line">                for (p = buf; p &lt; buf + nread;) &#123;</span><br><span class="line">                    d = (struct linux_dirent *)p;</span><br><span class="line">                    </span><br><span class="line">                    // 跳过.和..目录项</span><br><span class="line">                    if (strcmp(d-&gt;d_name, &quot;.&quot;) != 0 &amp;&amp; strcmp(d-&gt;d_name, &quot;..&quot;) != 0) &#123;</span><br><span class="line">                        printf(&quot;  文件名: %-20s&quot;, d-&gt;d_name);</span><br><span class="line">                        printf(&quot;inode: %ld, &quot;, d-&gt;d_ino);</span><br><span class="line">                        printf(&quot;长度: %d\n&quot;, d-&gt;d_reclen);</span><br><span class="line">                    &#125;</span><br><span class="line">                    </span><br><span class="line">                    p += d-&gt;d_reclen;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            close(fd);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 返回上级目录并清理</span><br><span class="line">        chdir(&quot;..&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 示例3: 与readdir的对比</span><br><span class="line">    printf(&quot;\n示例3: getdents与readdir对比\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 使用getdents读取</span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd != -1) &#123;</span><br><span class="line">        printf(&quot;使用getdents读取目录:\n&quot;);</span><br><span class="line">        nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">        if (nread &gt; 0) &#123;</span><br><span class="line">            int count = 0;</span><br><span class="line">            for (p = buf; p &lt; buf + nread &amp;&amp; count &lt; 5;) &#123;</span><br><span class="line">                d = (struct linux_dirent *)p;</span><br><span class="line">                if (strcmp(d-&gt;d_name, &quot;.&quot;) != 0 &amp;&amp; strcmp(d-&gt;d_name, &quot;..&quot;) != 0) &#123;</span><br><span class="line">                    printf(&quot;  %s\n&quot;, d-&gt;d_name);</span><br><span class="line">                    count++;</span><br><span class="line">                &#125;</span><br><span class="line">                p += d-&gt;d_reclen;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 使用readdir读取（标准方法）</span><br><span class="line">    printf(&quot;使用readdir读取目录:\n&quot;);</span><br><span class="line">    DIR *dir = opendir(&quot;.&quot;);</span><br><span class="line">    if (dir != NULL) &#123;</span><br><span class="line">        struct dirent *entry;</span><br><span class="line">        int count = 0;</span><br><span class="line">        while ((entry = readdir(dir)) != NULL &amp;&amp; count &lt; 5) &#123;</span><br><span class="line">            if (strcmp(entry-&gt;d_name, &quot;.&quot;) != 0 &amp;&amp; strcmp(entry-&gt;d_name, &quot;..&quot;) != 0) &#123;</span><br><span class="line">                printf(&quot;  %s\n&quot;, entry-&gt;d_name);</span><br><span class="line">                count++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        closedir(dir);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;getdents提供更多底层控制，但readdir更易使用\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 示例4: 目录项详细信息解析</span><br><span class="line">    printf(&quot;\n示例4: 目录项详细信息解析\n&quot;);</span><br><span class="line">    </span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd != -1) &#123;</span><br><span class="line">        nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">        if (nread &gt; 0) &#123;</span><br><span class="line">            printf(&quot;目录项详细信息:\n&quot;);</span><br><span class="line">            for (p = buf; p &lt; buf + nread;) &#123;</span><br><span class="line">                d = (struct linux_dirent *)p;</span><br><span class="line">                </span><br><span class="line">                // 显示所有目录项（包括.和..）</span><br><span class="line">                printf(&quot;  名称: %-20s&quot;, d-&gt;d_name);</span><br><span class="line">                printf(&quot;inode: %-10ld&quot;, d-&gt;d_ino);</span><br><span class="line">                printf(&quot;偏移: %-8ld&quot;, (long)d-&gt;d_off);</span><br><span class="line">                printf(&quot;长度: %d\n&quot;, d-&gt;d_reclen);</span><br><span class="line">                </span><br><span class="line">                p += d-&gt;d_reclen;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 示例5: 错误处理演示</span><br><span class="line">    printf(&quot;\n示例5: 错误处理演示\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 尝试对无效文件描述符操作</span><br><span class="line">    nread = syscall(SYS_getdents, 999, buf, sizeof(buf));</span><br><span class="line">    if (nread == -1) &#123;</span><br><span class="line">        printf(&quot;对无效文件描述符操作: %s\n&quot;, strerror(errno));</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 尝试对普通文件操作</span><br><span class="line">    int regular_fd = open(&quot;regular_file.txt&quot;, O_CREAT | O_WRONLY, 0644);</span><br><span class="line">    if (regular_fd != -1) &#123;</span><br><span class="line">        write(regular_fd, &quot;test&quot;, 4);</span><br><span class="line">        nread = syscall(SYS_getdents, regular_fd, buf, sizeof(buf));</span><br><span class="line">        if (nread == -1) &#123;</span><br><span class="line">            printf(&quot;对普通文件操作: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">        close(regular_fd);</span><br><span class="line">        unlink(&quot;regular_file.txt&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 尝试使用无效缓冲区</span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd != -1) &#123;</span><br><span class="line">        nread = syscall(SYS_getdents, fd, NULL, sizeof(buf));</span><br><span class="line">        if (nread == -1) &#123;</span><br><span class="line">            printf(&quot;使用无效缓冲区: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 示例6: 实际应用场景</span><br><span class="line">    printf(&quot;\n示例6: 实际应用场景\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 场景1: 快速目录扫描（跳过隐藏文件）</span><br><span class="line">    printf(&quot;场景1: 快速目录扫描\n&quot;);</span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd != -1) &#123;</span><br><span class="line">        printf(&quot;非隐藏文件列表:\n&quot;);</span><br><span class="line">        int file_count = 0;</span><br><span class="line">        while (1) &#123;</span><br><span class="line">            nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">            if (nread &lt;= 0) break;</span><br><span class="line">            </span><br><span class="line">            for (p = buf; p &lt; buf + nread;) &#123;</span><br><span class="line">                d = (struct linux_dirent *)p;</span><br><span class="line">                </span><br><span class="line">                // 跳过.和..以及隐藏文件（以.开头）</span><br><span class="line">                if (strcmp(d-&gt;d_name, &quot;.&quot;) != 0 &amp;&amp; </span><br><span class="line">                    strcmp(d-&gt;d_name, &quot;..&quot;) != 0 &amp;&amp; </span><br><span class="line">                    d-&gt;d_name&amp;#91;0] != &#x27;.&#x27;) &#123;</span><br><span class="line">                    printf(&quot;  %s\n&quot;, d-&gt;d_name);</span><br><span class="line">                    file_count++;</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                p += d-&gt;d_reclen;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;总共找到 %d 个非隐藏文件\n&quot;, file_count);</span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 场景2: 目录统计信息</span><br><span class="line">    printf(&quot;场景2: 目录统计信息\n&quot;);</span><br><span class="line">    fd = open(&quot;.&quot;, O_RDONLY | O_DIRECTORY);</span><br><span class="line">    if (fd != -1) &#123;</span><br><span class="line">        int total_files = 0;</span><br><span class="line">        int total_dirs = 0;</span><br><span class="line">        long long total_size = 0;</span><br><span class="line">        </span><br><span class="line">        while (1) &#123;</span><br><span class="line">            nread = syscall(SYS_getdents, fd, buf, sizeof(buf));</span><br><span class="line">            if (nread &lt;= 0) break;</span><br><span class="line">            </span><br><span class="line">            for (p = buf; p &lt; buf + nread;) &#123;</span><br><span class="line">                d = (struct linux_dirent *)p;</span><br><span class="line">                </span><br><span class="line">                // 跳过.和..</span><br><span class="line">                if (strcmp(d-&gt;d_name, &quot;.&quot;) != 0 &amp;&amp; strcmp(d-&gt;d_name, &quot;..&quot;) != 0) &#123;</span><br><span class="line">                    // 检查文件类型（需要stat）</span><br><span class="line">                    struct stat st;</span><br><span class="line">                    if (stat(d-&gt;d_name, &amp;st) == 0) &#123;</span><br><span class="line">                        if (S_ISDIR(st.st_mode)) &#123;</span><br><span class="line">                            total_dirs++;</span><br><span class="line">                        &#125; else &#123;</span><br><span class="line">                            total_files++;</span><br><span class="line">                            total_size += st.st_size;</span><br><span class="line">                        &#125;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">                </span><br><span class="line">                p += d-&gt;d_reclen;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        printf(&quot;目录统计:\n&quot;);</span><br><span class="line">        printf(&quot;  文件数: %d\n&quot;, total_files);</span><br><span class="line">        printf(&quot;  目录数: %d\n&quot;, total_dirs);</span><br><span class="line">        printf(&quot;  文件总大小: %lld 字节\n&quot;, total_size);</span><br><span class="line">        </span><br><span class="line">        close(fd);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 清理测试目录</span><br><span class="line">    printf(&quot;\n清理测试资源...\n&quot;);</span><br><span class="line">    if (access(&quot;test_getdents_dir&quot;, F_OK) == 0) &#123;</span><br><span class="line">        // 删除测试目录中的文件</span><br><span class="line">        chdir(&quot;test_getdents_dir&quot;);</span><br><span class="line">        for (int i = 1; i &lt;= 5; i++) &#123;</span><br><span class="line">            char filename&amp;#91;20];</span><br><span class="line">            sprintf(filename, &quot;test_file_%d.txt&quot;, i);</span><br><span class="line">            unlink(filename);</span><br><span class="line">        &#125;</span><br><span class="line">        rmdir(&quot;subdir&quot;);</span><br><span class="line">        chdir(&quot;..&quot;);</span><br><span class="line">        rmdir(&quot;test_getdents_dir&quot;);</span><br><span class="line">        printf(&quot;删除测试目录完成\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p><a href="https://www.calcguide.tech/2025/09/09/getdents-syscall-demo/">https://www.calcguide.tech/2025/09/09/getdents-syscall-demo/</a></p><p>getdents64系统调用及示例</p><p>getdents系统调用及示例</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getdents-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getdents-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getdents - 获取目录项</p>
<h3 id="函数介绍"><a href="#函数介绍" class="headerlink" title="函数介绍"></a>函数介绍</h3><p>getdents系统调用用于读取目录文件的内容，获取目录中的文件项信息。它返]]>
    </summary>
    <title>getdents系统调用及示例</title>
    <updated>2026-06-15T07:56:28.169Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getegid - 获取当前进程的有效组ID</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getegid 是一个 Linux 系统调用，用于获取当前进程的有效组 ID（Effective Group ID）。有效组 ID 决定了进程当前对文件和资源的组级访问权限。</p><p>在 Unix&#x2F;Linux 系统中，每个进程都有多个相关的用户和组 ID：</p><ul><li><p>真实 ID (Real ID)：标识运行该进程的实际用户&#x2F;组</p></li><li><p>有效 ID (Effective ID)：决定当前权限的用户&#x2F;组 ID</p></li><li><p>保存的设置 ID (Saved Set ID)：用于权限切换的备份 ID</p></li></ul><p>getegid 专门用于获取有效组 ID，这是进程当前用于权限检查的组标识符。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">gid_t getegid(void);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><p>返回当前进程的有效组 ID（Effective Group ID）。这是一个只读操作，不会修改任何系统状态。</p><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><ul><li>无参数</li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>返回当前进程的有效组 ID（gid_t 类型）</p></li><li><p>不会失败，总是成功返回</p></li></ul><h3 id="6-相似函数，或关联函数"><a href="#6-相似函数，或关联函数" class="headerlink" title="6. 相似函数，或关联函数"></a>6. 相似函数，或关联函数</h3><ul><li><p>getgid(): 获取真实组 ID（Real Group ID）</p></li><li><p>geteuid(): 获取有效用户 ID（Effective User ID）</p></li><li><p>getuid(): 获取真实用户 ID（Real User ID）</p></li><li><p>setgid(): 设置组 ID</p></li><li><p>setegid(): 设置有效组 ID</p></li><li><p>setregid(): 同时设置真实和有效组 ID</p></li><li><p>setgroups(): 设置补充组列表</p></li><li><p>getgroups(): 获取补充组列表</p></li><li><p>initgroups(): 初始化用户组访问列表</p></li></ul><h3 id="7-示例代码"><a href="#7-示例代码" class="headerlink" title="7. 示例代码"></a>7. 示例代码</h3><h4 id="示例1：基本使用-获取和显示组ID信息"><a href="#示例1：基本使用-获取和显示组ID信息" class="headerlink" title="示例1：基本使用 - 获取和显示组ID信息"></a>示例1：基本使用 - 获取和显示组ID信息</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line"></span><br><span class="line">void print_group_info(const char *label, gid_t gid) &#123;</span><br><span class="line">    struct group *grp;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;%s: %d&quot;, label, gid);</span><br><span class="line">    </span><br><span class="line">    // 尝试获取组名</span><br><span class="line">    grp = getgrgid(gid);</span><br><span class="line">    if (grp != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    gid_t real_gid, effective_gid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程组 ID 信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取真实组 ID</span><br><span class="line">    real_gid = getgid();</span><br><span class="line">    print_group_info(&quot;真实组 ID&quot;, real_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取有效组 ID</span><br><span class="line">    effective_gid = getegid();</span><br><span class="line">    print_group_info(&quot;有效组 ID&quot;, effective_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取当前用户名</span><br><span class="line">    struct passwd *pwd = getpwuid(getuid());</span><br><span class="line">    if (pwd != NULL) &#123;</span><br><span class="line">        printf(&quot;当前用户: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否为 root 组</span><br><span class="line">    if (effective_gid == 0) &#123;</span><br><span class="line">        printf(&quot;注意: 当前进程具有 root 组权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：权限检查和组切换演示"><a href="#示例2：权限检查和组切换演示" class="headerlink" title="示例2：权限检查和组切换演示"></a>示例2：权限检查和组切换演示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    gid_t original_egid, current_egid;</span><br><span class="line">    int ret;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 组 ID 切换演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 保存原始有效组 ID</span><br><span class="line">    original_egid = getegid();</span><br><span class="line">    printf(&quot;原始有效组 ID: %d\n&quot;, original_egid);</span><br><span class="line">    </span><br><span class="line">    // 尝试切换到不同的组（需要适当权限）</span><br><span class="line">    // 这里使用一些常见的系统组进行演示</span><br><span class="line">    gid_t test_groups&amp;#91;] = &#123;1000, 1001, 1002&#125;;  // 假设的用户组</span><br><span class="line">    int num_groups = sizeof(test_groups) / sizeof(test_groups&amp;#91;0]);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; num_groups; i++) &#123;</span><br><span class="line">        printf(&quot;\n尝试切换到组 %d:\n&quot;, test_groups&amp;#91;i]);</span><br><span class="line">        </span><br><span class="line">        // 尝试设置有效组 ID</span><br><span class="line">        ret = setegid(test_groups&amp;#91;i]);</span><br><span class="line">        if (ret == -1) &#123;</span><br><span class="line">            printf(&quot;  切换失败: %s\n&quot;, strerror(errno));</span><br><span class="line">            switch (errno) &#123;</span><br><span class="line">                case EPERM:</span><br><span class="line">                    printf(&quot;  原因: 权限不足\n&quot;);</span><br><span class="line">                    break;</span><br><span class="line">                case EINVAL:</span><br><span class="line">                    printf(&quot;  原因: 无效的组 ID\n&quot;);</span><br><span class="line">                    break;</span><br><span class="line">                default:</span><br><span class="line">                    break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            current_egid = getegid();</span><br><span class="line">            printf(&quot;  切换成功，当前有效组 ID: %d\n&quot;, current_egid);</span><br><span class="line">            </span><br><span class="line">            // 切换回原始组 ID</span><br><span class="line">            if (setegid(original_egid) == 0) &#123;</span><br><span class="line">                printf(&quot;  已切换回原始组 ID: %d\n&quot;, getegid());</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n最终有效组 ID: %d\n&quot;, getegid());</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：补充组信息获取"><a href="#示例3：补充组信息获取" class="headerlink" title="示例3：补充组信息获取"></a>示例3：补充组信息获取</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    gid_t effective_gid;</span><br><span class="line">    gid_t *group_list;</span><br><span class="line">    int group_count;</span><br><span class="line">    long max_groups;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 完整组信息展示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取有效组 ID</span><br><span class="line">    effective_gid = getegid();</span><br><span class="line">    printf(&quot;有效组 ID: %d\n&quot;, effective_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取组名</span><br><span class="line">    struct group *grp = getgrgid(effective_gid);</span><br><span class="line">    if (grp != NULL) &#123;</span><br><span class="line">        printf(&quot;有效组名: %s\n&quot;, grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取补充组列表大小</span><br><span class="line">    max_groups = sysconf(_SC_NGROUPS_MAX);</span><br><span class="line">    if (max_groups == -1) &#123;</span><br><span class="line">        max_groups = 64;  // 默认值</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;最大支持组数: %ld\n&quot;, max_groups);</span><br><span class="line">    </span><br><span class="line">    // 分配组列表内存</span><br><span class="line">    group_list = malloc(max_groups * sizeof(gid_t));</span><br><span class="line">    if (group_list == NULL) &#123;</span><br><span class="line">        perror(&quot;内存分配失败&quot;);</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取补充组列表</span><br><span class="line">    group_count = getgroups(max_groups, group_list);</span><br><span class="line">    if (group_count == -1) &#123;</span><br><span class="line">        perror(&quot;获取补充组列表失败&quot;);</span><br><span class="line">        free(group_list);</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;补充组数量: %d\n&quot;, group_count);</span><br><span class="line">    </span><br><span class="line">    if (group_count &gt; 0) &#123;</span><br><span class="line">        printf(&quot;补充组列表:\n&quot;);</span><br><span class="line">        for (int i = 0; i &lt; group_count; i++) &#123;</span><br><span class="line">            printf(&quot;  组 %d: %d&quot;, i + 1, group_list&amp;#91;i]);</span><br><span class="line">            </span><br><span class="line">            // 获取组名</span><br><span class="line">            struct group *sup_grp = getgrgid(group_list&amp;#91;i]);</span><br><span class="line">            if (sup_grp != NULL) &#123;</span><br><span class="line">                printf(&quot; (%s)&quot;, sup_grp-&gt;gr_name);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查有效组 ID 是否在补充组列表中</span><br><span class="line">    int found = 0;</span><br><span class="line">    for (int i = 0; i &lt; group_count; i++) &#123;</span><br><span class="line">        if (group_list&amp;#91;i] == effective_gid) &#123;</span><br><span class="line">            found = 1;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n有效组 ID %s 在补充组列表中\n&quot;, </span><br><span class="line">           found ? &quot;存在&quot; : &quot;不存在&quot;);</span><br><span class="line">    </span><br><span class="line">    free(group_list);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：权限相关的实际应用"><a href="#示例4：权限相关的实际应用" class="headerlink" title="示例4：权限相关的实际应用"></a>示例4：权限相关的实际应用</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 检查当前进程是否属于指定组</span><br><span class="line">int is_member_of_group(gid_t target_gid) &#123;</span><br><span class="line">    gid_t effective_gid = getegid();</span><br><span class="line">    </span><br><span class="line">    // 首先检查有效组 ID</span><br><span class="line">    if (effective_gid == target_gid) &#123;</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查补充组</span><br><span class="line">    long max_groups = sysconf(_SC_NGROUPS_MAX);</span><br><span class="line">    if (max_groups == -1) max_groups = 64;</span><br><span class="line">    </span><br><span class="line">    gid_t *groups = malloc(max_groups * sizeof(gid_t));</span><br><span class="line">    if (groups == NULL) return 0;</span><br><span class="line">    </span><br><span class="line">    int ngroups = getgroups(max_groups, groups);</span><br><span class="line">    if (ngroups == -1) &#123;</span><br><span class="line">        free(groups);</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; ngroups; i++) &#123;</span><br><span class="line">        if (groups&amp;#91;i] == target_gid) &#123;</span><br><span class="line">            free(groups);</span><br><span class="line">            return 1;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    free(groups);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 获取当前用户的主要组信息</span><br><span class="line">void print_user_primary_group() &#123;</span><br><span class="line">    uid_t uid = getuid();</span><br><span class="line">    struct passwd *pwd = getpwuid(uid);</span><br><span class="line">    </span><br><span class="line">    if (pwd != NULL) &#123;</span><br><span class="line">        printf(&quot;用户 %s 的主要组: %d&quot;, pwd-&gt;pw_name, pwd-&gt;pw_gid);</span><br><span class="line">        struct group *grp = getgrgid(pwd-&gt;pw_gid);</span><br><span class="line">        if (grp != NULL) &#123;</span><br><span class="line">            printf(&quot; (%s)&quot;, grp-&gt;gr_name);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 权限检查应用示例 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示基本信息</span><br><span class="line">    printf(&quot;当前用户 ID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;当前有效组 ID: %d\n&quot;, getegid());</span><br><span class="line">    print_user_primary_group();</span><br><span class="line">    </span><br><span class="line">    // 检查是否属于 wheel 组（系统管理员组）</span><br><span class="line">    struct group *wheel_grp = getgrnam(&quot;wheel&quot;);</span><br><span class="line">    if (wheel_grp != NULL) &#123;</span><br><span class="line">        int is_wheel = is_member_of_group(wheel_grp-&gt;gr_gid);</span><br><span class="line">        printf(&quot;是否属于 wheel 组: %s\n&quot;, is_wheel ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否属于 sudo 组</span><br><span class="line">    struct group *sudo_grp = getgrnam(&quot;sudo&quot;);</span><br><span class="line">    if (sudo_grp != NULL) &#123;</span><br><span class="line">        int is_sudo = is_member_of_group(sudo_grp-&gt;gr_gid);</span><br><span class="line">        printf(&quot;是否属于 sudo 组: %s\n&quot;, is_sudo ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否具有 root 组权限</span><br><span class="line">    int is_root_group = is_member_of_group(0);</span><br><span class="line">    printf(&quot;是否具有 root 组权限: %s\n&quot;, is_root_group ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    </span><br><span class="line">    // 根据组权限显示不同信息</span><br><span class="line">    if (is_root_group) &#123;</span><br><span class="line">        printf(&quot;\n提示: 当前进程具有 root 组权限，可以执行特权操作\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;\n提示: 当前进程权限受限，某些操作可能需要提升权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="8-组-ID-类型说明"><a href="#8-组-ID-类型说明" class="headerlink" title="8. 组 ID 类型说明"></a>8. 组 ID 类型说明</h3><p>Unix&#x2F;Linux 系统中的组 ID 类型：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">// 真实组 ID (Real Group ID)</span><br><span class="line">// 标识启动进程的用户的组</span><br><span class="line">gid_t real_gid = getgid();</span><br><span class="line"></span><br><span class="line">// 有效组 ID (Effective Group ID)  </span><br><span class="line">// 当前用于权限检查的组 ID</span><br><span class="line">gid_t effective_gid = getegid();</span><br><span class="line"></span><br><span class="line">// 保存的设置组 ID (Saved Set Group ID)</span><br><span class="line">// 用于权限切换的备份 ID</span><br><span class="line">// 通过 setregid() 或类似函数设置</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-常见组-ID-值"><a href="#9-常见组-ID-值" class="headerlink" title="9. 常见组 ID 值"></a>9. 常见组 ID 值</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">// 特殊组 ID</span><br><span class="line">0     // root 组 (超级用户组)</span><br><span class="line">1     // bin 组 (系统二进制文件)</span><br><span class="line">2     // daemon 组 (系统守护进程)</span><br><span class="line">3     // sys 组 (系统文件)</span><br><span class="line">4     // adm 组 (系统日志)</span><br><span class="line">5     // tty 组 (终端设备)</span><br><span class="line">6     // disk 组 (磁盘设备)</span><br><span class="line">10    // wheel 组 (系统管理员，某些发行版)</span><br><span class="line">100+  // 普通用户组</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-实际应用场景"><a href="#10-实际应用场景" class="headerlink" title="10. 实际应用场景"></a>10. 实际应用场景</h3><p>getegid 在以下场景中非常有用：</p><h4 id="场景1：权限检查"><a href="#场景1：权限检查" class="headerlink" title="场景1：权限检查"></a>场景1：权限检查</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">int check_file_access_permission(const char *filename) &#123;</span><br><span class="line">    gid_t effective_gid = getegid();</span><br><span class="line">    // 根据有效组 ID 检查文件访问权限</span><br><span class="line">    // ...</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：安全审计"><a href="#场景2：安全审计" class="headerlink" title="场景2：安全审计"></a>场景2：安全审计</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">void audit_process_privileges() &#123;</span><br><span class="line">    gid_t egid = getegid();</span><br><span class="line">    if (egid == 0) &#123;</span><br><span class="line">        syslog(LOG_WARNING, &quot;进程以 root 组权限运行&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：组权限相关的功能控制"><a href="#场景3：组权限相关的功能控制" class="headerlink" title="场景3：组权限相关的功能控制"></a>场景3：组权限相关的功能控制</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">int can_perform_admin_task() &#123;</span><br><span class="line">    return is_member_of_group(get_admin_group_id());</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="11-与相关函数的配合使用"><a href="#11-与相关函数的配合使用" class="headerlink" title="11. 与相关函数的配合使用"></a>11. 与相关函数的配合使用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">// 完整的 ID 管理示例</span><br><span class="line">void demonstrate_id_management() &#123;</span><br><span class="line">    printf(&quot;真实用户 ID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;有效用户 ID: %d\n&quot;, geteuid());</span><br><span class="line">    printf(&quot;真实组 ID: %d\n&quot;, getgid());</span><br><span class="line">    printf(&quot;有效组 ID: %d\n&quot;, getegid());</span><br><span class="line">    </span><br><span class="line">    // 权限切换示例</span><br><span class="line">    // seteuid(), setegid() 用于临时权限切换</span><br><span class="line">    // setuid(), setgid() 用于永久权限切换</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getegid 是一个简单但重要的系统调用，用于获取当前进程的有效组 ID。关键要点：</p><p>总是成功: 不会失败，总是返回有效组 ID</p><p>权限检查: 有效组 ID 决定当前的组级权限</p><p>安全相关: 是权限管理和安全检查的基础</p><p>配合使用: 通常与 getgroups() 等函数配合使用</p><p>实际应用: 广泛用于权限验证、安全审计等场景</p><p>在编写需要进行权限检查的程序时，getegid 是必不可少的工具函数，它为程序提供了当前权限状态的重要信息。</p><p>getegid系统调用及示例-CSDN博客</p><p><a href="https://www.calcguide.tech/2025/09/09/getegid-syscall-demo/">https://www.calcguide.tech/2025/09/09/getegid-syscall-demo/</a></p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getegid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getegid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getegid - 获取当前进程的有效组ID</p>
<h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getegid 是一个 Linux 系统调用]]>
    </summary>
    <title>getegid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.169Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="geteuid-函数详解"><a href="#geteuid-函数详解" class="headerlink" title="geteuid 函数详解"></a>geteuid 函数详解</h1><ol><li>函数介绍</li></ol><p>geteuid 是 Linux 系统中用于获取进程有效用户 ID（Effective User ID）的系统调用。可以把有效用户 ID 想象成”进程当前正在使用的身份证明”——它决定了进程当前拥有的权限级别。</p><p>在 Linux 系统中，每个进程都有两个重要的用户 ID：</p><ul><li><p>真实用户 ID（real UID）: 进程实际所属的用户</p></li><li><p>有效用户 ID（effective UID）: 进程当前使用的用户身份（用于权限检查）</p></li></ul><p>这就像是一个人有真实身份和当前扮演的角色。比如一个系统管理员（真实身份）可能暂时切换到普通用户角色（有效身份）来执行某些操作。</p><p>geteuid 就是获取进程当前”扮演的角色”的用户 ID。</p><ol start="2"><li>函数原型</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">uid_t geteuid(void);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>功能</li></ol><p>geteuid 函数用于获取调用进程的有效用户 ID（effective user ID）。有效用户 ID 用于权限检查，决定了进程可以访问哪些资源和执行哪些操作。</p><ol start="4"><li>参数</li></ol><p>geteuid 函数不需要任何参数。</p><ol start="5"><li>返回值</li></ol><ul><li><p>成功: 返回调用进程的有效用户 ID（uid_t 类型）</p></li><li><p>注意: 此函数不会失败，总是成功返回</p></li></ul><ol start="6"><li>相关函数</li></ol><ul><li><p>getuid: 获取真实用户 ID（real user ID）</p></li><li><p>getgid: 获取真实组 ID（real group ID）</p></li><li><p>getegid: 获取有效组 ID（effective group ID）</p></li><li><p>setuid: 设置用户 ID</p></li><li><p>seteuid: 设置有效用户 ID</p></li><li><p>setreuid: 同时设置真实和有效用户 ID</p></li></ul><ol start="7"><li>用户 ID 类型说明</li></ol><p>Linux 系统中有几种不同的用户 ID：</p><p>用户 ID 类型说明真实用户 ID (real UID)进程实际所属的用户，由 getuid 返回有效用户 ID (effective UID)用于权限检查的用户 ID，由 geteuid 返回保存的设置用户 ID (saved set-user-ID)保存的用户 ID，用于权限切换</p><ol start="8"><li>示例代码</li></ol><h3 id="示例1：基础用法-获取进程用户-ID"><a href="#示例1：基础用法-获取进程用户-ID" class="headerlink" title="示例1：基础用法 - 获取进程用户 ID"></a>示例1：基础用法 - 获取进程用户 ID</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    uid_t real_uid, effective_uid;</span><br><span class="line">    struct passwd *pwd_info;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程用户 ID 信息 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取真实用户 ID</span><br><span class="line">    real_uid = getuid();</span><br><span class="line">    printf(&quot;真实用户 ID (real UID): %d\n&quot;, real_uid);</span><br><span class="line">    </span><br><span class="line">    // 获取有效用户 ID</span><br><span class="line">    effective_uid = geteuid();</span><br><span class="line">    printf(&quot;有效用户 ID (effective UID): %d\n&quot;, effective_uid);</span><br><span class="line">    </span><br><span class="line">    // 获取用户名信息</span><br><span class="line">    pwd_info = getpwuid(real_uid);</span><br><span class="line">    if (pwd_info != NULL) &#123;</span><br><span class="line">        printf(&quot;真实用户名: %s\n&quot;, pwd_info-&gt;pw_name);</span><br><span class="line">        printf(&quot;主目录: %s\n&quot;, pwd_info-&gt;pw_dir);</span><br><span class="line">        printf(&quot;登录 shell: %s\n&quot;, pwd_info-&gt;pw_shell);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;无法获取真实用户信息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取有效用户信息</span><br><span class="line">    pwd_info = getpwuid(effective_uid);</span><br><span class="line">    if (pwd_info != NULL) &#123;</span><br><span class="line">        printf(&quot;有效用户名: %s\n&quot;, pwd_info-&gt;pw_name);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;无法获取有效用户信息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 判断权限级别</span><br><span class="line">    printf(&quot;\n权限状态:\n&quot;);</span><br><span class="line">    if (effective_uid == 0) &#123;</span><br><span class="line">        printf(&quot;✓ 进程具有 root 权限\n&quot;);</span><br><span class="line">    &#125; else if (real_uid == 0 &amp;&amp; effective_uid != 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 进程已放弃 root 权限\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;✗ 进程为普通用户权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (real_uid == effective_uid) &#123;</span><br><span class="line">        printf(&quot;✓ 真实 UID 和有效 UID 相同\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;⚠ 真实 UID 和有效 UID 不同\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例2：权限检查和安全验证"><a href="#示例2：权限检查和安全验证" class="headerlink" title="示例2：权限检查和安全验证"></a>示例2：权限检查和安全验证</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 权限检查函数</span><br><span class="line">void check_permissions() &#123;</span><br><span class="line">    uid_t real_uid = getuid();</span><br><span class="line">    uid_t effective_uid = geteuid();</span><br><span class="line">    gid_t real_gid = getgid();</span><br><span class="line">    gid_t effective_gid = getegid();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 权限检查 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 用户权限检查</span><br><span class="line">    printf(&quot;用户权限:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 UID: %d&quot;, real_uid);</span><br><span class="line">    struct passwd *pwd = getpwuid(real_uid);</span><br><span class="line">    if (pwd) printf(&quot; (%s)&quot;, pwd-&gt;pw_name);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;  有效 UID: %d&quot;, effective_uid);</span><br><span class="line">    pwd = getpwuid(effective_uid);</span><br><span class="line">    if (pwd) printf(&quot; (%s)&quot;, pwd-&gt;pw_name);</span><br><span class="line">    if (effective_uid == 0) &#123;</span><br><span class="line">        printf(&quot; &amp;#91;ROOT 权限!]&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 组权限检查</span><br><span class="line">    printf(&quot;组权限:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 GID: %d\n&quot;, real_gid);</span><br><span class="line">    printf(&quot;  有效 GID: %d&quot;, effective_gid);</span><br><span class="line">    if (effective_gid == 0) &#123;</span><br><span class="line">        printf(&quot; &amp;#91;ROOT 组权限!]&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 安全状态分析</span><br><span class="line">    printf(&quot;\n安全状态分析:\n&quot;);</span><br><span class="line">    if (effective_uid == 0) &#123;</span><br><span class="line">        printf(&quot;  ⚠ 危险: 进程以 root 权限运行\n&quot;);</span><br><span class="line">        printf(&quot;  建议: 在完成特权操作后立即降低权限\n&quot;);</span><br><span class="line">    &#125; else if (real_uid == 0 &amp;&amp; effective_uid != 0) &#123;</span><br><span class="line">        printf(&quot;  ✓ 良好: 已安全放弃 root 权限\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  ✓ 正常: 以普通用户权限运行\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 安全操作示例</span><br><span class="line">void secure_operation_example() &#123;</span><br><span class="line">    uid_t real_uid = getuid();</span><br><span class="line">    uid_t effective_uid = geteuid();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 安全操作示例 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (effective_uid == 0) &#123;</span><br><span class="line">        printf(&quot;检测到 root 权限，执行特权操作...\n&quot;);</span><br><span class="line">        </span><br><span class="line">        // 模拟特权操作</span><br><span class="line">        printf(&quot;  执行系统管理任务...\n&quot;);</span><br><span class="line">        printf(&quot;  修改系统配置...\n&quot;);</span><br><span class="line">        printf(&quot;  访问受保护资源...\n&quot;);</span><br><span class="line">        </span><br><span class="line">        // 如果真实 UID 不是 root，可以安全地放弃权限</span><br><span class="line">        if (real_uid != 0) &#123;</span><br><span class="line">            printf(&quot;  准备放弃 root 权限...\n&quot;);</span><br><span class="line">            // 注意：实际代码中需要使用 setuid() 系列函数</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;以普通用户权限执行操作...\n&quot;);</span><br><span class="line">        printf(&quot;  执行用户级任务...\n&quot;);</span><br><span class="line">        printf(&quot;  访问用户文件...\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 进程身份和权限管理系统 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示基本进程信息</span><br><span class="line">    printf(&quot;进程基本信息:\n&quot;);</span><br><span class="line">    printf(&quot;  进程 ID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;  真实 UID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;  有效 UID: %d\n&quot;, geteuid());</span><br><span class="line">    printf(&quot;  真实 GID: %d\n&quot;, getgid());</span><br><span class="line">    printf(&quot;  有效 GID: %d\n\n&quot;, getegid());</span><br><span class="line">    </span><br><span class="line">    // 权限检查</span><br><span class="line">    check_permissions();</span><br><span class="line">    </span><br><span class="line">    // 安全操作示例</span><br><span class="line">    secure_operation_example();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 安全建议 ===\n&quot;);</span><br><span class="line">    printf(&quot;1. 遵循最小权限原则\n&quot;);</span><br><span class="line">    printf(&quot;2. 及时放弃不需要的特权\n&quot;);</span><br><span class="line">    printf(&quot;3. 定期检查有效 UID 和真实 UID\n&quot;);</span><br><span class="line">    printf(&quot;4. 避免长时间以 root 权限运行\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例3：完整的身份验证和权限管理系统"><a href="#示例3：完整的身份验证和权限管理系统" class="headerlink" title="示例3：完整的身份验证和权限管理系统"></a>示例3：完整的身份验证和权限管理系统</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 用户信息结构体</span><br><span class="line">struct user_info &#123;</span><br><span class="line">    uid_t uid;</span><br><span class="line">    gid_t gid;</span><br><span class="line">    char username&amp;#91;256];</span><br><span class="line">    char groupname&amp;#91;256];</span><br><span class="line">    char homedir&amp;#91;256];</span><br><span class="line">    int is_root;</span><br><span class="line">    int has_privileges;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 获取用户信息</span><br><span class="line">int get_user_information(struct user_info *info) &#123;</span><br><span class="line">    struct passwd *pwd;</span><br><span class="line">    struct group *grp;</span><br><span class="line">    </span><br><span class="line">    // 获取 UID 和 GID</span><br><span class="line">    info-&gt;uid = geteuid();</span><br><span class="line">    info-&gt;gid = getegid();</span><br><span class="line">    </span><br><span class="line">    // 获取用户信息</span><br><span class="line">    pwd = getpwuid(info-&gt;uid);</span><br><span class="line">    if (pwd) &#123;</span><br><span class="line">        strncpy(info-&gt;username, pwd-&gt;pw_name, sizeof(info-&gt;username) - 1);</span><br><span class="line">        info-&gt;username&amp;#91;sizeof(info-&gt;username) - 1] = &#x27;\0&#x27;;</span><br><span class="line">        strncpy(info-&gt;homedir, pwd-&gt;pw_dir, sizeof(info-&gt;homedir) - 1);</span><br><span class="line">        info-&gt;homedir&amp;#91;sizeof(info-&gt;homedir) - 1] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        snprintf(info-&gt;username, sizeof(info-&gt;username), &quot;uid_%d&quot;, info-&gt;uid);</span><br><span class="line">        strcpy(info-&gt;homedir, &quot;/tmp&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取组信息</span><br><span class="line">    grp = getgrgid(info-&gt;gid);</span><br><span class="line">    if (grp) &#123;</span><br><span class="line">        strncpy(info-&gt;groupname, grp-&gt;gr_name, sizeof(info-&gt;groupname) - 1);</span><br><span class="line">        info-&gt;groupname&amp;#91;sizeof(info-&gt;groupname) - 1] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        snprintf(info-&gt;groupname, sizeof(info-&gt;groupname), &quot;gid_%d&quot;, info-&gt;gid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 设置权限标志</span><br><span class="line">    info-&gt;is_root = (info-&gt;uid == 0);</span><br><span class="line">    info-&gt;has_privileges = (info-&gt;uid == 0 || info-&gt;gid == 0);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示用户信息</span><br><span class="line">void display_user_info(const struct user_info *info) &#123;</span><br><span class="line">    printf(&quot;=== 当前用户信息 ===\n&quot;);</span><br><span class="line">    printf(&quot;用户名: %s\n&quot;, info-&gt;username);</span><br><span class="line">    printf(&quot;用户 ID: %d\n&quot;, info-&gt;uid);</span><br><span class="line">    printf(&quot;组名: %s\n&quot;, info-&gt;groupname);</span><br><span class="line">    printf(&quot;组 ID: %d\n&quot;, info-&gt;gid);</span><br><span class="line">    printf(&quot;主目录: %s\n&quot;, info-&gt;homedir);</span><br><span class="line">    printf(&quot;权限状态: %s\n&quot;, </span><br><span class="line">           info-&gt;is_root ? &quot;ROOT 权限&quot; : </span><br><span class="line">           info-&gt;has_privileges ? &quot;特权用户&quot; : &quot;普通用户&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 权限验证函数</span><br><span class="line">int check_operation_permission(const char *operation) &#123;</span><br><span class="line">    struct user_info info;</span><br><span class="line">    get_user_information(&amp;info);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;权限检查: %s\n&quot;, operation);</span><br><span class="line">    </span><br><span class="line">    // 根据操作类型检查权限</span><br><span class="line">    if (strcmp(operation, &quot;read_system_files&quot;) == 0) &#123;</span><br><span class="line">        // 读取系统文件通常需要 root 权限</span><br><span class="line">        return info.is_root ? 1 : 0;</span><br><span class="line">    &#125; else if (strcmp(operation, &quot;write_user_files&quot;) == 0) &#123;</span><br><span class="line">        // 写入用户文件通常只需要有效权限</span><br><span class="line">        return 1;  // 假设总是允许</span><br><span class="line">    &#125; else if (strcmp(operation, &quot;network_admin&quot;) == 0) &#123;</span><br><span class="line">        // 网络管理需要 root 权限</span><br><span class="line">        return info.is_root ? 1 : 0;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        // 默认情况下，普通操作允许</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 模拟受保护操作</span><br><span class="line">void perform_protected_operation(const char *operation) &#123;</span><br><span class="line">    printf(&quot;\n--- 尝试执行操作: %s ---\n&quot;, operation);</span><br><span class="line">    </span><br><span class="line">    if (check_operation_permission(operation)) &#123;</span><br><span class="line">        printf(&quot;✓ 权限检查通过\n&quot;);</span><br><span class="line">        printf(&quot;  执行操作: %s\n&quot;, operation);</span><br><span class="line">        </span><br><span class="line">        // 模拟操作执行</span><br><span class="line">        if (strcmp(operation, &quot;read_system_files&quot;) == 0) &#123;</span><br><span class="line">            printf(&quot;  读取 /etc/shadow...\n&quot;);</span><br><span class="line">            printf(&quot;  读取系统配置文件...\n&quot;);</span><br><span class="line">        &#125; else if (strcmp(operation, &quot;network_admin&quot;) == 0) &#123;</span><br><span class="line">            printf(&quot;  配置网络接口...\n&quot;);</span><br><span class="line">            printf(&quot;  修改防火墙规则...\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        printf(&quot;  操作完成\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;✗ 权限不足，拒绝执行操作\n&quot;);</span><br><span class="line">        printf(&quot;  需要 ROOT 权限才能执行此操作\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示安全建议</span><br><span class="line">void show_security_advice(const struct user_info *info) &#123;</span><br><span class="line">    printf(&quot;\n=== 安全建议 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (info-&gt;is_root) &#123;</span><br><span class="line">        printf(&quot;⚠ 警告: 当前以 ROOT 权限运行\n&quot;);</span><br><span class="line">        printf(&quot;  建议:\n&quot;);</span><br><span class="line">        printf(&quot;  1. 完成必要操作后立即切换到普通用户\n&quot;);</span><br><span class="line">        printf(&quot;  2. 避免在 root 权限下运行不必要的程序\n&quot;);</span><br><span class="line">        printf(&quot;  3. 定期审计 root 权限的使用情况\n&quot;);</span><br><span class="line">    &#125; else if (info-&gt;has_privileges) &#123;</span><br><span class="line">        printf(&quot;⚠ 注意: 具有特权权限\n&quot;);</span><br><span class="line">        printf(&quot;  建议:\n&quot;);</span><br><span class="line">        printf(&quot;  1. 谨慎使用特权功能\n&quot;);</span><br><span class="line">        printf(&quot;  2. 遵循最小权限原则\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;✓ 信息: 以普通用户权限运行\n&quot;);</span><br><span class="line">        printf(&quot;  建议:\n&quot;);</span><br><span class="line">        printf(&quot;  1. 如需特权操作，请使用 sudo\n&quot;);</span><br><span class="line">        printf(&quot;  2. 保持系统和软件更新\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct user_info current_user;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 高级身份验证和权限管理系统 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取并显示用户信息</span><br><span class="line">    get_user_information(&amp;current_user);</span><br><span class="line">    display_user_info(&amp;current_user);</span><br><span class="line">    </span><br><span class="line">    // 执行各种受保护操作</span><br><span class="line">    perform_protected_operation(&quot;read_system_files&quot;);</span><br><span class="line">    perform_protected_operation(&quot;write_user_files&quot;);</span><br><span class="line">    perform_protected_operation(&quot;network_admin&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示安全建议</span><br><span class="line">    show_security_advice(&amp;current_user);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 系统信息 ===\n&quot;);</span><br><span class="line">    printf(&quot;进程 ID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;真实 UID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;有效 UID: %d\n&quot;, geteuid());</span><br><span class="line">    printf(&quot;真实 GID: %d\n&quot;, getgid());</span><br><span class="line">    printf(&quot;有效 GID: %d\n&quot;, getegid());</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>编译和运行说明</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"># 编译示例程序</span><br><span class="line">gcc -o geteuid_example1 example1.c</span><br><span class="line">gcc -o geteuid_example2 example2.c</span><br><span class="line">gcc -o geteuid_example3 example3.c</span><br><span class="line"></span><br><span class="line"># 运行示例</span><br><span class="line">./geteuid_example1</span><br><span class="line">./geteuid_example2</span><br><span class="line">./geteuid_example3</span><br><span class="line"></span><br><span class="line"># 以 root 权限运行（需要 sudo）</span><br><span class="line">sudo ./geteuid_example1</span><br><span class="line">sudo ./geteuid_example2</span><br><span class="line">sudo ./geteuid_example3</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>命令行查看用户信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"># 查看当前用户信息</span><br><span class="line">id</span><br><span class="line"></span><br><span class="line"># 查看特定用户信息</span><br><span class="line">id username</span><br><span class="line"></span><br><span class="line"># 查看当前进程信息</span><br><span class="line">ps -eo pid,ppid,uid,euid,gid,egid,comm</span><br><span class="line"></span><br><span class="line"># 查看用户数据库</span><br><span class="line">cat /etc/passwd</span><br><span class="line">cat /etc/group</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>重要注意事项</p><p>不会失败: geteuid 总是成功返回，不需要错误检查</p><p>实时性: 返回的是调用时刻的有效用户 ID</p><p>权限检查: 有效 UID 用于所有权限检查</p><p>安全关键: 在安全敏感程序中要特别注意有效 UID</p><p>继承性: 子进程继承父进程的有效 UID</p><p>实际应用场景</p><p>权限验证: 在执行特权操作前检查有效 UID</p><p>安全审计: 记录操作的有效用户身份</p><p>访问控制: 根据有效 UID 控制资源访问</p><p>特权管理: 管理程序的特权级别切换</p><p>日志记录: 在日志中记录有效的用户身份</p><p>常见用户 ID 含义</p><p>用户 ID用户名说明0root超级用户1daemon系统守护进程用户2bin系统二进制文件用户5sync用于同步操作的用户37www-dataWeb 服务器用户65534nobody无特权用户</p><p>与相关函数的配合使用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">// 完整的身份信息获取</span><br><span class="line">uid_t real_uid = getuid();     // 真实用户 ID</span><br><span class="line">uid_t effective_uid = geteuid(); // 有效用户 ID</span><br><span class="line">gid_t real_gid = getgid();     // 真实组 ID</span><br><span class="line">gid_t effective_gid = getegid(); // 有效组 ID</span><br><span class="line"></span><br><span class="line">// 权限切换示例</span><br><span class="line">if (geteuid() == 0) &#123;</span><br><span class="line">    // 当前有 root 权限，执行特权操作</span><br><span class="line">    // ...</span><br><span class="line">    // 完成后可以放弃权限</span><br><span class="line">    // setuid(getuid());  // 切换到真实 UID</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>安全最佳实践</p><p>最小权限原则: 只在必要时获取特权</p><p>及时放弃权限: 完成特权操作后立即降低权限</p><p>验证身份: 在关键操作前验证有效 UID</p><p>避免持久化: 不要长时间保持高权限运行</p><p>日志记录: 记录所有特权操作的身份信息</p><p>这些示例展示了 geteuid 函数的各种使用方法，从基本的用户 ID 获取到完整的权限管理系统，帮助你全面理解 Linux 系统中的用户权限管理机制。</p><p>getgid系统调用及示例-CSDN博客</p><p>geteuid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-geteuid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-geteuid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="geteuid-函数详解"><a href="#geteuid-函数详解" class="headerlink" title="geteuid 函数详解"></a>geteuid 函数详解</h1><ol>
<li>函数介绍</li>
</ol>
<p>geteu]]>
    </summary>
    <title>geteuid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.169Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="getgid-函数详解"><a href="#getgid-函数详解" class="headerlink" title="getgid 函数详解"></a>getgid 函数详解</h1><p>getgid 是 Linux 系统中获取进程真实组 ID 的系统调用函数，用于确定进程的组权限级别。该函数无参数，总是成功返回调用进程的真实组 ID（gid_t 类型）。组 ID 类似于”部门编号”，决定进程在系统中的组权限。系统还提供相关函数如 getegid（获取有效组 ID）、getuid（获取用户 ID）等。示例代码演示了如何获取组 ID 信息、查询完整用户&#x2F;组信息以及检查权限状态。真实组 ID 和有效组 ID 通常相同，但在特殊权限操作时可能不同。</p><ol><li>函数介绍</li></ol><p>getgid 是 Linux 系统中用于获取进程真实组 ID（Group ID）的系统调用。可以把组 ID 想象成”用户的身份证明”——每个进程都属于一个或多个用户组，组 ID 决定了进程在系统中的组权限级别。</p><p>在 Linux 系统中，权限管理不仅基于用户，还基于用户组。就像一个公司员工不仅有个人身份，还属于不同的部门一样，每个用户都属于一个或多个组，而 getgid 就是获取进程所属的”主部门”编号。</p><ol start="2"><li>函数原型</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">gid_t getgid(void);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>功能</li></ol><p>getgid 函数用于获取调用进程的真实组 ID（real group ID）。真实组 ID 是进程启动时从父进程继承的组 ID，通常与有效组 ID（effective group ID）相同，但在某些特殊情况下可能不同。</p><ol start="4"><li>参数</li></ol><p>getgid 函数不需要任何参数。</p><ol start="5"><li>返回值</li></ol><ul><li><p>成功: 返回调用进程的真实组 ID（gid_t 类型）</p></li><li><p>注意: 此函数不会失败，总是成功返回</p></li></ul><ol start="6"><li>相关函数</li></ol><ul><li><p>getegid: 获取有效组 ID（effective group ID）</p></li><li><p>getuid: 获取真实用户 ID（real user ID）</p></li><li><p>geteuid: 获取有效用户 ID（effective user ID）</p></li><li><p>getgroups: 获取进程所属的所有组 ID</p></li><li><p>setgid: 设置组 ID</p></li><li><p>setgroups: 设置进程的附加组 ID 列表</p></li><li><p>initgroups: 初始化用户组访问列表</p></li></ul><ol start="7"><li>组 ID 类型说明</li></ol><p>Linux 系统中有几种不同的组 ID：</p><p>组 ID 类型说明真实组 ID (real GID)进程实际所属的组，由 getgid 返回有效组 ID (effective GID)用于权限检查的组 ID，由 getegid 返回保存的设置组 ID (saved set-group-ID)保存的组 ID，用于权限切换附加组 ID (supplementary GIDs)进程所属的额外组列表</p><ol start="8"><li>示例代码</li></ol><h3 id="示例1：基础用法-获取进程组-ID"><a href="#示例1：基础用法-获取进程组-ID" class="headerlink" title="示例1：基础用法 - 获取进程组 ID"></a>示例1：基础用法 - 获取进程组 ID</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    gid_t real_gid, effective_gid;</span><br><span class="line">    struct group *grp_info;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程组 ID 信息 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取真实组 ID</span><br><span class="line">    real_gid = getgid();</span><br><span class="line">    printf(&quot;真实组 ID (real GID): %d\n&quot;, real_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取有效组 ID</span><br><span class="line">    effective_gid = getegid();</span><br><span class="line">    printf(&quot;有效组 ID (effective GID): %d\n&quot;, effective_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取组名信息</span><br><span class="line">    grp_info = getgrgid(real_gid);</span><br><span class="line">    if (grp_info != NULL) &#123;</span><br><span class="line">        printf(&quot;组名: %s\n&quot;, grp_info-&gt;gr_name);</span><br><span class="line">        printf(&quot;组密码: %s\n&quot;, grp_info-&gt;gr_passwd ? grp_info-&gt;gr_passwd : &quot;(无)&quot;);</span><br><span class="line">        printf(&quot;组成员: &quot;);</span><br><span class="line">        if (grp_info-&gt;gr_mem &amp;&amp; grp_info-&gt;gr_mem&amp;#91;0]) &#123;</span><br><span class="line">            for (int i = 0; grp_info-&gt;gr_mem&amp;#91;i]; i++) &#123;</span><br><span class="line">                printf(&quot;%s &quot;, grp_info-&gt;gr_mem&amp;#91;i]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;(无成员列表)&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;无法获取组信息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 比较真实组 ID 和有效组 ID</span><br><span class="line">    if (real_gid == effective_gid) &#123;</span><br><span class="line">        printf(&quot;\n真实组 ID 和有效组 ID 相同\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;\n真实组 ID 和有效组 ID 不同\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例2：完整的用户和组信息查询"><a href="#示例2：完整的用户和组信息查询" class="headerlink" title="示例2：完整的用户和组信息查询"></a>示例2：完整的用户和组信息查询</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">void print_user_info(uid_t uid) &#123;</span><br><span class="line">    struct passwd *pwd_info;</span><br><span class="line">    </span><br><span class="line">    pwd_info = getpwuid(uid);</span><br><span class="line">    if (pwd_info != NULL) &#123;</span><br><span class="line">        printf(&quot;  用户名: %s\n&quot;, pwd_info-&gt;pw_name);</span><br><span class="line">        printf(&quot;  用户 ID: %d\n&quot;, pwd_info-&gt;pw_uid);</span><br><span class="line">        printf(&quot;  组 ID: %d\n&quot;, pwd_info-&gt;pw_gid);</span><br><span class="line">        printf(&quot;  主目录: %s\n&quot;, pwd_info-&gt;pw_dir);</span><br><span class="line">        printf(&quot;  登录 shell: %s\n&quot;, pwd_info-&gt;pw_shell);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  无法获取用户信息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_group_info(gid_t gid) &#123;</span><br><span class="line">    struct group *grp_info;</span><br><span class="line">    </span><br><span class="line">    grp_info = getgrgid(gid);</span><br><span class="line">    if (grp_info != NULL) &#123;</span><br><span class="line">        printf(&quot;  组名: %s\n&quot;, grp_info-&gt;gr_name);</span><br><span class="line">        printf(&quot;  组 ID: %d\n&quot;, grp_info-&gt;gr_gid);</span><br><span class="line">        printf(&quot;  组成员: &quot;);</span><br><span class="line">        if (grp_info-&gt;gr_mem &amp;&amp; grp_info-&gt;gr_mem&amp;#91;0]) &#123;</span><br><span class="line">            for (int i = 0; grp_info-&gt;gr_mem&amp;#91;i]; i++) &#123;</span><br><span class="line">                printf(&quot;%s &quot;, grp_info-&gt;gr_mem&amp;#91;i]);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;(无成员列表)&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  无法获取组信息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    uid_t real_uid, effective_uid;</span><br><span class="line">    gid_t real_gid, effective_gid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 完整的用户和组信息 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取用户 ID 信息</span><br><span class="line">    printf(&quot;用户信息:\n&quot;);</span><br><span class="line">    real_uid = getuid();</span><br><span class="line">    effective_uid = geteuid();</span><br><span class="line">    printf(&quot;  真实用户 ID: %d\n&quot;, real_uid);</span><br><span class="line">    printf(&quot;  有效用户 ID: %d\n&quot;, effective_uid);</span><br><span class="line">    print_user_info(real_uid);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取组 ID 信息</span><br><span class="line">    printf(&quot;组信息:\n&quot;);</span><br><span class="line">    real_gid = getgid();</span><br><span class="line">    effective_gid = getegid();</span><br><span class="line">    printf(&quot;  真实组 ID: %d\n&quot;, real_gid);</span><br><span class="line">    printf(&quot;  有效组 ID: %d\n&quot;, effective_gid);</span><br><span class="line">    print_group_info(real_gid);</span><br><span class="line">    </span><br><span class="line">    // 检查权限状态</span><br><span class="line">    printf(&quot;\n权限状态分析:\n&quot;);</span><br><span class="line">    if (real_uid == 0 || effective_uid == 0) &#123;</span><br><span class="line">        printf(&quot;  ✓ 进程具有 root 权限\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  ✗ 进程为普通用户权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (real_gid == effective_gid) &#123;</span><br><span class="line">        printf(&quot;  ✓ 组权限未被修改\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  ⚠ 组权限可能被修改过\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例3：多组支持和权限检查工具"><a href="#示例3：多组支持和权限检查工具" class="headerlink" title="示例3：多组支持和权限检查工具"></a>示例3：多组支持和权限检查工具</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line"></span><br><span class="line">// 获取并显示所有组信息</span><br><span class="line">void show_all_groups() &#123;</span><br><span class="line">    gid_t *groups;</span><br><span class="line">    int ngroups;</span><br><span class="line">    long ngroups_max;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 所有组信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取最大组数</span><br><span class="line">    ngroups_max = sysconf(_SC_NGROUPS_MAX);</span><br><span class="line">    if (ngroups_max == -1) &#123;</span><br><span class="line">        ngroups_max = 1024;  // 默认值</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分配内存</span><br><span class="line">    groups = malloc(ngroups_max * sizeof(gid_t));</span><br><span class="line">    if (groups == NULL) &#123;</span><br><span class="line">        perror(&quot;malloc&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取组列表</span><br><span class="line">    ngroups = getgroups(ngroups_max, groups);</span><br><span class="line">    if (ngroups == -1) &#123;</span><br><span class="line">        perror(&quot;getgroups&quot;);</span><br><span class="line">        free(groups);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;进程所属组数量: %d\n&quot;, ngroups);</span><br><span class="line">    printf(&quot;组 ID 列表:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; ngroups; i++) &#123;</span><br><span class="line">        struct group *grp_info = getgrgid(groups&amp;#91;i]);</span><br><span class="line">        printf(&quot;  &amp;#91;%d] %d&quot;, i + 1, groups&amp;#91;i]);</span><br><span class="line">        if (grp_info != NULL) &#123;</span><br><span class="line">            printf(&quot; (%s)&quot;, grp_info-&gt;gr_name);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 显示主组</span><br><span class="line">    gid_t primary_gid = getgid();</span><br><span class="line">    struct group *primary_grp = getgrgid(primary_gid);</span><br><span class="line">    printf(&quot;\n主组 (getgid): %d&quot;, primary_gid);</span><br><span class="line">    if (primary_grp != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, primary_grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    free(groups);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 检查是否属于特定组</span><br><span class="line">int is_member_of_group(gid_t target_gid) &#123;</span><br><span class="line">    gid_t *groups;</span><br><span class="line">    int ngroups;</span><br><span class="line">    long ngroups_max;</span><br><span class="line">    int result = 0;</span><br><span class="line">    </span><br><span class="line">    // 获取最大组数</span><br><span class="line">    ngroups_max = sysconf(_SC_NGROUPS_MAX);</span><br><span class="line">    if (ngroups_max == -1) &#123;</span><br><span class="line">        ngroups_max = 1024;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分配内存</span><br><span class="line">    groups = malloc(ngroups_max * sizeof(gid_t));</span><br><span class="line">    if (groups == NULL) &#123;</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取组列表</span><br><span class="line">    ngroups = getgroups(ngroups_max, groups);</span><br><span class="line">    if (ngroups == -1) &#123;</span><br><span class="line">        free(groups);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否包含目标组</span><br><span class="line">    for (int i = 0; i &lt; ngroups; i++) &#123;</span><br><span class="line">        if (groups&amp;#91;i] == target_gid) &#123;</span><br><span class="line">            result = 1;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 也要检查主组</span><br><span class="line">    if (!result &amp;&amp; getgid() == target_gid) &#123;</span><br><span class="line">        result = 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    free(groups);</span><br><span class="line">    return result;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 特权检查函数</span><br><span class="line">void check_privileges() &#123;</span><br><span class="line">    uid_t uid = getuid();</span><br><span class="line">    uid_t euid = geteuid();</span><br><span class="line">    gid_t gid = getgid();</span><br><span class="line">    gid_t egid = getegid();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 权限检查 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;用户权限:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 UID: %d\n&quot;, uid);</span><br><span class="line">    printf(&quot;  有效 UID: %d&quot;, euid);</span><br><span class="line">    if (euid == 0) &#123;</span><br><span class="line">        printf(&quot; (root 权限!)\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot; (普通用户)\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;组权限:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 GID: %d\n&quot;, gid);</span><br><span class="line">    printf(&quot;  有效 GID: %d&quot;, egid);</span><br><span class="line">    if (egid == 0) &#123;</span><br><span class="line">        printf(&quot; (root 组权限!)\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot; (普通组)\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否属于 wheel 或 sudo 组（管理员组）</span><br><span class="line">    struct group *admin_group;</span><br><span class="line">    </span><br><span class="line">    admin_group = getgrnam(&quot;wheel&quot;);</span><br><span class="line">    if (admin_group &amp;&amp; is_member_of_group(admin_group-&gt;gr_gid)) &#123;</span><br><span class="line">        printf(&quot;  ✓ 属于 wheel 组 (管理员组)\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    admin_group = getgrnam(&quot;sudo&quot;);</span><br><span class="line">    if (admin_group &amp;&amp; is_member_of_group(admin_group-&gt;gr_gid)) &#123;</span><br><span class="line">        printf(&quot;  ✓ 属于 sudo 组 (管理员组)\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 进程身份和权限信息工具 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示基本身份信息</span><br><span class="line">    printf(&quot;基本身份信息:\n&quot;);</span><br><span class="line">    printf(&quot;  进程 ID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;  真实用户 ID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;  真实组 ID: %d\n&quot;, getgid());</span><br><span class="line">    printf(&quot;  有效用户 ID: %d\n&quot;, geteuid());</span><br><span class="line">    printf(&quot;  有效组 ID: %d\n\n&quot;, getegid());</span><br><span class="line">    </span><br><span class="line">    // 权限检查</span><br><span class="line">    check_privileges();</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示所有组信息</span><br><span class="line">    show_all_groups();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 使用说明 ===\n&quot;);</span><br><span class="line">    printf(&quot;此工具显示当前进程的完整身份和权限信息。\n&quot;);</span><br><span class="line">    printf(&quot;包括用户 ID、组 ID、所属的所有组等信息。\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>编译和运行说明</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># 编译示例程序</span><br><span class="line">gcc -o getgid_example1 example1.c</span><br><span class="line">gcc -o getgid_example2 example2.c</span><br><span class="line">gcc -o getgid_example3 example3.c</span><br><span class="line"></span><br><span class="line"># 运行示例</span><br><span class="line">./getgid_example1</span><br><span class="line">./getgid_example2</span><br><span class="line">./getgid_example3</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>命令行查看组信息</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"># 查看当前用户信息</span><br><span class="line">id</span><br><span class="line"></span><br><span class="line"># 查看特定用户信息</span><br><span class="line">id username</span><br><span class="line"></span><br><span class="line"># 查看组信息</span><br><span class="line">groups</span><br><span class="line">cat /etc/group</span><br><span class="line"></span><br><span class="line"># 查看当前进程信息</span><br><span class="line">ps -eo pid,ppid,uid,gid,comm</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>重要注意事项</p><p>不会失败: getgid 总是成功返回，不需要错误检查</p><p>实时性: 返回的是调用时刻的组 ID</p><p>继承性: 子进程继承父进程的组 ID</p><p>权限相关: 组 ID 直接影响文件访问权限</p><p>安全考虑: 在安全敏感程序中要验证组 ID</p><p>实际应用场景</p><p>权限检查: 在执行特权操作前检查组权限</p><p>日志记录: 记录操作的用户组信息</p><p>访问控制: 根据组 ID 控制资源访问</p><p>安全审计: 审计程序的执行环境</p><p>多用户应用: 根据组 ID 提供不同功能</p><p>常见组 ID 含义</p><p>组 ID组名说明0root超级用户组1bin系统二进制文件组2daemon系统守护进程组5tty终端设备组10uucpUnix to Unix Copy 组</p><p>与相关函数的配合使用</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">// 完整的身份信息获取</span><br><span class="line">uid_t uid = getuid();    // 真实用户 ID</span><br><span class="line">gid_t gid = getgid();    // 真实组 ID</span><br><span class="line">uid_t euid = geteuid();  // 有效用户 ID</span><br><span class="line">gid_t egid = getegid();  // 有效组 ID</span><br><span class="line"></span><br><span class="line">// 获取所有组</span><br><span class="line">int ngroups = getgroups(0, NULL);  // 先获取数量</span><br><span class="line">gid_t *groups = malloc(ngroups * sizeof(gid_t));</span><br><span class="line">getgroups(ngroups, groups);        // 再获取组列表</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>这些示例展示了 getgid 函数的各种使用方法，从基本的组 ID 获取到完整的权限检查工具，帮助你全面理解 Linux 系统中的用户组管理机制。</p><p>getgid系统调用及示例-CSDN博客</p><p><a href="https://www.calcguide.tech/2025/09/09/geteuid-syscall-demo/">https://www.calcguide.tech/2025/09/09/geteuid-syscall-demo/</a></p><p>geteuid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getgid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getgid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="getgid-函数详解"><a href="#getgid-函数详解" class="headerlink" title="getgid 函数详解"></a>getgid 函数详解</h1><p>getgid 是 Linux 系统中获取进程真实组 ID 的系统调用]]>
    </summary>
    <title>getgid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.170Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getgroups - 获取进程的补充组列表</p><p>getgroups 是 Linux 系统调用，用于获取当前进程的补充组 ID 列表。该函数需要传入缓冲区大小和数组指针，返回补充组数量或填充的组 ID 数量。主要功能包括：查询进程所属的补充组（除主组外的其他组），支持先获取组数量再分配内存填充，并可与getgid()获取的主组 ID 对比。典型用法是两次调用：第一次获取数量，第二次填充数组。错误处理需注意缓冲区不足(EINVAL)和无效指针(EFAULT)等情况。相关函数包括setgroups()、initgroups()等组管理函数。</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getgroups 是一个 Linux 系统调用，用于获取当前进程所属的补充组（supplementary groups）列表。除了进程的主要组 ID（由 getgid() 返回）之外，进程还可以属于多个补充组，这些组决定了进程对文件和资源的额外访问权限。</p><p>补充组机制是 Unix&#x2F;Linux 系统中实现灵活访问控制的重要组成部分，允许用户同时属于多个组以获得相应的权限。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">int getgroups(int size, gid_t list&amp;#91;]);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><p>获取当前进程所属的补充组 ID 列表。补充组是除了主要组之外，进程还属于的其他组。</p><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><p>int size: 指定 list 数组的大小（元素个数）</p><ul><li><p>如果为 0：函数返回补充组的数量，不填充 list 数组</p></li><li><p>如果大于 0：将补充组 ID 填充到 list 数组中</p></li></ul><p>gid_t list[]: 指向存储组 ID 的数组</p><ul><li><p>如果 size 为 0：可以为 NULL</p></li><li><p>如果 size 大于 0：必须指向有效的数组</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><p>成功时：</p><ul><li><p>如果 size 为 0：返回补充组的数量</p></li><li><p>如果 size 大于 0：返回实际填充到数组中的组 ID 数量</p></li></ul><p>失败时返回 -1，并设置 errno</p><h3 id="6-常见-errno-错误码"><a href="#6-常见-errno-错误码" class="headerlink" title="6. 常见 errno 错误码"></a>6. 常见 errno 错误码</h3><ul><li><p>EINVAL: size 参数小于补充组的实际数量（缓冲区不足）</p></li><li><p>EFAULT: list 指针指向无效内存地址</p></li><li><p>EPERM: 在某些安全限制下可能返回（较少见）</p></li></ul><h3 id="7-相似函数，或关联函数"><a href="#7-相似函数，或关联函数" class="headerlink" title="7. 相似函数，或关联函数"></a>7. 相似函数，或关联函数</h3><ul><li><p>setgroups(): 设置进程的补充组列表</p></li><li><p>initgroups(): 根据用户信息初始化补充组列表</p></li><li><p>getgid(): 获取进程的真实组 ID</p></li><li><p>getegid(): 获取进程的有效组 ID</p></li><li><p>getuid(), geteuid(): 获取用户 ID 相关函数</p></li><li><p>setgid(), setegid(): 设置组 ID</p></li><li><p>getgrouplist(): 获取用户的所有组（包括主要组）</p></li><li><p>&#x2F;etc&#x2F;group: 系统组信息文件</p></li><li><p>&#x2F;etc&#x2F;passwd: 用户主要组信息文件</p></li></ul><h3 id="8-示例代码"><a href="#8-示例代码" class="headerlink" title="8. 示例代码"></a>8. 示例代码</h3><h4 id="示例1：基本使用-获取补充组列表"><a href="#示例1：基本使用-获取补充组列表" class="headerlink" title="示例1：基本使用 - 获取补充组列表"></a>示例1：基本使用 - 获取补充组列表</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int group_count;</span><br><span class="line">    gid_t *group_list;</span><br><span class="line">    long max_groups;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 获取进程补充组列表 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 首先获取补充组数量</span><br><span class="line">    group_count = getgroups(0, NULL);</span><br><span class="line">    if (group_count == -1) &#123;</span><br><span class="line">        perror(&quot;获取补充组数量失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;补充组数量: %d\n&quot;, group_count);</span><br><span class="line">    </span><br><span class="line">    if (group_count == 0) &#123;</span><br><span class="line">        printf(&quot;当前进程没有补充组\n&quot;);</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取系统支持的最大组数</span><br><span class="line">    max_groups = sysconf(_SC_NGROUPS_MAX);</span><br><span class="line">    if (max_groups == -1) &#123;</span><br><span class="line">        max_groups = 65536;  // 设置一个较大的默认值</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;系统最大支持组数: %ld\n&quot;, max_groups);</span><br><span class="line">    </span><br><span class="line">    // 确保不会超出系统限制</span><br><span class="line">    if (group_count &gt; max_groups) &#123;</span><br><span class="line">        printf(&quot;警告: 补充组数量超出系统限制\n&quot;);</span><br><span class="line">        group_count = max_groups;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分配内存存储组列表</span><br><span class="line">    group_list = malloc(group_count * sizeof(gid_t));</span><br><span class="line">    if (group_list == NULL) &#123;</span><br><span class="line">        perror(&quot;内存分配失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取补充组列表</span><br><span class="line">    int result = getgroups(group_count, group_list);</span><br><span class="line">    if (result == -1) &#123;</span><br><span class="line">        perror(&quot;获取补充组列表失败&quot;);</span><br><span class="line">        free(group_list);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功获取 %d 个补充组:\n&quot;, result);</span><br><span class="line">    printf(&quot;%-8s %-10s %s\n&quot;, &quot;序号&quot;, &quot;组ID&quot;, &quot;组名&quot;);</span><br><span class="line">    printf(&quot;%-8s %-10s %s\n&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示每个组的信息</span><br><span class="line">    for (int i = 0; i &lt; result; i++) &#123;</span><br><span class="line">        printf(&quot;%-8d %-10d &quot;, i + 1, group_list&amp;#91;i]);</span><br><span class="line">        </span><br><span class="line">        // 尝试获取组名</span><br><span class="line">        struct group *grp = getgrgid(group_list&amp;#91;i]);</span><br><span class="line">        if (grp != NULL) &#123;</span><br><span class="line">            printf(&quot;%s&quot;, grp-&gt;gr_name);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;(未知)&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 显示主要组信息进行对比</span><br><span class="line">    gid_t primary_gid = getgid();</span><br><span class="line">    printf(&quot;\n主要组信息:\n&quot;);</span><br><span class="line">    printf(&quot;  组ID: %d\n&quot;, primary_gid);</span><br><span class="line">    </span><br><span class="line">    struct group *primary_grp = getgrgid(primary_gid);</span><br><span class="line">    if (primary_grp != NULL) &#123;</span><br><span class="line">        printf(&quot;  组名: %s\n&quot;, primary_grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查主要组是否在补充组列表中</span><br><span class="line">    int found_in_supplementary = 0;</span><br><span class="line">    for (int i = 0; i &lt; result; i++) &#123;</span><br><span class="line">        if (group_list&amp;#91;i] == primary_gid) &#123;</span><br><span class="line">            found_in_supplementary = 1;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;主要组是否在补充组中: %s\n&quot;, </span><br><span class="line">           found_in_supplementary ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    </span><br><span class="line">    free(group_list);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：错误处理和边界情况"><a href="#示例2：错误处理和边界情况" class="headerlink" title="示例2：错误处理和边界情况"></a>示例2：错误处理和边界情况</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void demonstrate_error_handling() &#123;</span><br><span class="line">    int result;</span><br><span class="line">    gid_t small_buffer&amp;#91;2];  // 故意使用小缓冲区</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 错误处理演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取实际补充组数量</span><br><span class="line">    int actual_count = getgroups(0, NULL);</span><br><span class="line">    if (actual_count == -1) &#123;</span><br><span class="line">        perror(&quot;获取补充组数量失败&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;实际补充组数量: %d\n&quot;, actual_count);</span><br><span class="line">    </span><br><span class="line">    if (actual_count &gt; 0) &#123;</span><br><span class="line">        // 使用过小的缓冲区，应该返回错误</span><br><span class="line">        printf(&quot;使用过小缓冲区测试 (大小: 2):\n&quot;);</span><br><span class="line">        result = getgroups(2, small_buffer);</span><br><span class="line">        </span><br><span class="line">        if (result == -1) &#123;</span><br><span class="line">            if (errno == EINVAL) &#123;</span><br><span class="line">                printf(&quot;  错误处理正确: 缓冲区不足 (EINVAL)\n&quot;);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                printf(&quot;  其他错误: %s\n&quot;, strerror(errno));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;  意外成功，返回数量: %d\n&quot;, result);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 使用 NULL 指针但 size &gt; 0</span><br><span class="line">        printf(&quot;使用 NULL 指针测试:\n&quot;);</span><br><span class="line">        result = getgroups(10, NULL);</span><br><span class="line">        if (result == -1) &#123;</span><br><span class="line">            if (errno == EFAULT) &#123;</span><br><span class="line">                printf(&quot;  错误处理正确: 无效指针 (EFAULT)\n&quot;);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                printf(&quot;  其他错误: %s\n&quot;, strerror(errno));</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void demonstrate_empty_groups() &#123;</span><br><span class="line">    printf(&quot;\n=== 空组列表演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取补充组数量</span><br><span class="line">    int count = getgroups(0, NULL);</span><br><span class="line">    if (count == -1) &#123;</span><br><span class="line">        perror(&quot;获取组数量失败&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;当前进程补充组数量: %d\n&quot;, count);</span><br><span class="line">    </span><br><span class="line">    if (count == 0) &#123;</span><br><span class="line">        printf(&quot;进程没有补充组权限\n&quot;);</span><br><span class="line">        printf(&quot;这可能表示:\n&quot;);</span><br><span class="line">        printf(&quot;  1. 进程以最小权限运行\n&quot;);</span><br><span class="line">        printf(&quot;  2. 用户不属于任何补充组\n&quot;);</span><br><span class="line">        printf(&quot;  3. 在容器或受限环境中运行\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    demonstrate_error_handling();</span><br><span class="line">    demonstrate_empty_groups();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：完整的组权限分析工具"><a href="#示例3：完整的组权限分析工具" class="headerlink" title="示例3：完整的组权限分析工具"></a>示例3：完整的组权限分析工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    gid_t gid;</span><br><span class="line">    char group_name&amp;#91;256];</span><br><span class="line">    int is_primary;</span><br><span class="line">    int is_effective;</span><br><span class="line">    int is_supplementary;</span><br><span class="line">&#125; group_info_t;</span><br><span class="line"></span><br><span class="line">int compare_gids(const void *a, const void *b) &#123;</span><br><span class="line">    gid_t gid_a = ((group_info_t*)a)-&gt;gid;</span><br><span class="line">    gid_t gid_b = ((group_info_t*)b)-&gt;gid;</span><br><span class="line">    return (gid_a &gt; gid_b) - (gid_a &lt; gid_b);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void analyze_process_groups() &#123;</span><br><span class="line">    gid_t primary_gid, effective_gid;</span><br><span class="line">    int sup_count;</span><br><span class="line">    gid_t *sup_groups = NULL;</span><br><span class="line">    group_info_t *all_groups = NULL;</span><br><span class="line">    int total_groups = 0;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程组权限完整分析 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取基本信息</span><br><span class="line">    primary_gid = getgid();</span><br><span class="line">    effective_gid = getegid();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;进程基本信息:\n&quot;);</span><br><span class="line">    printf(&quot;  真实用户 ID: %d\n&quot;, getuid());</span><br><span class="line">    printf(&quot;  有效用户 ID: %d\n&quot;, geteuid());</span><br><span class="line">    printf(&quot;  真实组 ID: %d\n&quot;, primary_gid);</span><br><span class="line">    printf(&quot;  有效组 ID: %d\n&quot;, effective_gid);</span><br><span class="line">    </span><br><span class="line">    // 获取用户信息</span><br><span class="line">    struct passwd *pwd = getpwuid(getuid());</span><br><span class="line">    if (pwd != NULL) &#123;</span><br><span class="line">        printf(&quot;  用户名: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取补充组</span><br><span class="line">    sup_count = getgroups(0, NULL);</span><br><span class="line">    if (sup_count &gt; 0) &#123;</span><br><span class="line">        sup_groups = malloc(sup_count * sizeof(gid_t));</span><br><span class="line">        if (sup_groups == NULL) &#123;</span><br><span class="line">            perror(&quot;内存分配失败&quot;);</span><br><span class="line">            return;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        if (getgroups(sup_count, sup_groups) == -1) &#123;</span><br><span class="line">            perror(&quot;获取补充组失败&quot;);</span><br><span class="line">            free(sup_groups);</span><br><span class="line">            return;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 创建完整的组信息列表</span><br><span class="line">    total_groups = 2 + sup_count;  // primary + effective + supplementary</span><br><span class="line">    all_groups = malloc(total_groups * sizeof(group_info_t));</span><br><span class="line">    if (all_groups == NULL) &#123;</span><br><span class="line">        perror(&quot;内存分配失败&quot;);</span><br><span class="line">        if (sup_groups) free(sup_groups);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int index = 0;</span><br><span class="line">    </span><br><span class="line">    // 添加主要组</span><br><span class="line">    all_groups&amp;#91;index].gid = primary_gid;</span><br><span class="line">    all_groups&amp;#91;index].is_primary = 1;</span><br><span class="line">    all_groups&amp;#91;index].is_effective = (primary_gid == effective_gid);</span><br><span class="line">    all_groups&amp;#91;index].is_supplementary = 0;</span><br><span class="line">    struct group *grp = getgrgid(primary_gid);</span><br><span class="line">    if (grp != NULL) &#123;</span><br><span class="line">        strncpy(all_groups&amp;#91;index].group_name, grp-&gt;gr_name, sizeof(all_groups&amp;#91;index].group_name) - 1);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        snprintf(all_groups&amp;#91;index].group_name, sizeof(all_groups&amp;#91;index].group_name), &quot;group_%d&quot;, primary_gid);</span><br><span class="line">    &#125;</span><br><span class="line">    index++;</span><br><span class="line">    </span><br><span class="line">    // 添加有效组（如果不同于主要组）</span><br><span class="line">    if (effective_gid != primary_gid) &#123;</span><br><span class="line">        all_groups&amp;#91;index].gid = effective_gid;</span><br><span class="line">        all_groups&amp;#91;index].is_primary = 0;</span><br><span class="line">        all_groups&amp;#91;index].is_effective = 1;</span><br><span class="line">        all_groups&amp;#91;index].is_supplementary = 0;</span><br><span class="line">        struct group *grp = getgrgid(effective_gid);</span><br><span class="line">        if (grp != NULL) &#123;</span><br><span class="line">            strncpy(all_groups&amp;#91;index].group_name, grp-&gt;gr_name, sizeof(all_groups&amp;#91;index].group_name) - 1);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            snprintf(all_groups&amp;#91;index].group_name, sizeof(all_groups&amp;#91;index].group_name), &quot;group_%d&quot;, effective_gid);</span><br><span class="line">        &#125;</span><br><span class="line">        index++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 添加补充组</span><br><span class="line">    for (int i = 0; i &lt; sup_count; i++) &#123;</span><br><span class="line">        // 检查是否已存在</span><br><span class="line">        int exists = 0;</span><br><span class="line">        for (int j = 0; j &lt; index; j++) &#123;</span><br><span class="line">            if (all_groups&amp;#91;j].gid == sup_groups&amp;#91;i]) &#123;</span><br><span class="line">                all_groups&amp;#91;j].is_supplementary = 1;</span><br><span class="line">                exists = 1;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        if (!exists) &#123;</span><br><span class="line">            all_groups&amp;#91;index].gid = sup_groups&amp;#91;i];</span><br><span class="line">            all_groups&amp;#91;index].is_primary = 0;</span><br><span class="line">            all_groups&amp;#91;index].is_effective = (sup_groups&amp;#91;i] == effective_gid);</span><br><span class="line">            all_groups&amp;#91;index].is_supplementary = 1;</span><br><span class="line">            struct group *grp = getgrgid(sup_groups&amp;#91;i]);</span><br><span class="line">            if (grp != NULL) &#123;</span><br><span class="line">                strncpy(all_groups&amp;#91;index].group_name, grp-&gt;gr_name, sizeof(all_groups&amp;#91;index].group_name) - 1);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                snprintf(all_groups&amp;#91;index].group_name, sizeof(all_groups&amp;#91;index].group_name), &quot;group_%d&quot;, sup_groups&amp;#91;i]);</span><br><span class="line">            &#125;</span><br><span class="line">            index++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    total_groups = index;</span><br><span class="line">    </span><br><span class="line">    // 按组 ID 排序</span><br><span class="line">    qsort(all_groups, total_groups, sizeof(group_info_t), compare_gids);</span><br><span class="line">    </span><br><span class="line">    // 显示结果</span><br><span class="line">    printf(&quot;\n完整的组权限信息:\n&quot;);</span><br><span class="line">    printf(&quot;%-8s %-10s %-12s %-12s %-15s %s\n&quot;, </span><br><span class="line">           &quot;序号&quot;, &quot;组ID&quot;, &quot;主要组&quot;, &quot;有效组&quot;, &quot;补充组&quot;, &quot;组名&quot;);</span><br><span class="line">    printf(&quot;%-8s %-10s %-12s %-12s %-15s %s\n&quot;, </span><br><span class="line">           &quot;----&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; total_groups; i++) &#123;</span><br><span class="line">        printf(&quot;%-8d %-10d %-12s %-12s %-15s %s\n&quot;,</span><br><span class="line">               i + 1,</span><br><span class="line">               all_groups&amp;#91;i].gid,</span><br><span class="line">               all_groups&amp;#91;i].is_primary ? &quot;是&quot; : &quot;否&quot;,</span><br><span class="line">               all_groups&amp;#91;i].is_effective ? &quot;是&quot; : &quot;否&quot;,</span><br><span class="line">               all_groups&amp;#91;i].is_supplementary ? &quot;是&quot; : &quot;否&quot;,</span><br><span class="line">               all_groups&amp;#91;i].group_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 统计信息</span><br><span class="line">    printf(&quot;\n统计信息:\n&quot;);</span><br><span class="line">    printf(&quot;  总组数: %d\n&quot;, total_groups);</span><br><span class="line">    </span><br><span class="line">    int primary_count = 0, effective_count = 0, supplementary_count = 0;</span><br><span class="line">    for (int i = 0; i &lt; total_groups; i++) &#123;</span><br><span class="line">        if (all_groups&amp;#91;i].is_primary) primary_count++;</span><br><span class="line">        if (all_groups&amp;#91;i].is_effective) effective_count++;</span><br><span class="line">        if (all_groups&amp;#91;i].is_supplementary) supplementary_count++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;  主要组: %d\n&quot;, primary_count);</span><br><span class="line">    printf(&quot;  有效组: %d\n&quot;, effective_count);</span><br><span class="line">    printf(&quot;  补充组: %d\n&quot;, supplementary_count);</span><br><span class="line">    </span><br><span class="line">    // 特殊权限检查</span><br><span class="line">    printf(&quot;\n特殊权限检查:\n&quot;);</span><br><span class="line">    int has_root_group = 0;</span><br><span class="line">    int has_admin_group = 0;</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; total_groups; i++) &#123;</span><br><span class="line">        if (all_groups&amp;#91;i].gid == 0) &#123;</span><br><span class="line">            has_root_group = 1;</span><br><span class="line">        &#125;</span><br><span class="line">        // 检查常见的管理员组</span><br><span class="line">        if (strcmp(all_groups&amp;#91;i].group_name, &quot;wheel&quot;) == 0 ||</span><br><span class="line">            strcmp(all_groups&amp;#91;i].group_name, &quot;sudo&quot;) == 0 ||</span><br><span class="line">            strcmp(all_groups&amp;#91;i].group_name, &quot;adm&quot;) == 0) &#123;</span><br><span class="line">            has_admin_group = 1;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;  Root 组权限: %s\n&quot;, has_root_group ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    printf(&quot;  管理员组权限: %s\n&quot;, has_admin_group ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">    </span><br><span class="line">    // 清理内存</span><br><span class="line">    if (sup_groups) free(sup_groups);</span><br><span class="line">    if (all_groups) free(all_groups);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    analyze_process_groups();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：组权限验证和安全检查"><a href="#示例4：组权限验证和安全检查" class="headerlink" title="示例4：组权限验证和安全检查"></a>示例4：组权限验证和安全检查</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">// 检查进程是否属于指定组</span><br><span class="line">int is_process_member_of_group(gid_t target_gid) &#123;</span><br><span class="line">    // 首先检查主要组和有效组</span><br><span class="line">    if (getgid() == target_gid || getegid() == target_gid) &#123;</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查补充组</span><br><span class="line">    int sup_count = getgroups(0, NULL);</span><br><span class="line">    if (sup_count &lt;= 0) &#123;</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    gid_t *sup_groups = malloc(sup_count * sizeof(gid_t));</span><br><span class="line">    if (sup_groups == NULL) &#123;</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (getgroups(sup_count, sup_groups) == -1) &#123;</span><br><span class="line">        free(sup_groups);</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; sup_count; i++) &#123;</span><br><span class="line">        if (sup_groups&amp;#91;i] == target_gid) &#123;</span><br><span class="line">            free(sup_groups);</span><br><span class="line">            return 1;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    free(sup_groups);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 获取特定组的权限级别</span><br><span class="line">typedef enum &#123;</span><br><span class="line">    NO_ACCESS = 0,</span><br><span class="line">    SUPPLEMENTARY_ACCESS = 1,</span><br><span class="line">    PRIMARY_ACCESS = 2,</span><br><span class="line">    EFFECTIVE_ACCESS = 3,</span><br><span class="line">    ROOT_ACCESS = 4</span><br><span class="line">&#125; access_level_t;</span><br><span class="line"></span><br><span class="line">access_level_t get_group_access_level(gid_t target_gid) &#123;</span><br><span class="line">    if (target_gid == 0 &amp;&amp; (getgid() == 0 || getegid() == 0)) &#123;</span><br><span class="line">        return ROOT_ACCESS;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (getegid() == target_gid) &#123;</span><br><span class="line">        return EFFECTIVE_ACCESS;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (getgid() == target_gid) &#123;</span><br><span class="line">        return PRIMARY_ACCESS;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查补充组</span><br><span class="line">    int sup_count = getgroups(0, NULL);</span><br><span class="line">    if (sup_count &gt; 0) &#123;</span><br><span class="line">        gid_t *sup_groups = malloc(sup_count * sizeof(gid_t));</span><br><span class="line">        if (sup_groups != NULL) &#123;</span><br><span class="line">            if (getgroups(sup_count, sup_groups) != -1) &#123;</span><br><span class="line">                for (int i = 0; i &lt; sup_count; i++) &#123;</span><br><span class="line">                    if (sup_groups&amp;#91;i] == target_gid) &#123;</span><br><span class="line">                        free(sup_groups);</span><br><span class="line">                        return SUPPLEMENTARY_ACCESS;</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125;</span><br><span class="line">            free(sup_groups);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return NO_ACCESS;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void check_common_groups() &#123;</span><br><span class="line">    printf(&quot;=== 常见组权限检查 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 检查一些常见的系统组</span><br><span class="line">    struct &#123;</span><br><span class="line">        const char *name;</span><br><span class="line">        gid_t gid;</span><br><span class="line">    &#125; common_groups&amp;#91;] = &#123;</span><br><span class="line">        &#123;&quot;root&quot;, 0&#125;,</span><br><span class="line">        &#123;&quot;wheel&quot;, 0&#125;,  // 需要查找实际 GID</span><br><span class="line">        &#123;&quot;sudo&quot;, 0&#125;,</span><br><span class="line">        &#123;&quot;adm&quot;, 0&#125;,</span><br><span class="line">        &#123;&quot;disk&quot;, 0&#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    </span><br><span class="line">    // 获取这些组的实际 GID</span><br><span class="line">    for (int i = 0; i &lt; sizeof(common_groups)/sizeof(common_groups&amp;#91;0]); i++) &#123;</span><br><span class="line">        struct group *grp = getgrnam(common_groups&amp;#91;i].name);</span><br><span class="line">        if (grp != NULL) &#123;</span><br><span class="line">            common_groups&amp;#91;i].gid = grp-&gt;gr_gid;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;%-12s %-8s %-15s %s\n&quot;, &quot;组名&quot;, &quot;组ID&quot;, &quot;访问级别&quot;, &quot;成员状态&quot;);</span><br><span class="line">    printf(&quot;%-12s %-8s %-15s %s\n&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; sizeof(common_groups)/sizeof(common_groups&amp;#91;0]); i++) &#123;</span><br><span class="line">        if (common_groups&amp;#91;i].gid != 0) &#123;</span><br><span class="line">            access_level_t level = get_group_access_level(common_groups&amp;#91;i].gid);</span><br><span class="line">            int is_member = is_process_member_of_group(common_groups&amp;#91;i].gid);</span><br><span class="line">            </span><br><span class="line">            const char *level_str;</span><br><span class="line">            switch (level) &#123;</span><br><span class="line">                case ROOT_ACCESS: level_str = &quot;Root&quot;; break;</span><br><span class="line">                case EFFECTIVE_ACCESS: level_str = &quot;Effective&quot;; break;</span><br><span class="line">                case PRIMARY_ACCESS: level_str = &quot;Primary&quot;; break;</span><br><span class="line">                case SUPPLEMENTARY_ACCESS: level_str = &quot;Supplementary&quot;; break;</span><br><span class="line">                default: level_str = &quot;None&quot;; break;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            printf(&quot;%-12s %-8d %-15s %s\n&quot;,</span><br><span class="line">                   common_groups&amp;#91;i].name,</span><br><span class="line">                   common_groups&amp;#91;i].gid,</span><br><span class="line">                   level_str,</span><br><span class="line">                   is_member ? &quot;是&quot; : &quot;否&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    check_common_groups();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-实际应用场景"><a href="#9-实际应用场景" class="headerlink" title="9. 实际应用场景"></a>9. 实际应用场景</h3><p>getgroups 在以下场景中非常有用：</p><h4 id="场景1：权限验证"><a href="#场景1：权限验证" class="headerlink" title="场景1：权限验证"></a>场景1：权限验证</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">int can_access_resource(gid_t required_group) &#123;</span><br><span class="line">    return is_process_member_of_group(required_group);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：安全审计"><a href="#场景2：安全审计" class="headerlink" title="场景2：安全审计"></a>场景2：安全审计</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">void audit_process_groups() &#123;</span><br><span class="line">    int count = getgroups(0, NULL);</span><br><span class="line">    syslog(LOG_INFO, &quot;进程拥有 %d 个补充组&quot;, count);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：访问控制"><a href="#场景3：访问控制" class="headerlink" title="场景3：访问控制"></a>场景3：访问控制</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">int check_file_group_permission(const char *filename) &#123;</span><br><span class="line">    struct stat file_stat;</span><br><span class="line">    if (stat(filename, &amp;file_stat) == 0) &#123;</span><br><span class="line">        return is_process_member_of_group(file_stat.st_gid);</span><br><span class="line">    &#125;</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-注意事项"><a href="#10-注意事项" class="headerlink" title="10. 注意事项"></a>10. 注意事项</h3><p>使用 getgroups 时需要注意：</p><p>缓冲区大小: 确保缓冲区足够大，避免 EINVAL 错误</p><p>内存管理: 正确分配和释放内存</p><p>错误处理: 检查返回值和 errno</p><p>系统限制: 了解 NGROUPS_MAX 限制</p><p>并发安全: 在多线程环境中注意数据一致性</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getgroups 是管理进程组权限的重要函数，关键要点：</p><p>补充组获取: 获取进程除主要组外的所有组</p><p>双重调用: 通常需要先获取数量，再获取实际数据</p><p>权限检查: 是权限验证和访问控制的基础</p><p>安全相关: 在安全审计和权限管理中广泛使用</p><p>系统集成: 与 &#x2F;etc&#x2F;group 等系统文件紧密相关</p><p>正确使用 getgroups 可以帮助程序准确了解当前的组权限状态，实现更精细的访问控制和安全检查。</p><p>getgroups系统调用及示例-CSDN博客</p><p>getgid系统调用及示例-CSDN博客</p><p>getgid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getgroups-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getgroups-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getgroups - 获取进程的补充组列表</p>
<p>getgroups 是 Linux 系统调用，用于获取当前进程的补充组 ID 列表。该函数需要传入缓冲区大小和数组指针，返回补充组数量或填充的组 ID 数量。主要功能包括：查询进程所属的补充组（除主组外的其他组），]]>
    </summary>
    <title>getgroups系统调用及示例</title>
    <updated>2026-06-15T07:56:28.170Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="getmsg-函数详解"><a href="#getmsg-函数详解" class="headerlink" title="getmsg 函数详解"></a>getmsg 函数详解</h1><ol><li>函数介绍</li></ol><p>getmsg 是 System V STREAMS 接口中的一个函数，用于从 STREAMS 设备或管道中接收消息。可以把 STREAMS 想象成一个”消息传送带系统”——数据以消息的形式在系统中流动，getmsg 就是从这个传送带上取下消息的工具。</p><p>STREAMS 是 Unix System V 中的一种模块化 I&#x2F;O 框架，它允许在数据流中插入处理模块，实现复杂的数据处理。虽然在现代 Linux 系统中 STREAMS 使用较少，但在一些 Unix 系统（如 Solaris）中仍然重要。</p><p>getmsg 允许你接收包含控制信息和数据信息的消息，提供了比普通 read 更精细的控制。</p><p>getmsg系统调用及示例-CSDN博客</p><ol start="2"><li>函数原型</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stropts.h&gt;</span><br><span class="line"></span><br><span class="line">int getmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, int *flagsp);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>功能</li></ol><p>getmsg 函数用于从 STREAMS 文件描述符中接收消息。它可以分别接收消息的控制部分和数据部分，提供了对消息结构的精细控制。</p><ol start="4"><li>参数</li></ol><ul><li><p>fildes: STREAMS 设备或管道的文件描述符</p></li><li><p>ctlptr: 指向 strbuf 结构体的指针，用于接收控制信息</p></li><li><p>dataptr: 指向 strbuf 结构体的指针，用于接收数据信息</p></li><li><p>flagsp: 指向标志的指针，用于指定接收模式和返回消息类型</p></li></ul><ol start="5"><li>strbuf 结构体</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">struct strbuf &#123;</span><br><span class="line">    int     maxlen;    /* 缓冲区最大长度 */</span><br><span class="line">    int     len;       /* 实际数据长度 */</span><br><span class="line">    char    *buf;      /* 指向缓冲区的指针 */</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="6"><li>flags 参数说明</li></ol><p>输入标志（指定要接收的消息类型）：</p><ul><li><p>0: 接收下一条消息（按优先级顺序）</p></li><li><p>RS_HIPRI: 接收下一条高优先级消息</p></li></ul><p>输出标志（返回实际接收到的消息类型）：</p><ul><li><p>0: 普通优先级消息</p></li><li><p>RS_HIPRI: 高优先级消息</p></li></ul><ol start="7"><li>返回值</li></ol><ul><li><p>成功: 返回 0 或非负值</p></li><li><p>失败: 返回 -1，并设置相应的 errno 错误码</p></li></ul><p>特殊返回值：</p><ul><li><p>MORECTL: 控制部分还有更多数据</p></li><li><p>MOREDATA: 数据部分还有更多数据</p></li></ul><p>常见错误码：</p><ul><li><p>EBADF: fildes 不是有效的文件描述符</p></li><li><p>EINVAL: 参数无效</p></li><li><p>EIO: I&#x2F;O 错误</p></li><li><p>ENOSTR: fildes 不是 STREAMS 设备</p></li><li><p>ENOSR: 没有足够的 STREAMS 资源</p></li><li><p>EAGAIN: 非阻塞模式下无数据可读</p></li></ul><ol start="8"><li>相似函数或关联函数</li></ol><ul><li><p>putmsg: 发送消息到 STREAMS 设备</p></li><li><p>getpmsg: 获取带优先级的消息（更高级的版本）</p></li><li><p>putpmsg: 发送带优先级的消息</p></li><li><p>ioctl: 控制 STREAMS 设备</p></li><li><p>read&#x2F;write: 普通的文件读写操作</p></li></ul><ol start="9"><li>示例代码</li></ol><h3 id="示例1：基础用法-简单的消息接收"><a href="#示例1：基础用法-简单的消息接收" class="headerlink" title="示例1：基础用法 - 简单的消息接收"></a>示例1：基础用法 - 简单的消息接收</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stropts.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line"></span><br><span class="line">// 注意：这个示例在大多数 Linux 系统上可能无法运行</span><br><span class="line">// 因为 Linux 不完全支持 STREAMS</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    struct strbuf ctlbuf, databuf;</span><br><span class="line">    char ctl_data&amp;#91;256], data_buf&amp;#91;1024];</span><br><span class="line">    int flags;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== getmsg 基础示例 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区结构</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_data);</span><br><span class="line">    ctlbuf.buf = ctl_data;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buf);</span><br><span class="line">    databuf.buf = data_buf;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    flags = 0;  // 接收普通消息</span><br><span class="line">    </span><br><span class="line">    printf(&quot;注意: getmsg 主要用于 STREAMS 系统\n&quot;);</span><br><span class="line">    printf(&quot;在大多数 Linux 系统上可能不可用\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 尝试打开一个 STREAMS 设备（示例）</span><br><span class="line">    // fd = open(&quot;/dev/stream_device&quot;, O_RDONLY);</span><br><span class="line">    // 由于大多数系统没有 STREAMS 设备，这里只演示结构</span><br><span class="line">    </span><br><span class="line">    printf(&quot;控制缓冲区设置:\n&quot;);</span><br><span class="line">    printf(&quot;  最大长度: %d\n&quot;, ctlbuf.maxlen);</span><br><span class="line">    printf(&quot;  缓冲区地址: %p\n&quot;, (void*)ctlbuf.buf);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;数据缓冲区设置:\n&quot;);</span><br><span class="line">    printf(&quot;  最大长度: %d\n&quot;, databuf.maxlen);</span><br><span class="line">    printf(&quot;  缓冲区地址: %p\n&quot;, (void*)databuf.buf);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;标志设置: %d\n&quot;, flags);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n如果在支持 STREAMS 的系统上，可以这样调用:\n&quot;);</span><br><span class="line">    printf(&quot;result = getmsg(fd, &amp;ctlbuf, &amp;databuf, &amp;flags);\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例2：模拟-STREAMS-消息处理"><a href="#示例2：模拟-STREAMS-消息处理" class="headerlink" title="示例2：模拟 STREAMS 消息处理"></a>示例2：模拟 STREAMS 消息处理</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 模拟 STREAMS 消息结构</span><br><span class="line">struct simulated_msg &#123;</span><br><span class="line">    int priority;           // 消息优先级</span><br><span class="line">    int control_len;        // 控制数据长度</span><br><span class="line">    char control_data&amp;#91;256]; // 控制数据</span><br><span class="line">    int data_len;           // 数据长度</span><br><span class="line">    char data&amp;#91;1024];        // 实际数据</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 模拟的 strbuf 结构</span><br><span class="line">struct simulated_strbuf &#123;</span><br><span class="line">    int maxlen;</span><br><span class="line">    int len;</span><br><span class="line">    char *buf;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 模拟的 getmsg 函数</span><br><span class="line">int simulated_getmsg(struct simulated_msg *msg, </span><br><span class="line">                     struct simulated_strbuf *ctlptr, </span><br><span class="line">                     struct simulated_strbuf *dataptr, </span><br><span class="line">                     int *flagsp) &#123;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 模拟 getmsg 操作 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 复制控制数据</span><br><span class="line">    if (ctlptr &amp;&amp; ctlptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;control_len &lt; ctlptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;control_len : ctlptr-&gt;maxlen;</span><br><span class="line">        memcpy(ctlptr-&gt;buf, msg-&gt;control_data, copy_len);</span><br><span class="line">        ctlptr-&gt;len = copy_len;</span><br><span class="line">        printf(&quot;复制控制数据: %d 字节\n&quot;, copy_len);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 复制数据</span><br><span class="line">    if (dataptr &amp;&amp; dataptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;data_len &lt; dataptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;data_len : dataptr-&gt;maxlen;</span><br><span class="line">        memcpy(dataptr-&gt;buf, msg-&gt;data, copy_len);</span><br><span class="line">        dataptr-&gt;len = copy_len;</span><br><span class="line">        printf(&quot;复制数据: %d 字节\n&quot;, copy_len);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 设置标志</span><br><span class="line">    if (flagsp) &#123;</span><br><span class="line">        *flagsp = (msg-&gt;priority &gt; 0) ? 1 : 0;  // 模拟高优先级标志</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;消息优先级: %s\n&quot;, </span><br><span class="line">           (msg-&gt;priority &gt; 0) ? &quot;高&quot; : &quot;普通&quot;);</span><br><span class="line">    printf(&quot;控制数据长度: %d\n&quot;, msg-&gt;control_len);</span><br><span class="line">    printf(&quot;数据长度: %d\n&quot;, msg-&gt;data_len);</span><br><span class="line">    </span><br><span class="line">    return 0;  // 成功</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 创建测试消息</span><br><span class="line">struct simulated_msg* create_test_message() &#123;</span><br><span class="line">    static struct simulated_msg msg;</span><br><span class="line">    </span><br><span class="line">    msg.priority = 1;  // 高优先级</span><br><span class="line">    msg.control_len = strlen(&quot;CONTROL_INFO&quot;) + 1;</span><br><span class="line">    strcpy(msg.control_data, &quot;CONTROL_INFO&quot;);</span><br><span class="line">    msg.data_len = strlen(&quot;Hello, STREAMS World!&quot;) + 1;</span><br><span class="line">    strcpy(msg.data, &quot;Hello, STREAMS World!&quot;);</span><br><span class="line">    </span><br><span class="line">    return &amp;msg;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct simulated_msg *test_msg;</span><br><span class="line">    struct simulated_strbuf ctlbuf, databuf;</span><br><span class="line">    char ctl_buffer&amp;#91;256], data_buffer&amp;#91;1024];</span><br><span class="line">    int flags;</span><br><span class="line">    int result;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== STREAMS 消息处理模拟 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 创建测试消息</span><br><span class="line">    test_msg = create_test_message();</span><br><span class="line">    printf(&quot;创建测试消息完成\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_buffer);</span><br><span class="line">    ctlbuf.buf = ctl_buffer;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buffer);</span><br><span class="line">    databuf.buf = data_buffer;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    flags = 0;</span><br><span class="line">    </span><br><span class="line">    // 调用模拟的 getmsg</span><br><span class="line">    result = simulated_getmsg(test_msg, &amp;ctlbuf, &amp;databuf, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;\n=== 接收结果 ===\n&quot;);</span><br><span class="line">        printf(&quot;控制数据 (%d 字节): %s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;数据 (%d 字节): %s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;消息标志: %s\n&quot;, (flags &gt; 0) ? &quot;高优先级&quot; : &quot;普通优先级&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;接收消息失败\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例3：完整的-STREAMS-消息系统模拟"><a href="#示例3：完整的-STREAMS-消息系统模拟" class="headerlink" title="示例3：完整的 STREAMS 消息系统模拟"></a>示例3：完整的 STREAMS 消息系统模拟</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">// 消息类型定义</span><br><span class="line">#define MSG_NORMAL 0</span><br><span class="line">#define MSG_HIGH_PRIORITY 1</span><br><span class="line">#define MSG_CONTROL 2</span><br><span class="line">#define MSG_DATA 3</span><br><span class="line"></span><br><span class="line">// 模拟的 STREAMS 消息队列</span><br><span class="line">struct message_queue &#123;</span><br><span class="line">    int count;</span><br><span class="line">    struct &#123;</span><br><span class="line">        int priority;</span><br><span class="line">        int type;</span><br><span class="line">        time_t timestamp;</span><br><span class="line">        int control_len;</span><br><span class="line">        char control_data&amp;#91;128];</span><br><span class="line">        int data_len;</span><br><span class="line">        char data&amp;#91;512];</span><br><span class="line">    &#125; messages&amp;#91;10];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 模拟的 strbuf 结构</span><br><span class="line">struct my_strbuf &#123;</span><br><span class="line">    int maxlen;</span><br><span class="line">    int len;</span><br><span class="line">    char *buf;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 全局消息队列</span><br><span class="line">struct message_queue global_queue = &#123;0&#125;;</span><br><span class="line"></span><br><span class="line">// 向队列添加消息</span><br><span class="line">int add_message(int priority, int type, </span><br><span class="line">                const char *control, const char *data) &#123;</span><br><span class="line">    if (global_queue.count &gt;= 10) &#123;</span><br><span class="line">        printf(&quot;消息队列已满\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int index = global_queue.count++;</span><br><span class="line">    global_queue.messages&amp;#91;index].priority = priority;</span><br><span class="line">    global_queue.messages&amp;#91;index].type = type;</span><br><span class="line">    global_queue.messages&amp;#91;index].timestamp = time(NULL);</span><br><span class="line">    </span><br><span class="line">    if (control) &#123;</span><br><span class="line">        global_queue.messages&amp;#91;index].control_len = strlen(control) + 1;</span><br><span class="line">        strncpy(global_queue.messages&amp;#91;index].control_data, control, 127);</span><br><span class="line">        global_queue.messages&amp;#91;index].control_data&amp;#91;127] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        global_queue.messages&amp;#91;index].control_len = 0;</span><br><span class="line">        global_queue.messages&amp;#91;index].control_data&amp;#91;0] = &#x27;\0&#x27;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (data) &#123;</span><br><span class="line">        global_queue.messages&amp;#91;index].data_len = strlen(data) + 1;</span><br><span class="line">        strncpy(global_queue.messages&amp;#91;index].data, data, 511);</span><br><span class="line">        global_queue.messages&amp;#91;index].data&amp;#91;511] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        global_queue.messages&amp;#91;index].data_len = 0;</span><br><span class="line">        global_queue.messages&amp;#91;index].data&amp;#91;0] = &#x27;\0&#x27;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;添加消息: 优先级=%d, 类型=%d, 控制=%s, 数据=%s\n&quot;,</span><br><span class="line">           priority, type, control ? control : &quot;无&quot;, data ? data : &quot;无&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 模拟的 getmsg 实现</span><br><span class="line">int my_getmsg(struct my_strbuf *ctlptr, </span><br><span class="line">              struct my_strbuf *dataptr, </span><br><span class="line">              int *flagsp) &#123;</span><br><span class="line">    </span><br><span class="line">    if (global_queue.count == 0) &#123;</span><br><span class="line">        printf(&quot;消息队列为空\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 查找高优先级消息（如果请求）</span><br><span class="line">    int msg_index = 0;</span><br><span class="line">    if (flagsp &amp;&amp; (*flagsp &amp; 1)) &#123;  // 模拟 RS_HIPRI</span><br><span class="line">        for (int i = 0; i &lt; global_queue.count; i++) &#123;</span><br><span class="line">            if (global_queue.messages&amp;#91;i].priority &gt; 0) &#123;</span><br><span class="line">                msg_index = i;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取消息</span><br><span class="line">    struct message_queue *msg = &amp;global_queue.messages&amp;#91;msg_index];</span><br><span class="line">    </span><br><span class="line">    // 复制控制数据</span><br><span class="line">    if (ctlptr &amp;&amp; ctlptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;control_len &lt; ctlptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;control_len : ctlptr-&gt;maxlen;</span><br><span class="line">        memcpy(ctlptr-&gt;buf, msg-&gt;control_data, copy_len);</span><br><span class="line">        ctlptr-&gt;len = copy_len;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 复制数据</span><br><span class="line">    if (dataptr &amp;&amp; dataptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;data_len &lt; dataptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;data_len : dataptr-&gt;maxlen;</span><br><span class="line">        memcpy(dataptr-&gt;buf, msg-&gt;data, copy_len);</span><br><span class="line">        dataptr-&gt;len = copy_len;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 设置返回标志</span><br><span class="line">    if (flagsp) &#123;</span><br><span class="line">        *flagsp = (msg-&gt;priority &gt; 0) ? 1 : 0;  // 高优先级标志</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 从队列中移除消息</span><br><span class="line">    for (int i = msg_index; i &lt; global_queue.count - 1; i++) &#123;</span><br><span class="line">        global_queue.messages&amp;#91;i] = global_queue.messages&amp;#91;i + 1];</span><br><span class="line">    &#125;</span><br><span class="line">    global_queue.count--;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示队列状态</span><br><span class="line">void show_queue_status() &#123;</span><br><span class="line">    printf(&quot;\n=== 消息队列状态 ===\n&quot;);</span><br><span class="line">    printf(&quot;队列中消息数量: %d\n&quot;, global_queue.count);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; global_queue.count; i++) &#123;</span><br><span class="line">        printf(&quot;消息 %d: 优先级=%d, 类型=%d, 时间=%s&quot;,</span><br><span class="line">               i, global_queue.messages&amp;#91;i].priority,</span><br><span class="line">               global_queue.messages&amp;#91;i].type,</span><br><span class="line">               ctime(&amp;global_queue.messages&amp;#91;i].timestamp));</span><br><span class="line">        printf(&quot;  控制: %s\n&quot;, global_queue.messages&amp;#91;i].control_data);</span><br><span class="line">        printf(&quot;  数据: %s\n&quot;, global_queue.messages&amp;#91;i].data);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct my_strbuf ctlbuf, databuf;</span><br><span class="line">    char ctl_buffer&amp;#91;256], data_buffer&amp;#91;1024];</span><br><span class="line">    int flags;</span><br><span class="line">    int result;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 完整的 STREAMS 消息系统模拟 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_buffer);</span><br><span class="line">    ctlbuf.buf = ctl_buffer;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buffer);</span><br><span class="line">    databuf.buf = data_buffer;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    // 添加测试消息</span><br><span class="line">    printf(&quot;添加测试消息...\n&quot;);</span><br><span class="line">    add_message(0, MSG_NORMAL, &quot;NORMAL_CTL&quot;, &quot;普通消息数据&quot;);</span><br><span class="line">    add_message(1, MSG_HIGH_PRIORITY, &quot;HIGH_CTL&quot;, &quot;高优先级消息&quot;);</span><br><span class="line">    add_message(0, MSG_DATA, &quot;DATA_CTL&quot;, &quot;另一个普通消息&quot;);</span><br><span class="line">    add_message(1, MSG_CONTROL, &quot;CTRL_CTL&quot;, &quot;高优先级控制消息&quot;);</span><br><span class="line">    </span><br><span class="line">    show_queue_status();</span><br><span class="line">    </span><br><span class="line">    // 测试接收普通消息</span><br><span class="line">    printf(&quot;\n--- 测试1: 接收普通消息 ---\n&quot;);</span><br><span class="line">    flags = 0;  // 普通消息</span><br><span class="line">    result = my_getmsg(&amp;ctlbuf, &amp;databuf, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;成功接收消息:\n&quot;);</span><br><span class="line">        printf(&quot;  控制数据: %.*s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  数据: %.*s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;  优先级: %s\n&quot;, (flags &gt; 0) ? &quot;高&quot; : &quot;普通&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试接收高优先级消息</span><br><span class="line">    printf(&quot;\n--- 测试2: 接收高优先级消息 ---\n&quot;);</span><br><span class="line">    flags = 1;  // 高优先级消息</span><br><span class="line">    result = my_getmsg(&amp;ctlbuf, &amp;databuf, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;成功接收高优先级消息:\n&quot;);</span><br><span class="line">        printf(&quot;  控制数据: %.*s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  数据: %.*s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;  优先级: %s\n&quot;, (flags &gt; 0) ? &quot;高&quot; : &quot;普通&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    show_queue_status();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== STREAMS 概念说明 ===\n&quot;);</span><br><span class="line">    printf(&quot;STREAMS 是 System V 中的消息传递机制\n&quot;);</span><br><span class="line">    printf(&quot;特点:\n&quot;);</span><br><span class="line">    printf(&quot;1. 消息包含控制部分和数据部分\n&quot;);</span><br><span class="line">    printf(&quot;2. 支持消息优先级\n&quot;);</span><br><span class="line">    printf(&quot;3. 模块化处理架构\n&quot;);</span><br><span class="line">    printf(&quot;4. 主要在 Solaris 等系统中使用\n&quot;);</span><br><span class="line">    printf(&quot;\n在 Linux 中，类似功能可通过以下方式实现:\n&quot;);</span><br><span class="line">    printf(&quot;- Unix 域套接字\n&quot;);</span><br><span class="line">    printf(&quot;- 管道和 FIFO\n&quot;);</span><br><span class="line">    printf(&quot;- netlink 套接字\n&quot;);</span><br><span class="line">    printf(&quot;- D-Bus 消息系统\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>编译和运行说明</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># 编译示例程序</span><br><span class="line">gcc -o getmsg_example1 example1.c</span><br><span class="line">gcc -o getmsg_example2 example2.c</span><br><span class="line">gcc -o getmsg_example3 example3.c</span><br><span class="line"></span><br><span class="line"># 运行示例</span><br><span class="line">./getmsg_example1</span><br><span class="line">./getmsg_example2</span><br><span class="line">./getmsg_example3</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>STREAMS 系统检查</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 检查系统是否支持 STREAMS</span><br><span class="line">ls /usr/include/stropts.h</span><br><span class="line"></span><br><span class="line"># 在支持 STREAMS 的系统上编译</span><br><span class="line">gcc -DSTREAMS_AVAILABLE -o getmsg_real example_real.c -lstrmi</span><br><span class="line"></span><br><span class="line"># 查看 STREAMS 相关设备</span><br><span class="line">ls /dev/* | grep stream</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>重要注意事项</p><p>系统支持: getmsg 主要在 System V Unix 系统中可用</p><p>Linux 限制: 大多数 Linux 系统不完全支持 STREAMS</p><p>移植性: 代码可移植性较差</p><p>替代方案: Linux 中可以使用其他 IPC 机制</p><p>错误处理: 始终检查返回值和 errno</p><p>现代 Linux 替代方案</p><h3 id="使用-Unix-域套接字"><a href="#使用-Unix-域套接字" class="headerlink" title="使用 Unix 域套接字"></a>使用 Unix 域套接字</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/socket.h&gt;</span><br><span class="line">#include &lt;sys/un.h&gt;</span><br><span class="line"></span><br><span class="line">// 创建 Unix 域套接字进行消息传递</span><br><span class="line">int create_unix_socket(const char *path) &#123;</span><br><span class="line">    int sock = socket(AF_UNIX, SOCK_STREAM, 0);</span><br><span class="line">    // ... 配置和使用套接字</span><br><span class="line">    return sock;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="使用管道"><a href="#使用管道" class="headerlink" title="使用管道"></a>使用管道</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line"></span><br><span class="line">// 创建管道进行进程间通信</span><br><span class="line">int pipe_fd&amp;#91;2];</span><br><span class="line">if (pipe(pipe_fd) == 0) &#123;</span><br><span class="line">    // 使用 pipe_fd&amp;#91;0] 读取，pipe_fd&amp;#91;1] 写入</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>实际应用场景</p><p>设备驱动: 在某些 Unix 系统中用于设备通信</p><p>网络协议: 实现复杂的网络协议栈</p><p>系统管理: 系统管理工具的消息传递</p><p>模块化处理: 数据流的模块化处理</p><p>STREAMS 架构概念</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">应用程序</span><br><span class="line">    ↓</span><br><span class="line">STREAMS 接口 (putmsg/getmsg)</span><br><span class="line">    ↓</span><br><span class="line">流首部 (Stream Head)</span><br><span class="line">    ↓</span><br><span class="line">模块 1 → 模块 2 → 模块 3</span><br><span class="line">    ↓</span><br><span class="line">驱动程序 (Driver)</span><br><span class="line">    ↓</span><br><span class="line">硬件设备</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>虽然 getmsg 在现代 Linux 系统中使用较少，但了解这个概念有助于理解 Unix 系统的消息传递机制和 STREAMS 架构的设计思想。在实际开发中，建议使用 Linux 原生的 IPC 机制。</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getmsg-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getmsg-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="getmsg-函数详解"><a href="#getmsg-函数详解" class="headerlink" title="getmsg 函数详解"></a>getmsg 函数详解</h1><ol>
<li>函数介绍</li>
</ol>
<p>getmsg 是]]>
    </summary>
    <title>getmsg系统调用及示例</title>
    <updated>2026-06-15T07:56:28.170Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getpeername系统调用及示例</p><p>我们已经介绍了 getsockname，所以接下来应该介绍 getpeername。</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getpeername 是一个 Linux 系统调用，用于获取已连接套接字的对方（peer）的协议地址。这个地址包含了与本端套接字建立连接的那个远程主机的 IP 地址 和 端口号。</p><p>你可以把它想象成查看已接通电话的对方号码：</p><ul><li><p>你和朋友正在通话（套接字已连接）。</p></li><li><p>你想知道现在和你通话的人的电话号码是多少（对方地址）。</p></li><li><p>getpeername 就是查看这个对方号码的功能。</p></li></ul><p>这对于以下场景非常有用：</p><p>服务器: 服务器 accept 一个连接后，得到一个新的已连接套接字。服务器可以使用 getpeername 来获取是哪个客户端（IP 和端口）连接了进来。</p><p>客户端: 客户端在 connect 成功后，可以使用 getpeername 来确认它连接到了哪个服务器地址（IP 和端口），尤其是在连接时使用了域名，想确认解析后的具体 IP。</p><p>调试和日志: 在网络程序中记录连接信息时，getpeername 是获取对端地址的标准方法。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/socket.h&gt; // 必需</span><br><span class="line"></span><br><span class="line">int getpeername(int sockfd, struct sockaddr *addr, socklen_t *addrlen);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><ul><li><p>获取对端地址: 检索与已连接套接字 sockfd 关联的对方协议地址。</p></li><li><p>填充结构体: 将获取到的地址信息填充到调用者提供的 struct sockaddr 结构体指针 addr 所指向的内存中。</p></li><li><p>返回地址大小: 通过 addrlen 参数返回实际存储在 addr 中的地址结构的大小。</p></li></ul><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><p>int sockfd: 这是一个有效的、已连接的套接字文件描述符。</p><ul><li><p>对于 TCP，这意味着已经成功调用了 connect（客户端）或 accept（服务器返回的新套接字）。</p></li><li><p>对于 UDP，如果调用了 connect，也可以使用 getpeername。</p></li><li><p>如果套接字未连接，调用会失败。</p></li></ul><p>struct sockaddr *addr: 这是一个指向套接字地址结构的指针，用于接收对方的地址信息。</p><ul><li>调用者需要提供一个足够大的缓冲区（例如 struct sockaddr_in 或 struct sockaddr_in6）并将其地址传递给 addr。</li></ul><p>socklen_t *addrlen: 这是一个指向 socklen_t 类型变量的指针。</p><ul><li><p>输入: 在调用 getpeername 时，这个变量必须被初始化为 addr 指向的缓冲区的大小（以字节为单位）。例如，如果 addr 指向 struct sockaddr_in，则 *addrlen 应初始化为 sizeof(struct sockaddr_in)。</p></li><li><p>输出: getpeername 返回时，这个变量会被更新为实际存储在 addr 中的地址结构的大小。</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时: 返回 0。同时，addr 指向的结构体被成功填充，*addrlen 被更新为实际地址大小。</p></li><li><p>失败时: 返回 -1，并设置全局变量 errno 来指示具体的错误原因（例如 EBADF sockfd 无效，EINVAL addrlen 指针无效，ENOTSOCK sockfd 不是一个套接字，ENOTCONN 套接字未连接等）。</p></li></ul><h3 id="6-相似函数，或关联函数"><a href="#6-相似函数，或关联函数" class="headerlink" title="6. 相似函数，或关联函数"></a>6. 相似函数，或关联函数</h3><ul><li><p>getsockname: 用于获取本地（本端）套接字的地址信息。</p></li><li><p>connect: 客户端使用此函数连接到服务器。连接成功后，可以使用 getpeername 获取服务器地址。</p></li><li><p>accept: 服务器使用此函数接受客户端连接，返回一个已连接的新套接字，可以使用 getpeername 获取客户端地址。</p></li><li><p>socket: 创建套接字。</p></li></ul><h3 id="7-示例代码"><a href="#7-示例代码" class="headerlink" title="7. 示例代码"></a>7. 示例代码</h3><h4 id="示例-1：客户端使用-getpeername-确认服务器地址"><a href="#示例-1：客户端使用-getpeername-确认服务器地址" class="headerlink" title="示例 1：客户端使用 getpeername 确认服务器地址"></a>示例 1：客户端使用 getpeername 确认服务器地址</h4><p>这个例子演示了 TCP 客户端在连接到服务器后，如何使用 getpeername 来获取它所连接的服务器的地址信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line">// getpeername_client.c</span><br><span class="line">#include &lt;sys/socket.h&gt;</span><br><span class="line">#include &lt;netinet/in.h&gt;</span><br><span class="line">#include &lt;arpa/inet.h&gt; // inet_ntoa, ntohs</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">#define SERVER_PORT 8093</span><br><span class="line">#define SERVER_IP &quot;127.0.0.1&quot; // 可以换成域名测试，如 &quot;localhost&quot;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int sock;</span><br><span class="line">    struct sockaddr_in server_addr, peer_addr;</span><br><span class="line">    socklen_t peer_addr_len = sizeof(peer_addr);</span><br><span class="line"></span><br><span class="line">    sock = socket(AF_INET, SOCK_STREAM, 0);</span><br><span class="line">    if (sock &lt; 0) &#123;</span><br><span class="line">        perror(&quot;socket creation failed&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;Client socket created (fd: %d)\n&quot;, sock);</span><br><span class="line"></span><br><span class="line">    // 配置服务器地址并连接</span><br><span class="line">    memset(&amp;server_addr, 0, sizeof(server_addr));</span><br><span class="line">    server_addr.sin_family = AF_INET;</span><br><span class="line">    server_addr.sin_port = htons(SERVER_PORT);</span><br><span class="line">    if (inet_pton(AF_INET, SERVER_IP, &amp;server_addr.sin_addr) &lt;= 0) &#123;</span><br><span class="line">        fprintf(stderr, &quot;Invalid server address: %s\n&quot;, SERVER_IP);</span><br><span class="line">        close(sock);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Connecting to server %s:%d...\n&quot;, SERVER_IP, SERVER_PORT);</span><br><span class="line">    if (connect(sock, (struct sockaddr *)&amp;server_addr, sizeof(server_addr)) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;connect failed&quot;);</span><br><span class="line">        close(sock);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;Connected to server successfully.\n&quot;);</span><br><span class="line"></span><br><span class="line">    // --- 关键: 使用 getpeername 获取服务器地址 ---</span><br><span class="line">    printf(&quot;\n--- Getting peer (server) name with getpeername ---\n&quot;);</span><br><span class="line">    // 重新初始化长度，以防被修改</span><br><span class="line">    peer_addr_len = sizeof(peer_addr);</span><br><span class="line">    if (getpeername(sock, (struct sockaddr *)&amp;peer_addr, &amp;peer_addr_len) == 0) &#123;</span><br><span class="line">        printf(&quot;Connected to server at:\n&quot;);</span><br><span class="line">        printf(&quot;  Peer IP Address: %s\n&quot;, inet_ntoa(peer_addr.sin_addr));</span><br><span class="line">        printf(&quot;  Peer Port: %d\n&quot;, ntohs(peer_addr.sin_port));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;getpeername failed&quot;);</span><br><span class="line">        // 常见错误：ENOTCONN (如果套接字未连接)</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // (对比) 使用 getsockname 获取自己的本地地址</span><br><span class="line">    struct sockaddr_in local_addr;</span><br><span class="line">    socklen_t local_addr_len = sizeof(local_addr);</span><br><span class="line">    if (getsockname(sock, (struct sockaddr *)&amp;local_addr, &amp;local_addr_len) == 0) &#123;</span><br><span class="line">        printf(&quot;\nMy local address is:\n&quot;);</span><br><span class="line">        printf(&quot;  Local IP Address: %s\n&quot;, inet_ntoa(local_addr.sin_addr));</span><br><span class="line">        printf(&quot;  Local Port: %d\n&quot;, ntohs(local_addr.sin_port));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;getsockname failed&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;\nClient is connected and verified peer/local addresses.\n&quot;);</span><br><span class="line"></span><br><span class="line">    // ... 进行通信 ...</span><br><span class="line"></span><br><span class="line">    close(sock);</span><br><span class="line">    printf(&quot;Client socket closed.\n&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>创建 TCP 套接字。</p><p>配置服务器地址并调用 connect 连接。</p><p>关键步骤: 连接成功后，调用 getpeername(sock, (struct sockaddr *)&amp;peer_addr, &amp;peer_addr_len)。</p><ul><li><p>sock: 已连接的套接字。</p></li><li><p>&amp;peer_addr: 指向用于存储对端地址的 sockaddr_in 结构的指针。</p></li><li><p>&amp;peer_addr_len: 指向 socklen_t 变量的指针，初始化为 sizeof(peer_addr)。</p></li></ul><p>getpeername 成功后，打印出服务器的地址（IP 和端口）。</p><p>对比: 调用 getsockname 获取自己的本地地址。</p><p>最后关闭套接字。</p><h4 id="示例-2：服务器使用-getpeername-获取客户端地址"><a href="#示例-2：服务器使用-getpeername-获取客户端地址" class="headerlink" title="示例 2：服务器使用 getpeername 获取客户端地址"></a>示例 2：服务器使用 getpeername 获取客户端地址</h4><p>这个例子演示了 TCP 服务器在 accept 一个连接后，如何使用 getpeername 来获取连接进来的客户端的地址信息。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br></pre></td><td class="code"><pre><span class="line">// getpeername_server.c</span><br><span class="line">#include &lt;sys/socket.h&gt;</span><br><span class="line">#include &lt;netinet/in.h&gt;</span><br><span class="line">#include &lt;arpa/inet.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">#define PORT 8093</span><br><span class="line">#define BACKLOG 10</span><br><span class="line"></span><br><span class="line">void handle_client(int client_fd) &#123;</span><br><span class="line">    struct sockaddr_in peer_addr;</span><br><span class="line">    socklen_t peer_addr_len = sizeof(peer_addr);</span><br><span class="line"></span><br><span class="line">    printf(&quot;Handling new client connection (fd: %d)\n&quot;, client_fd);</span><br><span class="line"></span><br><span class="line">    // --- 关键: 使用 getpeername 获取客户端地址 ---</span><br><span class="line">    if (getpeername(client_fd, (struct sockaddr *)&amp;peer_addr, &amp;peer_addr_len) == 0) &#123;</span><br><span class="line">        printf(&quot;  Client connected from: %s:%d\n&quot;,</span><br><span class="line">               inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getpeername on client socket failed&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 为了演示，我们立即关闭连接</span><br><span class="line">    // 实际应用中，这里会进行数据读写</span><br><span class="line">    close(client_fd);</span><br><span class="line">    printf(&quot;  Closed connection to client.\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int server_fd, client_fd;</span><br><span class="line">    struct sockaddr_in address;</span><br><span class="line">    socklen_t client_addr_len;</span><br><span class="line">    struct sockaddr_in client_address;</span><br><span class="line">    int opt = 1;</span><br><span class="line"></span><br><span class="line">    server_fd = socket(AF_INET, SOCK_STREAM, 0);</span><br><span class="line">    if (server_fd == 0) &#123;</span><br><span class="line">        perror(&quot;socket failed&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &amp;opt, sizeof(opt))) &#123;</span><br><span class="line">        perror(&quot;setsockopt failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    memset(&amp;address, 0, sizeof(address));</span><br><span class="line">    address.sin_family = AF_INET;</span><br><span class="line">    address.sin_addr.s_addr = INADDR_ANY;</span><br><span class="line">    address.sin_port = htons(PORT);</span><br><span class="line"></span><br><span class="line">    if (bind(server_fd, (struct sockaddr *)&amp;address, sizeof(address)) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;bind failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if (listen(server_fd, BACKLOG) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;listen failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Server listening on port %d\n&quot;, PORT);</span><br><span class="line"></span><br><span class="line">    // 演示接受几个连接</span><br><span class="line">    for (int i = 0; i &lt; 3; ++i) &#123;</span><br><span class="line">        printf(&quot;\n--- Waiting for connection #%d ---\n&quot;, i + 1);</span><br><span class="line">        client_addr_len = sizeof(client_address);</span><br><span class="line">        client_fd = accept(server_fd, (struct sockaddr *)&amp;client_address, &amp;client_addr_len);</span><br><span class="line">        if (client_fd &lt; 0) &#123;</span><br><span class="line">            perror(&quot;accept failed&quot;);</span><br><span class="line">            continue;</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        printf(&quot;New connection accepted (fd: %d)\n&quot;, client_fd);</span><br><span class="line">        // accept 返回的 client_fd 已经包含了客户端地址信息，</span><br><span class="line">        // 我们也可以用 getpeername 再次确认</span><br><span class="line">        handle_client(client_fd);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    close(server_fd);</span><br><span class="line">    printf(&quot;Server socket closed.\n&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>如何测试:</p><p>在一个终端编译并运行服务器：gcc -o getpeername_server getpeername_server.c .&#x2F;getpeername_server</p><p>在另外几个终端运行客户端（可以多次运行）：gcc -o getpeername_client getpeername_client.c .&#x2F;getpeername_client</p><p>代码解释:</p><p>创建、绑定、监听标准的 TCP 服务器套接字。</p><p>进入一个循环，accept 三个客户端连接。</p><p>每次 accept 成功后，调用 handle_client(client_fd)。</p><p>在 handle_client 函数中：</p><ul><li><p>关键步骤: 调用 getpeername(client_fd, …)。</p></li><li><p>client_fd 是 accept 返回的、与特定客户端关联的已连接套接字。</p></li><li><p>getpeername 会返回该客户端的 IP 地址和端口号。</p></li><li><p>打印出客户端的地址信息。</p></li></ul><p>函数结束时关闭与该客户端的连接。</p><h4 id="示例-3：对比-getsockname-和-getpeername"><a href="#示例-3：对比-getsockname-和-getpeername" class="headerlink" title="示例 3：对比 getsockname 和 getpeername"></a>示例 3：对比 getsockname 和 getpeername</h4><p>这个例子在一个已连接的套接字上同时使用 getsockname 和 getpeername，清晰地展示它们的区别。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><span class="line">// compare_sock_peer_name.c</span><br><span class="line">#include &lt;sys/socket.h&gt;</span><br><span class="line">#include &lt;netinet/in.h&gt;</span><br><span class="line">#include &lt;arpa/inet.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">#define SERVER_PORT 8094</span><br><span class="line">#define SERVER_IP &quot;127.0.0.1&quot;</span><br><span class="line"></span><br><span class="line">void print_socket_addresses(int sock, const char* role) &#123;</span><br><span class="line">    struct sockaddr_in local_addr, peer_addr;</span><br><span class="line">    socklen_t addr_len;</span><br><span class="line"></span><br><span class="line">    printf(&quot;--- Addresses for %s socket (fd: %d) ---\n&quot;, role, sock);</span><br><span class="line"></span><br><span class="line">    // 获取本地地址</span><br><span class="line">    addr_len = sizeof(local_addr);</span><br><span class="line">    if (getsockname(sock, (struct sockaddr *)&amp;local_addr, &amp;addr_len) == 0) &#123;</span><br><span class="line">        printf(&quot;  Local Address : %s:%d\n&quot;,</span><br><span class="line">               inet_ntoa(local_addr.sin_addr), ntohs(local_addr.sin_port));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getsockname failed&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 获取对端地址</span><br><span class="line">    addr_len = sizeof(peer_addr);</span><br><span class="line">    if (getpeername(sock, (struct sockaddr *)&amp;peer_addr, &amp;addr_len) == 0) &#123;</span><br><span class="line">        printf(&quot;  Peer Address  : %s:%d\n&quot;,</span><br><span class="line">               inet_ntoa(peer_addr.sin_addr), ntohs(peer_addr.sin_port));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getpeername failed&quot;);</span><br><span class="line">        // 如果套接字未连接，会打印错误，如 &quot;Transport endpoint is not connected&quot;</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;----------------------------------------\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int server_fd, client_sock;</span><br><span class="line">    struct sockaddr_in server_addr, client_addr;</span><br><span class="line">    socklen_t client_addr_len = sizeof(client_addr);</span><br><span class="line">    int opt = 1;</span><br><span class="line"></span><br><span class="line">    // --- 服务器端 ---</span><br><span class="line">    server_fd = socket(AF_INET, SOCK_STREAM, 0);</span><br><span class="line">    if (server_fd == 0) &#123;</span><br><span class="line">        perror(&quot;server socket failed&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &amp;opt, sizeof(opt))) &#123;</span><br><span class="line">        perror(&quot;server setsockopt failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    memset(&amp;server_addr, 0, sizeof(server_addr));</span><br><span class="line">    server_addr.sin_family = AF_INET;</span><br><span class="line">    server_addr.sin_addr.s_addr = INADDR_ANY;</span><br><span class="line">    server_addr.sin_port = htons(SERVER_PORT);</span><br><span class="line"></span><br><span class="line">    if (bind(server_fd, (struct sockaddr *)&amp;server_addr, sizeof(server_addr)) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;server bind failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if (listen(server_fd, 5) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;server listen failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Server listening on port %d\n&quot;, PORT);</span><br><span class="line"></span><br><span class="line">    // --- 客户端 ---</span><br><span class="line">    client_sock = socket(AF_INET, SOCK_STREAM, 0);</span><br><span class="line">    if (client_sock &lt; 0) &#123;</span><br><span class="line">        perror(&quot;client socket failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    memset(&amp;client_addr, 0, sizeof(client_addr));</span><br><span class="line">    client_addr.sin_family = AF_INET;</span><br><span class="line">    client_addr.sin_port = htons(SERVER_PORT);</span><br><span class="line">    if (inet_pton(AF_INET, SERVER_IP, &amp;client_addr.sin_addr) &lt;= 0) &#123;</span><br><span class="line">        fprintf(stderr, &quot;Invalid server IP\n&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        close(client_sock);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;\nClient connecting to server...\n&quot;);</span><br><span class="line">    if (connect(client_sock, (struct sockaddr *)&amp;client_addr, sizeof(client_addr)) &lt; 0) &#123;</span><br><span class="line">        perror(&quot;client connect failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        close(client_sock);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // --- 连接建立后，检查客户端套接字 ---</span><br><span class="line">    print_socket_addresses(client_sock, &quot;Client&quot;);</span><br><span class="line"></span><br><span class="line">    // --- 服务器接受连接 ---</span><br><span class="line">    int accepted_sock = accept(server_fd, NULL, NULL); // 忽略客户端地址</span><br><span class="line">    if (accepted_sock &lt; 0) &#123;</span><br><span class="line">        perror(&quot;server accept failed&quot;);</span><br><span class="line">        close(server_fd);</span><br><span class="line">        close(client_sock);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // --- 检查服务器端的已连接套接字 ---</span><br><span class="line">    print_socket_addresses(accepted_sock, &quot;Server-Accepted&quot;);</span><br><span class="line"></span><br><span class="line">    // 客户端和服务器的本地地址应该等于对方的对端地址</span><br><span class="line">    printf(&quot;\nNote:\n&quot;);</span><br><span class="line">    printf(&quot;- Client&#x27;s Local Address should equal Server&#x27;s Peer Address.\n&quot;);</span><br><span class="line">    printf(&quot;- Server&#x27;s Local Address should equal Client&#x27;s Peer Address.\n&quot;);</span><br><span class="line"></span><br><span class="line">    close(client_sock);</span><br><span class="line">    close(accepted_sock);</span><br><span class="line">    close(server_fd);</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>程序同时扮演服务器和客户端的角色。</p><p>设置服务器套接字并开始监听。</p><p>创建客户端套接字并连接到服务器。</p><p>定义一个 print_socket_addresses 函数，它接受一个套接字和一个角色名称（“Client” 或 “Server-Accepted”）。</p><p>在该函数内部：</p><ul><li><p>调用 getsockname 获取并打印本地地址。</p></li><li><p>调用 getpeername 获取并打印对端地址。</p></li></ul><p>在 main 函数中：</p><ul><li><p>客户端连接成功后，调用 print_socket_addresses(client_sock, “Client”)。</p></li><li><p>服务器 accept 连接后，调用 print_socket_addresses(accepted_sock, “Server-Accepted”)。</p></li></ul><p>通过打印的地址可以清楚地看到：</p><ul><li><p>客户端的本地地址 &#x3D;&#x3D; 服务器 accept 套接字的对端地址。</p></li><li><p>服务器的本地地址 &#x3D;&#x3D; 客户端的对端地址。</p></li></ul><h3 id="重要提示与注意事项"><a href="#重要提示与注意事项" class="headerlink" title="重要提示与注意事项:"></a>重要提示与注意事项:</h3><p>仅对已连接套接字有效: getpeername 只能用于已连接的套接字。对于未连接的套接字（如刚创建的套接字，或未 connect 的 UDP 套接字），调用会失败，errno 通常为 ENOTCONN。</p><p>区分 getsockname 和 getpeername:</p><ul><li><p>getsockname: 获取本地地址（我的地址）。</p></li><li><p>getpeername: 获取对端地址（对方的地址）。</p></li></ul><p>addrlen 的初始化: 与 getsockname 一样，在调用前，必须将 *addrlen 初始化为目标缓冲区的大小。调用后，它会被更新为实际的地址结构大小。</p><p>服务器常用: 服务器在 accept 后，经常使用 getpeername 来记录或显示是哪个客户端连接了进来。</p><p>客户端确认: 客户端可以用它来确认连接的服务器地址，尤其是在使用域名时。</p><p>错误处理: 始终检查返回值。最常见的错误是 ENOTCONN（套接字未连接）。</p><p>总结:</p><p>getpeername 是一个用于获取已连接套接字对端地址信息的系统调用。它与 getsockname 相辅相成，分别用于查询连接两端的地址。在服务器记录客户端信息和客户端确认服务器信息等场景中非常有用。理解其参数和使用条件对于进行有效的网络编程至关重要。</p><p><a href="https://blog.csdn.net/zidier215/article/details/151373575?sharetype=blogdetail&sharerId=151373575&sharerefer=PC&sharesource=zidier215&spm=1011.2480.3001.8118">https://blog.csdn.net/zidier215/article/details/151373575?sharetype=blogdetail&amp;sharerId=151373575&amp;sharerefer=PC&amp;sharesource=zidier215&amp;spm=1011.2480.3001.8118</a></p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getpeername-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getpeername-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getpeername系统调用及示例</p>
<p>我们已经介绍了 getsockname，所以接下来应该介绍 getpeername。</p>
<h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函]]>
    </summary>
    <title>getpeername系统调用及示例</title>
    <updated>2026-06-15T07:56:28.171Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getppid - 获取父进程ID</p><p>getppid是Linux系统调用，用于获取当前进程的父进程ID（PPID）。该函数无需参数，总是成功返回父进程ID，在进程管理和监控中非常有用。示例代码展示了基础用法、父子进程关系、孤儿进程现象以及构建进程树结构，通过getpid()、fork()等相关函数配合使用，可完整呈现Unix&#x2F;Linux的进程层级关系。当父进程终止后，子进程PPID会变为1（init进程），成为孤儿进程。</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getppid 是一个 Linux 系统调用，用于获取当前进程的父进程 ID（Parent Process ID）。每个进程（除了初始进程）都有一个父进程，父进程 ID 是进程管理、进程监控和进程间通信的重要信息。</p><p>在 Unix&#x2F;Linux 系统中，进程以树状结构组织，getppid 提供了访问这种父子关系的方法，对于进程监控、调试和管理工具非常有用。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line"></span><br><span class="line">pid_t getppid(void);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><p>返回当前进程的父进程 ID。这是一个只读操作，不会修改任何系统状态。</p><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><ul><li>无参数</li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时：返回父进程 ID（pid_t 类型）</p></li><li><p>不会失败：该系统调用总是成功返回</p></li></ul><h3 id="6-相似函数，或关联函数"><a href="#6-相似函数，或关联函数" class="headerlink" title="6. 相似函数，或关联函数"></a>6. 相似函数，或关联函数</h3><ul><li><p>getpid(): 获取当前进程 ID</p></li><li><p>getpgid(): 获取进程组 ID</p></li><li><p>getpgrp(): 获取进程组 ID（当前进程）</p></li><li><p>getsid(): 获取会话 ID</p></li><li><p>fork(): 创建新进程</p></li><li><p>wait(), waitpid(): 等待子进程</p></li><li><p>kill(): 向进程发送信号</p></li><li><p>prctl(): 进程控制</p></li><li><p>&#x2F;proc&#x2F;[pid]&#x2F;stat: 查看进程状态信息</p></li></ul><h3 id="7-示例代码"><a href="#7-示例代码" class="headerlink" title="7. 示例代码"></a>7. 示例代码</h3><h4 id="示例1：基本使用-获取进程父子关系"><a href="#示例1：基本使用-获取进程父子关系" class="headerlink" title="示例1：基本使用 - 获取进程父子关系"></a>示例1：基本使用 - 获取进程父子关系</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    pid_t my_pid, parent_pid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程父子关系信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取当前进程 ID</span><br><span class="line">    my_pid = getpid();</span><br><span class="line">    printf(&quot;当前进程 ID: %d\n&quot;, my_pid);</span><br><span class="line">    </span><br><span class="line">    // 获取父进程 ID</span><br><span class="line">    parent_pid = getppid();</span><br><span class="line">    printf(&quot;父进程 ID: %d\n&quot;, parent_pid);</span><br><span class="line">    </span><br><span class="line">    // 获取父进程的父进程 ID（祖父进程）</span><br><span class="line">    // 注意：我们无法直接获取祖父进程 ID，需要通过其他方式</span><br><span class="line">    </span><br><span class="line">    printf(&quot;进程关系: %d -&gt; %d (父 -&gt; 子)\n&quot;, parent_pid, my_pid);</span><br><span class="line">    </span><br><span class="line">    // 检查特殊情况</span><br><span class="line">    if (parent_pid == 1) &#123;</span><br><span class="line">        printf(&quot;注意: 父进程是 init 进程 (PID 1)\n&quot;);</span><br><span class="line">    &#125; else if (parent_pid == 0) &#123;</span><br><span class="line">        printf(&quot;注意: 父进程是调度进程 (内核进程)\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：父子进程关系演示"><a href="#示例2：父子进程关系演示" class="headerlink" title="示例2：父子进程关系演示"></a>示例2：父子进程关系演示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;sys/wait.h&gt;</span><br><span class="line"></span><br><span class="line">void print_process_info(const char *label) &#123;</span><br><span class="line">    printf(&quot;%s:\n&quot;, label);</span><br><span class="line">    printf(&quot;  进程 ID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;  进程组 ID: %d\n&quot;, getpgrp());</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    pid_t child_pid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 父子进程关系演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 显示父进程信息</span><br><span class="line">    print_process_info(&quot;父进程（创建子进程前）&quot;);</span><br><span class="line">    </span><br><span class="line">    // 创建子进程</span><br><span class="line">    child_pid = fork();</span><br><span class="line">    </span><br><span class="line">    if (child_pid == -1) &#123;</span><br><span class="line">        perror(&quot;fork 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (child_pid == 0) &#123;</span><br><span class="line">        // 子进程</span><br><span class="line">        print_process_info(&quot;子进程&quot;);</span><br><span class="line">        </span><br><span class="line">        // 子进程睡眠一段时间</span><br><span class="line">        printf(&quot;子进程睡眠 3 秒...\n&quot;);</span><br><span class="line">        sleep(3);</span><br><span class="line">        </span><br><span class="line">        // 再次检查父进程 ID（父进程可能已经结束）</span><br><span class="line">        printf(&quot;子进程睡眠结束，再次检查父进程 ID:\n&quot;);</span><br><span class="line">        printf(&quot;  当前进程 ID: %d\n&quot;, getpid());</span><br><span class="line">        printf(&quot;  父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">        </span><br><span class="line">        if (getppid() == 1) &#123;</span><br><span class="line">            printf(&quot;  父进程已结束，现在由 init 进程收养\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        // 父进程</span><br><span class="line">        printf(&quot;父进程创建了子进程，子进程 ID: %d\n&quot;, child_pid);</span><br><span class="line">        print_process_info(&quot;父进程（创建子进程后）&quot;);</span><br><span class="line">        </span><br><span class="line">        // 父进程立即结束</span><br><span class="line">        printf(&quot;父进程即将结束...\n&quot;);</span><br><span class="line">        exit(0);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：孤儿进程演示"><a href="#示例3：孤儿进程演示" class="headerlink" title="示例3：孤儿进程演示"></a>示例3：孤儿进程演示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;sys/wait.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    pid_t child_pid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 孤儿进程演示 ===\n&quot;);</span><br><span class="line">    printf(&quot;父进程 ID: %d\n&quot;, getpid());</span><br><span class="line">    </span><br><span class="line">    child_pid = fork();</span><br><span class="line">    </span><br><span class="line">    if (child_pid == -1) &#123;</span><br><span class="line">        perror(&quot;fork 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (child_pid == 0) &#123;</span><br><span class="line">        // 子进程</span><br><span class="line">        printf(&quot;子进程启动，PID: %d, PPID: %d\n&quot;, getpid(), getppid());</span><br><span class="line">        </span><br><span class="line">        // 子进程循环检查父进程状态</span><br><span class="line">        for (int i = 0; i &lt; 10; i++) &#123;</span><br><span class="line">            printf(&quot;子进程 %d: 父进程 ID = %d\n&quot;, getpid(), getppid());</span><br><span class="line">            sleep(2);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        printf(&quot;子进程 %d 结束\n&quot;, getpid());</span><br><span class="line">        </span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        // 父进程</span><br><span class="line">        printf(&quot;父进程创建了子进程 %d\n&quot;, child_pid);</span><br><span class="line">        printf(&quot;父进程即将结束，子进程将成为孤儿进程\n&quot;);</span><br><span class="line">        </span><br><span class="line">        // 父进程很快结束</span><br><span class="line">        sleep(1);</span><br><span class="line">        printf(&quot;父进程 %d 结束\n&quot;, getpid());</span><br><span class="line">        exit(0);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：进程树构建和分析"><a href="#示例4：进程树构建和分析" class="headerlink" title="示例4：进程树构建和分析"></a>示例4：进程树构建和分析</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;sys/wait.h&gt;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    pid_t pid;</span><br><span class="line">    pid_t ppid;</span><br><span class="line">    pid_t pgid;</span><br><span class="line">    int generation;</span><br><span class="line">    char name&amp;#91;32];</span><br><span class="line">&#125; process_info_t;</span><br><span class="line"></span><br><span class="line">void collect_process_info(process_info_t *info, int generation, const char *name) &#123;</span><br><span class="line">    info-&gt;pid = getpid();</span><br><span class="line">    info-&gt;ppid = getppid();</span><br><span class="line">    info-&gt;pgid = getpgrp();</span><br><span class="line">    info-&gt;generation = generation;</span><br><span class="line">    snprintf(info-&gt;name, sizeof(info-&gt;name), &quot;%s&quot;, name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_process_tree(process_info_t *processes, int count) &#123;</span><br><span class="line">    printf(&quot;\n=== 进程树结构 ===\n&quot;);</span><br><span class="line">    printf(&quot;%-8s %-8s %-8s %-12s %s\n&quot;, &quot;PID&quot;, &quot;PPID&quot;, &quot;PGID&quot;, &quot;代数&quot;, &quot;名称&quot;);</span><br><span class="line">    printf(&quot;%-8s %-8s %-8s %-12s %s\n&quot;, &quot;---&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; count; i++) &#123;</span><br><span class="line">        printf(&quot;%-8d %-8d %-8d %-12d %s\n&quot;,</span><br><span class="line">               processes&amp;#91;i].pid,</span><br><span class="line">               processes&amp;#91;i].ppid,</span><br><span class="line">               processes&amp;#91;i].pgid,</span><br><span class="line">               processes&amp;#91;i].generation,</span><br><span class="line">               processes&amp;#91;i].name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    pid_t pid1, pid2, pid3;</span><br><span class="line">    process_info_t processes&amp;#91;4];</span><br><span class="line">    int process_count = 0;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 复杂进程树演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 收集根进程信息</span><br><span class="line">    collect_process_info(&amp;processes&amp;#91;process_count++], 0, &quot;根进程&quot;);</span><br><span class="line">    </span><br><span class="line">    // 创建第一层子进程</span><br><span class="line">    pid1 = fork();</span><br><span class="line">    if (pid1 == 0) &#123;</span><br><span class="line">        // 第一个子进程</span><br><span class="line">        collect_process_info(&amp;processes&amp;#91;process_count++], 1, &quot;子进程1&quot;);</span><br><span class="line">        </span><br><span class="line">        // 第一个子进程创建孙子进程</span><br><span class="line">        pid2 = fork();</span><br><span class="line">        if (pid2 == 0) &#123;</span><br><span class="line">            // 孙子进程1</span><br><span class="line">            collect_process_info(&amp;processes&amp;#91;process_count++], 2, &quot;孙子进程1&quot;);</span><br><span class="line">            sleep(3);</span><br><span class="line">            exit(0);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 第一个子进程再创建另一个孙子进程</span><br><span class="line">        pid3 = fork();</span><br><span class="line">        if (pid3 == 0) &#123;</span><br><span class="line">            // 孙子进程2</span><br><span class="line">            collect_process_info(&amp;processes&amp;#91;process_count++], 2, &quot;孙子进程2&quot;);</span><br><span class="line">            sleep(3);</span><br><span class="line">            exit(0);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 等待孙子进程结束</span><br><span class="line">        wait(NULL);</span><br><span class="line">        wait(NULL);</span><br><span class="line">        exit(0);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 等待第一层子进程结束</span><br><span class="line">    wait(NULL);</span><br><span class="line">    </span><br><span class="line">    // 在实际应用中，这里需要通过 IPC 机制收集所有进程信息</span><br><span class="line">    // 这里为了演示，只显示当前进程信息</span><br><span class="line">    printf(&quot;当前进程信息:\n&quot;);</span><br><span class="line">    printf(&quot;  PID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  PPID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;  PGID: %d\n&quot;, getpgrp());</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例5：进程监控和管理工具"><a href="#示例5：进程监控和管理工具" class="headerlink" title="示例5：进程监控和管理工具"></a>示例5：进程监控和管理工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;signal.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 检查父进程是否还存在</span><br><span class="line">int is_parent_alive() &#123;</span><br><span class="line">    pid_t ppid = getppid();</span><br><span class="line">    </span><br><span class="line">    // 特殊情况：父进程是 init (PID 1) 或内核进程 (PID 0)</span><br><span class="line">    if (ppid == 1 || ppid == 0) &#123;</span><br><span class="line">        return 1;  // 认为父进程&quot;存在&quot;（虽然可能已结束）</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 尝试向父进程发送 0 信号来检查是否存在</span><br><span class="line">    if (kill(ppid, 0) == 0) &#123;</span><br><span class="line">        return 1;  // 父进程存在</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        if (errno == ESRCH) &#123;</span><br><span class="line">            return 0;  // 父进程不存在</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            return 1;  // 其他错误，假设父进程存在</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 监控父进程状态</span><br><span class="line">void monitor_parent_status() &#123;</span><br><span class="line">    pid_t original_ppid = getppid();</span><br><span class="line">    pid_t current_ppid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;开始监控父进程状态...\n&quot;);</span><br><span class="line">    printf(&quot;原始父进程 ID: %d\n&quot;, original_ppid);</span><br><span class="line">    </span><br><span class="line">    while (1) &#123;</span><br><span class="line">        current_ppid = getppid();</span><br><span class="line">        </span><br><span class="line">        if (current_ppid != original_ppid) &#123;</span><br><span class="line">            printf(&quot;父进程 ID 发生变化: %d -&gt; %d\n&quot;, original_ppid, current_ppid);</span><br><span class="line">            </span><br><span class="line">            if (current_ppid == 1) &#123;</span><br><span class="line">                printf(&quot;进程已被 init 进程收养\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            original_ppid = current_ppid;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        if (!is_parent_alive()) &#123;</span><br><span class="line">            printf(&quot;检测到父进程可能已结束\n&quot;);</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        sleep(1);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 守护进程检查</span><br><span class="line">int is_daemon_process() &#123;</span><br><span class="line">    pid_t ppid = getppid();</span><br><span class="line">    </span><br><span class="line">    // 守护进程的特征</span><br><span class="line">    if (ppid == 1) &#123;</span><br><span class="line">        return 1;  // 由 init 进程管理</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否在后台运行</span><br><span class="line">    if (getpgrp() != tcgetpgrp(STDIN_FILENO)) &#123;</span><br><span class="line">        return 1;  // 不在前台进程组</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 进程状态监控工具 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;当前进程信息:\n&quot;);</span><br><span class="line">    printf(&quot;  PID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  PPID: %d\n&quot;, getppid());</span><br><span class="line">    printf(&quot;  PGID: %d\n&quot;, getpgrp());</span><br><span class="line">    </span><br><span class="line">    // 检查是否为守护进程</span><br><span class="line">    if (is_daemon_process()) &#123;</span><br><span class="line">        printf(&quot;✓ 当前进程是守护进程或后台进程\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;✗ 当前进程是前台进程\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查父进程状态</span><br><span class="line">    if (is_parent_alive()) &#123;</span><br><span class="line">        printf(&quot;✓ 父进程存在\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;✗ 父进程不存在\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 如果需要，可以启动监控</span><br><span class="line">    char choice;</span><br><span class="line">    printf(&quot;\n是否启动父进程监控? (y/N): &quot;);</span><br><span class="line">    if (scanf(&quot;%c&quot;, &amp;choice) == 1 &amp;&amp; (choice == &#x27;y&#x27; || choice == &#x27;Y&#x27;)) &#123;</span><br><span class="line">        monitor_parent_status();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="8-特殊父进程-ID"><a href="#8-特殊父进程-ID" class="headerlink" title="8. 特殊父进程 ID"></a>8. 特殊父进程 ID</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">// 特殊的父进程 ID 值</span><br><span class="line">if (ppid == 0) &#123;</span><br><span class="line">    // 内核进程或调度进程</span><br><span class="line">    printf(&quot;父进程是内核进程\n&quot;);</span><br><span class="line">&#125; else if (ppid == 1) &#123;</span><br><span class="line">    // init 进程或 systemd</span><br><span class="line">    printf(&quot;父进程是 init 进程\n&quot;);</span><br><span class="line">&#125; else if (ppid == getppid()) &#123;</span><br><span class="line">    // 自己是父进程（不太可能）</span><br><span class="line">    printf(&quot;异常：自己是自己的父进程\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-实际应用场景"><a href="#9-实际应用场景" class="headerlink" title="9. 实际应用场景"></a>9. 实际应用场景</h3><h4 id="场景1：守护进程实现"><a href="#场景1：守护进程实现" class="headerlink" title="场景1：守护进程实现"></a>场景1：守护进程实现</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">void create_daemon() &#123;</span><br><span class="line">    pid_t pid = fork();</span><br><span class="line">    if (pid == 0) &#123;</span><br><span class="line">        // 第一次 fork 的子进程</span><br><span class="line">        setsid();  // 创建新会话</span><br><span class="line">        </span><br><span class="line">        pid = fork();</span><br><span class="line">        if (pid == 0) &#123;</span><br><span class="line">            // 第二次 fork 的子进程（真正的守护进程）</span><br><span class="line">            // 检查父进程是否为 init</span><br><span class="line">            if (getppid() == 1) &#123;</span><br><span class="line">                printf(&quot;成功创建守护进程\n&quot;);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            exit(0);  // 第一次 fork 的子进程退出</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        wait(NULL);  // 等待第一次 fork 的子进程退出</span><br><span class="line">        exit(0);     // 父进程退出</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：进程监控"><a href="#场景2：进程监控" class="headerlink" title="场景2：进程监控"></a>场景2：进程监控</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">int monitor_process_tree(pid_t target_pid) &#123;</span><br><span class="line">    // 实现进程树监控逻辑</span><br><span class="line">    pid_t current_ppid = getppid();</span><br><span class="line">    // ... 监控逻辑</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：安全检查"><a href="#场景3：安全检查" class="headerlink" title="场景3：安全检查"></a>场景3：安全检查</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">int check_parent_process() &#123;</span><br><span class="line">    pid_t ppid = getppid();</span><br><span class="line">    </span><br><span class="line">    // 检查父进程是否为预期的进程</span><br><span class="line">    if (ppid != expected_parent_pid) &#123;</span><br><span class="line">        syslog(LOG_WARNING, &quot;父进程异常: %d&quot;, ppid);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-注意事项"><a href="#10-注意事项" class="headerlink" title="10. 注意事项"></a>10. 注意事项</h3><p>使用 getppid 时需要注意：</p><p>孤儿进程: 父进程结束后，子进程被 init 进程收养（PPID 变为 1）</p><p>竞态条件: 父进程可能在检查期间结束</p><p>权限问题: 通常可以访问父进程信息，但在某些安全环境中可能受限</p><p>跨平台兼容: 在所有 Unix-like 系统中都可用</p><p>性能考虑: 调用成本很低，可以频繁使用</p><h3 id="11-进程生命周期中的变化"><a href="#11-进程生命周期中的变化" class="headerlink" title="11. 进程生命周期中的变化"></a>11. 进程生命周期中的变化</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">// 进程生命周期中 PPID 的变化示例</span><br><span class="line">void demonstrate_ppid_changes() &#123;</span><br><span class="line">    printf(&quot;进程生命周期 PPID 变化:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    pid_t original_ppid = getppid();</span><br><span class="line">    printf(&quot;1. 启动时 PPID: %d\n&quot;, original_ppid);</span><br><span class="line">    </span><br><span class="line">    // fork 后子进程的 PPID</span><br><span class="line">    pid_t child = fork();</span><br><span class="line">    if (child == 0) &#123;</span><br><span class="line">        printf(&quot;2. 子进程 PPID: %d\n&quot;, getppid());</span><br><span class="line">        // 如果父进程结束，PPID 会变为 1</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getppid 是一个简单但重要的系统调用，用于获取当前进程的父进程 ID。关键要点：</p><ol><li>总是成功: 不会失败，总是返回父进程 ID2. 进程管理: 是进程管理和监控的基础信息3. 孤儿处理: 理解父进程结束后的孤儿进程处理机制4. 安全相关: 可用于进程身份验证和安全检查5. 系统工具: 广泛用于 ps、top 等系统工具</li></ol><p>在编写需要了解进程关系的程序时，getppid 是必不可少的工具函数，它为程序提供了进程层次结构的重要信息。</p><p>getppid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getppid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getppid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getppid - 获取父进程ID</p>
<p>getppid是Linux系统调用，用于获取当前进程的父进程ID（PPID）。该函数无需参数，总是成功返回父进程ID，在进程管理和监控中非常有用。示例代码展示了基础用法、父子进程关系、孤儿进程现象以及构建进程树结构，通过ge]]>
    </summary>
    <title>getppid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.171Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="getpmsg-函数详解"><a href="#getpmsg-函数详解" class="headerlink" title="getpmsg 函数详解"></a>getpmsg 函数详解</h1><ol><li>函数介绍</li></ol><p>getpmsg 是 System V STREAMS 接口中的一个函数，用于从 STREAMS 设备或管道中接收带优先级的消息。可以把 STREAMS 想象成一个”智能分拣系统”——消息根据优先级被分类处理，getpmsg 就是从这个系统中按指定优先级取下消息的工具。</p><p>与 getmsg 不同，getpmsg 提供了更精细的优先级控制，允许你指定要接收的消息类型（普通优先级、高优先级等），就像邮件分拣系统可以按紧急程度分拣邮件一样。</p><p>getpmsg 是 System V STREAMS 接口中的函数，用于从 STREAMS 设备接收带优先级的消息。该函数允许按优先级(band)接收消息，支持多种接收模式(MSG_HIPRI&#x2F;MSG_ANY&#x2F;MSG_BAND)。参数包括文件描述符、控制&#x2F;数据缓冲区结构(strbuf)以及优先级&#x2F;标志指针。函数返回0表示成功，-1表示失败并设置errno。示例代码展示了基础用法和模拟实现，但需注意Linux系统对STREAMS的支持有限。关联函数包括putpmsg、getmsg等，常用于消息优先级处理场景。</p><ol start="2"><li>函数原型</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stropts.h&gt;</span><br><span class="line"></span><br><span class="line">int getpmsg(int fildes, struct strbuf *ctlptr, struct strbuf *dataptr, </span><br><span class="line">            int *bandp, int *flagsp);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>功能</li></ol><p>getpmsg 函数用于从 STREAMS 文件描述符中接收带优先级的消息。它可以接收指定优先级（band）的消息，并且可以控制接收行为。</p><ol start="4"><li>参数</li></ol><ul><li><p>fildes: STREAMS 设备或管道的文件描述符</p></li><li><p>ctlptr: 指向 strbuf 结构体的指针，用于接收控制信息</p></li><li><p>dataptr: 指向 strbuf 结构体的指针，用于接收数据信息</p></li><li><p>bandp: 指向优先级（band）的指针</p></li><li><p>flagsp: 指向标志的指针，用于指定接收模式和返回消息类型</p></li></ul><ol start="5"><li>strbuf 结构体</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">struct strbuf &#123;</span><br><span class="line">    int     maxlen;    /* 缓冲区最大长度 */</span><br><span class="line">    int     len;       /* 实际数据长度 */</span><br><span class="line">    char    *buf;      /* 指向缓冲区的指针 */</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="6"><li>band 和 flags 参数说明</li></ol><h3 id="band-参数（优先级）"><a href="#band-参数（优先级）" class="headerlink" title="band 参数（优先级）"></a>band 参数（优先级）</h3><ul><li><p>0-255: 消息优先级级别，数值越高优先级越高</p></li><li><p>用于区分不同类型的消息</p></li></ul><h3 id="flags-参数（输入标志）"><a href="#flags-参数（输入标志）" class="headerlink" title="flags 参数（输入标志）"></a>flags 参数（输入标志）</h3><ul><li><p>MSG_HIPRI: 接收高优先级消息</p></li><li><p>MSG_ANY: 接收任何优先级的消息</p></li><li><p>MSG_BAND: 接收指定优先级的消息</p></li></ul><h3 id="flags-参数（输出标志）"><a href="#flags-参数（输出标志）" class="headerlink" title="flags 参数（输出标志）"></a>flags 参数（输出标志）</h3><ul><li><p>MSG_HIPRI: 接收到高优先级消息</p></li><li><p>MSG_BAND: 接收到指定优先级消息</p></li><li><p>MSG_MORECTL: 控制部分还有更多数据</p></li><li><p>MSG_MOREDATA: 数据部分还有更多数据</p></li></ul><ol start="7"><li>返回值</li></ol><ul><li><p>成功: 返回 0</p></li><li><p>失败: 返回 -1，并设置相应的 errno 错误码</p></li></ul><p>常见错误码：</p><ul><li><p>EBADF: fildes 不是有效的文件描述符</p></li><li><p>EINVAL: 参数无效</p></li><li><p>EIO: I&#x2F;O 错误</p></li><li><p>ENOSTR: fildes 不是 STREAMS 设备</p></li><li><p>ENOSR: 没有足够的 STREAMS 资源</p></li><li><p>EAGAIN: 非阻塞模式下无数据可读</p></li></ul><ol start="8"><li>相似函数或关联函数</li></ol><ul><li><p>putpmsg: 发送带优先级的消息</p></li><li><p>getmsg: 获取普通消息（不区分优先级）</p></li><li><p>putmsg: 发送普通消息</p></li><li><p>ioctl: 控制 STREAMS 设备</p></li><li><p>poll&#x2F;select: 检查 STREAMS 文件描述符状态</p></li></ul><ol start="9"><li>示例代码</li></ol><h3 id="示例1：基础用法-简单的优先级消息接收"><a href="#示例1：基础用法-简单的优先级消息接收" class="headerlink" title="示例1：基础用法 - 简单的优先级消息接收"></a>示例1：基础用法 - 简单的优先级消息接收</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stropts.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line"></span><br><span class="line">// 注意：这个示例在大多数 Linux 系统上可能无法运行</span><br><span class="line">// 因为 Linux 不完全支持 STREAMS</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    struct strbuf ctlbuf, databuf;</span><br><span class="line">    char ctl_data&amp;#91;256], data_buf&amp;#91;1024];</span><br><span class="line">    int band, flags;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== getpmsg 基础示例 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区结构</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_data);</span><br><span class="line">    ctlbuf.buf = ctl_data;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buf);</span><br><span class="line">    databuf.buf = data_buf;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    band = 0;   // 优先级</span><br><span class="line">    flags = 0;  // 接收标志</span><br><span class="line">    </span><br><span class="line">    printf(&quot;注意: getpmsg 主要用于 STREAMS 系统\n&quot;);</span><br><span class="line">    printf(&quot;在大多数 Linux 系统上可能不可用\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;参数设置:\n&quot;);</span><br><span class="line">    printf(&quot;  控制缓冲区最大长度: %d\n&quot;, ctlbuf.maxlen);</span><br><span class="line">    printf(&quot;  数据缓冲区最大长度: %d\n&quot;, databuf.maxlen);</span><br><span class="line">    printf(&quot;  优先级 (band): %d\n&quot;, band);</span><br><span class="line">    printf(&quot;  标志: %d\n&quot;, flags);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n如果在支持 STREAMS 的系统上，可以这样调用:\n&quot;);</span><br><span class="line">    printf(&quot;result = getpmsg(fd, &amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例2：模拟-STREAMS-优先级消息处理"><a href="#示例2：模拟-STREAMS-优先级消息处理" class="headerlink" title="示例2：模拟 STREAMS 优先级消息处理"></a>示例2：模拟 STREAMS 优先级消息处理</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">// 模拟的 STREAMS 消息结构</span><br><span class="line">struct simulated_pmsg &#123;</span><br><span class="line">    int band;              // 消息优先级 (0-255)</span><br><span class="line">    int control_len;       // 控制数据长度</span><br><span class="line">    char control_data&amp;#91;256]; // 控制数据</span><br><span class="line">    int data_len;          // 数据长度</span><br><span class="line">    char data&amp;#91;1024];       // 实际数据</span><br><span class="line">    time_t timestamp;      // 时间戳</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 模拟的消息队列</span><br><span class="line">struct priority_message_queue &#123;</span><br><span class="line">    int count;</span><br><span class="line">    struct simulated_pmsg messages&amp;#91;20];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 全局消息队列</span><br><span class="line">struct priority_message_queue msg_queue = &#123;0&#125;;</span><br><span class="line"></span><br><span class="line">// 模拟的 strbuf 结构</span><br><span class="line">struct simulated_strbuf &#123;</span><br><span class="line">    int maxlen;</span><br><span class="line">    int len;</span><br><span class="line">    char *buf;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 标志定义（模拟）</span><br><span class="line">#define MSG_HIPRI     0x01</span><br><span class="line">#define MSG_ANY       0x02</span><br><span class="line">#define MSG_BAND      0x04</span><br><span class="line">#define MSG_MORECTL   0x08</span><br><span class="line">#define MSG_MOREDATA  0x10</span><br><span class="line"></span><br><span class="line">// 向队列添加优先级消息</span><br><span class="line">int add_priority_message(int band, const char *control, const char *data) &#123;</span><br><span class="line">    if (msg_queue.count &gt;= 20) &#123;</span><br><span class="line">        printf(&quot;消息队列已满\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int index = msg_queue.count++;</span><br><span class="line">    msg_queue.messages&amp;#91;index].band = band;</span><br><span class="line">    msg_queue.messages&amp;#91;index].timestamp = time(NULL);</span><br><span class="line">    </span><br><span class="line">    if (control) &#123;</span><br><span class="line">        msg_queue.messages&amp;#91;index].control_len = strlen(control) + 1;</span><br><span class="line">        strncpy(msg_queue.messages&amp;#91;index].control_data, control, 255);</span><br><span class="line">        msg_queue.messages&amp;#91;index].control_data&amp;#91;255] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        msg_queue.messages&amp;#91;index].control_len = 0;</span><br><span class="line">        msg_queue.messages&amp;#91;index].control_data&amp;#91;0] = &#x27;\0&#x27;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (data) &#123;</span><br><span class="line">        msg_queue.messages&amp;#91;index].data_len = strlen(data) + 1;</span><br><span class="line">        strncpy(msg_queue.messages&amp;#91;index].data, data, 1023);</span><br><span class="line">        msg_queue.messages&amp;#91;index].data&amp;#91;1023] = &#x27;\0&#x27;;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        msg_queue.messages&amp;#91;index].data_len = 0;</span><br><span class="line">        msg_queue.messages&amp;#91;index].data&amp;#91;0] = &#x27;\0&#x27;;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;添加优先级消息: band=%d, 控制=&#x27;%s&#x27;, 数据=&#x27;%s&#x27;\n&quot;,</span><br><span class="line">           band, control ? control : &quot;无&quot;, data ? data : &quot;无&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 模拟的 getpmsg 实现</span><br><span class="line">int simulated_getpmsg(struct simulated_strbuf *ctlptr,</span><br><span class="line">                      struct simulated_strbuf *dataptr,</span><br><span class="line">                      int *bandp, int *flagsp) &#123;</span><br><span class="line">    </span><br><span class="line">    if (msg_queue.count == 0) &#123;</span><br><span class="line">        printf(&quot;消息队列为空\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int msg_index = -1;</span><br><span class="line">    int target_band = *bandp;</span><br><span class="line">    int flags = *flagsp;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;查找消息: band=%d, flags=0x%x\n&quot;, target_band, flags);</span><br><span class="line">    </span><br><span class="line">    // 根据标志查找消息</span><br><span class="line">    if (flags &amp; MSG_HIPRI) &#123;</span><br><span class="line">        // 查找最高优先级消息</span><br><span class="line">        int max_band = -1;</span><br><span class="line">        for (int i = 0; i &lt; msg_queue.count; i++) &#123;</span><br><span class="line">            if (msg_queue.messages&amp;#91;i].band &gt; max_band) &#123;</span><br><span class="line">                max_band = msg_queue.messages&amp;#91;i].band;</span><br><span class="line">                msg_index = i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;查找最高优先级消息: band=%d\n&quot;, max_band);</span><br><span class="line">    &#125;</span><br><span class="line">    else if (flags &amp; MSG_BAND) &#123;</span><br><span class="line">        // 查找指定优先级消息</span><br><span class="line">        for (int i = 0; i &lt; msg_queue.count; i++) &#123;</span><br><span class="line">            if (msg_queue.messages&amp;#91;i].band == target_band) &#123;</span><br><span class="line">                msg_index = i;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;查找指定优先级消息: band=%d\n&quot;, target_band);</span><br><span class="line">    &#125;</span><br><span class="line">    else if (flags &amp; MSG_ANY) &#123;</span><br><span class="line">        // 查找任何消息（通常按顺序）</span><br><span class="line">        msg_index = 0;</span><br><span class="line">        printf(&quot;查找任意消息\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    else &#123;</span><br><span class="line">        // 默认行为：查找最高优先级</span><br><span class="line">        int max_band = -1;</span><br><span class="line">        for (int i = 0; i &lt; msg_queue.count; i++) &#123;</span><br><span class="line">            if (msg_queue.messages&amp;#91;i].band &gt; max_band) &#123;</span><br><span class="line">                max_band = msg_queue.messages&amp;#91;i].band;</span><br><span class="line">                msg_index = i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;默认查找最高优先级消息: band=%d\n&quot;, max_band);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (msg_index == -1) &#123;</span><br><span class="line">        printf(&quot;未找到符合条件的消息\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取消息</span><br><span class="line">    struct simulated_pmsg *msg = &amp;msg_queue.messages&amp;#91;msg_index];</span><br><span class="line">    </span><br><span class="line">    // 复制控制数据</span><br><span class="line">    if (ctlptr &amp;&amp; ctlptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;control_len &lt; ctlptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;control_len : ctlptr-&gt;maxlen;</span><br><span class="line">        memcpy(ctlptr-&gt;buf, msg-&gt;control_data, copy_len);</span><br><span class="line">        ctlptr-&gt;len = copy_len;</span><br><span class="line">        printf(&quot;复制控制数据: %d 字节\n&quot;, copy_len);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 复制数据</span><br><span class="line">    if (dataptr &amp;&amp; dataptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (msg-&gt;data_len &lt; dataptr-&gt;maxlen) ? </span><br><span class="line">                       msg-&gt;data_len : dataptr-&gt;maxlen;</span><br><span class="line">        memcpy(dataptr-&gt;buf, msg-&gt;data, copy_len);</span><br><span class="line">        dataptr-&gt;len = copy_len;</span><br><span class="line">        printf(&quot;复制数据: %d 字节\n&quot;, copy_len);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 更新返回参数</span><br><span class="line">    *bandp = msg-&gt;band;</span><br><span class="line">    *flagsp = (msg-&gt;band &gt; 100) ? MSG_HIPRI : 0;  // 模拟高优先级</span><br><span class="line">    </span><br><span class="line">    // 从队列中移除消息</span><br><span class="line">    for (int i = msg_index; i &lt; msg_queue.count - 1; i++) &#123;</span><br><span class="line">        msg_queue.messages&amp;#91;i] = msg_queue.messages&amp;#91;i + 1];</span><br><span class="line">    &#125;</span><br><span class="line">    msg_queue.count--;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功接收消息: band=%d\n&quot;, *bandp);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示队列状态</span><br><span class="line">void show_priority_queue() &#123;</span><br><span class="line">    printf(&quot;\n=== 优先级消息队列状态 ===\n&quot;);</span><br><span class="line">    printf(&quot;消息数量: %d\n&quot;, msg_queue.count);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; msg_queue.count; i++) &#123;</span><br><span class="line">        printf(&quot;消息 %d: band=%d, 时间=%s&quot;,</span><br><span class="line">               i, msg_queue.messages&amp;#91;i].band,</span><br><span class="line">               ctime(&amp;msg_queue.messages&amp;#91;i].timestamp));</span><br><span class="line">        printf(&quot;  控制: %s\n&quot;, msg_queue.messages&amp;#91;i].control_data);</span><br><span class="line">        printf(&quot;  数据: %s\n&quot;, msg_queue.messages&amp;#91;i].data);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct simulated_strbuf ctlbuf, databuf;</span><br><span class="line">    char ctl_buffer&amp;#91;256], data_buffer&amp;#91;1024];</span><br><span class="line">    int band, flags;</span><br><span class="line">    int result;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== STREAMS 优先级消息处理模拟 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_buffer);</span><br><span class="line">    ctlbuf.buf = ctl_buffer;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buffer);</span><br><span class="line">    databuf.buf = data_buffer;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    // 添加测试消息（不同优先级）</span><br><span class="line">    printf(&quot;添加测试消息...\n&quot;);</span><br><span class="line">    add_priority_message(50, &quot;NORMAL_CTL&quot;, &quot;普通优先级消息&quot;);</span><br><span class="line">    add_priority_message(150, &quot;HIGH_CTL&quot;, &quot;高优先级消息&quot;);</span><br><span class="line">    add_priority_message(25, &quot;LOW_CTL&quot;, &quot;低优先级消息&quot;);</span><br><span class="line">    add_priority_message(200, &quot;CRITICAL_CTL&quot;, &quot;关键优先级消息&quot;);</span><br><span class="line">    add_priority_message(75, &quot;MEDIUM_CTL&quot;, &quot;中等优先级消息&quot;);</span><br><span class="line">    </span><br><span class="line">    show_priority_queue();</span><br><span class="line">    </span><br><span class="line">    // 测试1: 接收最高优先级消息</span><br><span class="line">    printf(&quot;\n--- 测试1: 接收最高优先级消息 ---\n&quot;);</span><br><span class="line">    band = 0;</span><br><span class="line">    flags = MSG_HIPRI;</span><br><span class="line">    result = simulated_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;成功接收最高优先级消息:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制数据: %.*s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  数据: %.*s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;  消息标志: 0x%x\n&quot;, flags);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试2: 接收指定优先级消息</span><br><span class="line">    printf(&quot;\n--- 测试2: 接收指定优先级消息 (band=75) ---\n&quot;);</span><br><span class="line">    band = 75;</span><br><span class="line">    flags = MSG_BAND;</span><br><span class="line">    result = simulated_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;成功接收指定优先级消息:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制数据: %.*s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  数据: %.*s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;  消息标志: 0x%x\n&quot;, flags);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试3: 接收任意消息</span><br><span class="line">    printf(&quot;\n--- 测试3: 接收任意消息 ---\n&quot;);</span><br><span class="line">    band = 0;</span><br><span class="line">    flags = MSG_ANY;</span><br><span class="line">    result = simulated_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;成功接收任意消息:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制数据: %.*s\n&quot;, ctlbuf.len, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  数据: %.*s\n&quot;, databuf.len, databuf.buf);</span><br><span class="line">        printf(&quot;  消息标志: 0x%x\n&quot;, flags);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    show_priority_queue();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 优先级消息概念说明 ===\n&quot;);</span><br><span class="line">    printf(&quot;STREAMS 优先级消息系统:\n&quot;);</span><br><span class="line">    printf(&quot;1. 消息按优先级 (band) 分类\n&quot;);</span><br><span class="line">    printf(&quot;2. 优先级范围: 0-255 (数值越高优先级越高)\n&quot;);</span><br><span class="line">    printf(&quot;3. 可以按优先级选择性接收消息\n&quot;);</span><br><span class="line">    printf(&quot;4. 支持高优先级消息抢占\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例3：完整的优先级消息管理系统"><a href="#示例3：完整的优先级消息管理系统" class="headerlink" title="示例3：完整的优先级消息管理系统"></a>示例3：完整的优先级消息管理系统</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br><span class="line">259</span><br><span class="line">260</span><br><span class="line">261</span><br><span class="line">262</span><br><span class="line">263</span><br><span class="line">264</span><br><span class="line">265</span><br><span class="line">266</span><br><span class="line">267</span><br><span class="line">268</span><br><span class="line">269</span><br><span class="line">270</span><br><span class="line">271</span><br><span class="line">272</span><br><span class="line">273</span><br><span class="line">274</span><br><span class="line">275</span><br><span class="line">276</span><br><span class="line">277</span><br><span class="line">278</span><br><span class="line">279</span><br><span class="line">280</span><br><span class="line">281</span><br><span class="line">282</span><br><span class="line">283</span><br><span class="line">284</span><br><span class="line">285</span><br><span class="line">286</span><br><span class="line">287</span><br><span class="line">288</span><br><span class="line">289</span><br><span class="line">290</span><br><span class="line">291</span><br><span class="line">292</span><br><span class="line">293</span><br><span class="line">294</span><br><span class="line">295</span><br><span class="line">296</span><br><span class="line">297</span><br><span class="line">298</span><br><span class="line">299</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">// 消息类型定义</span><br><span class="line">#define BAND_LOW      25    // 低优先级</span><br><span class="line">#define BAND_NORMAL   50    // 普通优先级</span><br><span class="line">#define BAND_MEDIUM   100   // 中等优先级</span><br><span class="line">#define BAND_HIGH     150   // 高优先级</span><br><span class="line">#define BAND_CRITICAL 200   // 关键优先级</span><br><span class="line"></span><br><span class="line">// 消息队列管理器</span><br><span class="line">struct message_manager &#123;</span><br><span class="line">    int total_messages;</span><br><span class="line">    int processed_messages;</span><br><span class="line">    int dropped_messages;</span><br><span class="line">    struct &#123;</span><br><span class="line">        int band;</span><br><span class="line">        int msg_id;</span><br><span class="line">        char type&amp;#91;32];</span><br><span class="line">        char content&amp;#91;256];</span><br><span class="line">        time_t created_time;</span><br><span class="line">        time_t processed_time;</span><br><span class="line">    &#125; queue&amp;#91;50];</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 全局消息管理器</span><br><span class="line">struct message_manager msg_mgr = &#123;0&#125;;</span><br><span class="line"></span><br><span class="line">// 标志定义</span><br><span class="line">#define MSG_HIPRI     0x01</span><br><span class="line">#define MSG_ANY       0x02</span><br><span class="line">#define MSG_BAND      0x04</span><br><span class="line"></span><br><span class="line">// 模拟的 strbuf 结构</span><br><span class="line">struct stream_buffer &#123;</span><br><span class="line">    int maxlen;</span><br><span class="line">    int len;</span><br><span class="line">    char *buf;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 添加消息到队列</span><br><span class="line">int queue_message(int band, const char *type, const char *content) &#123;</span><br><span class="line">    if (msg_mgr.total_messages &gt;= 50) &#123;</span><br><span class="line">        msg_mgr.dropped_messages++;</span><br><span class="line">        printf(&quot;警告: 消息队列已满，丢弃消息\n&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int index = msg_mgr.total_messages++;</span><br><span class="line">    msg_mgr.queue&amp;#91;index].band = band;</span><br><span class="line">    msg_mgr.queue&amp;#91;index].msg_id = msg_mgr.total_messages;</span><br><span class="line">    strncpy(msg_mgr.queue&amp;#91;index].type, type, 31);</span><br><span class="line">    msg_mgr.queue&amp;#91;index].type&amp;#91;31] = &#x27;\0&#x27;;</span><br><span class="line">    strncpy(msg_mgr.queue&amp;#91;index].content, content, 255);</span><br><span class="line">    msg_mgr.queue&amp;#91;index].content&amp;#91;255] = &#x27;\0&#x27;;</span><br><span class="line">    msg_mgr.queue&amp;#91;index].created_time = time(NULL);</span><br><span class="line">    msg_mgr.queue&amp;#91;index].processed_time = 0;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;入队消息 #%d: band=%d, 类型=%s\n&quot;, </span><br><span class="line">           msg_mgr.queue&amp;#91;index].msg_id, band, type);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 模拟的 getpmsg 实现</span><br><span class="line">int advanced_getpmsg(struct stream_buffer *ctlptr,</span><br><span class="line">                     struct stream_buffer *dataptr,</span><br><span class="line">                     int *bandp, int *flagsp) &#123;</span><br><span class="line">    </span><br><span class="line">    if (msg_mgr.total_messages == 0) &#123;</span><br><span class="line">        return -1;  // 队列为空</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    int msg_index = -1;</span><br><span class="line">    int target_band = *bandp;</span><br><span class="line">    int flags = *flagsp;</span><br><span class="line">    </span><br><span class="line">    // 根据标志选择消息</span><br><span class="line">    if (flags &amp; MSG_HIPRI) &#123;</span><br><span class="line">        // 查找最高优先级消息</span><br><span class="line">        int max_band = -1;</span><br><span class="line">        for (int i = 0; i &lt; msg_mgr.total_messages; i++) &#123;</span><br><span class="line">            if (msg_mgr.queue&amp;#91;i].band &gt; max_band) &#123;</span><br><span class="line">                max_band = msg_mgr.queue&amp;#91;i].band;</span><br><span class="line">                msg_index = i;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    else if (flags &amp; MSG_BAND) &#123;</span><br><span class="line">        // 查找指定优先级消息</span><br><span class="line">        for (int i = 0; i &lt; msg_mgr.total_messages; i++) &#123;</span><br><span class="line">            if (msg_mgr.queue&amp;#91;i].band == target_band) &#123;</span><br><span class="line">                msg_index = i;</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    else &#123;</span><br><span class="line">        // 默认：按顺序处理</span><br><span class="line">        msg_index = 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (msg_index == -1) &#123;</span><br><span class="line">        return -1;  // 未找到消息</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 处理消息</span><br><span class="line">    struct &#123;</span><br><span class="line">        int band;</span><br><span class="line">        int msg_id;</span><br><span class="line">        char type&amp;#91;32];</span><br><span class="line">        char content&amp;#91;256];</span><br><span class="line">        time_t created_time;</span><br><span class="line">        time_t processed_time;</span><br><span class="line">    &#125; *msg = &amp;msg_mgr.queue&amp;#91;msg_index];</span><br><span class="line">    </span><br><span class="line">    msg-&gt;processed_time = time(NULL);</span><br><span class="line">    msg_mgr.processed_messages++;</span><br><span class="line">    </span><br><span class="line">    // 准备返回数据</span><br><span class="line">    if (ctlptr &amp;&amp; ctlptr-&gt;buf) &#123;</span><br><span class="line">        char ctl_info&amp;#91;256];</span><br><span class="line">        snprintf(ctl_info, sizeof(ctl_info), </span><br><span class="line">                &quot;MSG_ID=%d,BAND=%d,TYPE=%s&quot;,</span><br><span class="line">                msg-&gt;msg_id, msg-&gt;band, msg-&gt;type);</span><br><span class="line">        </span><br><span class="line">        int copy_len = (strlen(ctl_info) + 1 &lt; ctlptr-&gt;maxlen) ? </span><br><span class="line">                       strlen(ctl_info) + 1 : ctlptr-&gt;maxlen;</span><br><span class="line">        memcpy(ctlptr-&gt;buf, ctl_info, copy_len - 1);</span><br><span class="line">        ctlptr-&gt;buf&amp;#91;copy_len - 1] = &#x27;\0&#x27;;</span><br><span class="line">        ctlptr-&gt;len = copy_len - 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (dataptr &amp;&amp; dataptr-&gt;buf) &#123;</span><br><span class="line">        int copy_len = (strlen(msg-&gt;content) + 1 &lt; dataptr-&gt;maxlen) ? </span><br><span class="line">                       strlen(msg-&gt;content) + 1 : dataptr-&gt;maxlen;</span><br><span class="line">        memcpy(dataptr-&gt;buf, msg-&gt;content, copy_len - 1);</span><br><span class="line">        dataptr-&gt;buf&amp;#91;copy_len - 1] = &#x27;\0&#x27;;</span><br><span class="line">        dataptr-&gt;len = copy_len - 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 更新返回参数</span><br><span class="line">    *bandp = msg-&gt;band;</span><br><span class="line">    *flagsp = (msg-&gt;band &gt;= BAND_HIGH) ? MSG_HIPRI : 0;</span><br><span class="line">    </span><br><span class="line">    // 从队列中移除消息</span><br><span class="line">    for (int i = msg_index; i &lt; msg_mgr.total_messages - 1; i++) &#123;</span><br><span class="line">        msg_mgr.queue&amp;#91;i] = msg_mgr.queue&amp;#91;i + 1];</span><br><span class="line">    &#125;</span><br><span class="line">    msg_mgr.total_messages--;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示系统统计</span><br><span class="line">void show_system_stats() &#123;</span><br><span class="line">    printf(&quot;\n=== 消息系统统计 ===\n&quot;);</span><br><span class="line">    printf(&quot;总消息数: %d\n&quot;, msg_mgr.total_messages);</span><br><span class="line">    printf(&quot;已处理消息: %d\n&quot;, msg_mgr.processed_messages);</span><br><span class="line">    printf(&quot;丢弃消息: %d\n&quot;, msg_mgr.dropped_messages);</span><br><span class="line">    printf(&quot;队列中消息: %d\n&quot;, msg_mgr.total_messages);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示队列内容</span><br><span class="line">void show_queue_contents() &#123;</span><br><span class="line">    printf(&quot;\n=== 队列内容 ===\n&quot;);</span><br><span class="line">    if (msg_mgr.total_messages == 0) &#123;</span><br><span class="line">        printf(&quot;队列为空\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;优先级  ID    类型           内容\n&quot;);</span><br><span class="line">    printf(&quot;-------- ----  -------------- ------------------------\n&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; msg_mgr.total_messages; i++) &#123;</span><br><span class="line">        printf(&quot;%-8d %-4d  %-14s %s\n&quot;,</span><br><span class="line">               msg_mgr.queue&amp;#91;i].band,</span><br><span class="line">               msg_mgr.queue&amp;#91;i].msg_id,</span><br><span class="line">               msg_mgr.queue&amp;#91;i].type,</span><br><span class="line">               msg_mgr.queue&amp;#91;i].content);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 按优先级分类统计</span><br><span class="line">void show_priority_statistics() &#123;</span><br><span class="line">    int band_counts&amp;#91;5] = &#123;0&#125;;  // 低、普通、中等、高、关键</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; msg_mgr.total_messages; i++) &#123;</span><br><span class="line">        int band = msg_mgr.queue&amp;#91;i].band;</span><br><span class="line">        if (band &lt;= BAND_LOW) band_counts&amp;#91;0]++;</span><br><span class="line">        else if (band &lt;= BAND_NORMAL) band_counts&amp;#91;1]++;</span><br><span class="line">        else if (band &lt;= BAND_MEDIUM) band_counts&amp;#91;2]++;</span><br><span class="line">        else if (band &lt;= BAND_HIGH) band_counts&amp;#91;3]++;</span><br><span class="line">        else band_counts&amp;#91;4]++;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 优先级统计 ===\n&quot;);</span><br><span class="line">    printf(&quot;低优先级 (0-25):     %d 条消息\n&quot;, band_counts&amp;#91;0]);</span><br><span class="line">    printf(&quot;普通优先级 (26-50):  %d 条消息\n&quot;, band_counts&amp;#91;1]);</span><br><span class="line">    printf(&quot;中等优先级 (51-100): %d 条消息\n&quot;, band_counts&amp;#91;2]);</span><br><span class="line">    printf(&quot;高优先级 (101-150):  %d 条消息\n&quot;, band_counts&amp;#91;3]);</span><br><span class="line">    printf(&quot;关键优先级 (151-255): %d 条消息\n&quot;, band_counts&amp;#91;4]);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct stream_buffer ctlbuf, databuf;</span><br><span class="line">    char ctl_buffer&amp;#91;256], data_buffer&amp;#91;1024];</span><br><span class="line">    int band, flags;</span><br><span class="line">    int result;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 高级优先级消息管理系统 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始化缓冲区</span><br><span class="line">    ctlbuf.maxlen = sizeof(ctl_buffer);</span><br><span class="line">    ctlbuf.buf = ctl_buffer;</span><br><span class="line">    ctlbuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    databuf.maxlen = sizeof(data_buffer);</span><br><span class="line">    databuf.buf = data_buffer;</span><br><span class="line">    databuf.len = 0;</span><br><span class="line">    </span><br><span class="line">    // 添加各种优先级的消息</span><br><span class="line">    printf(&quot;初始化消息队列...\n&quot;);</span><br><span class="line">    queue_message(BAND_CRITICAL, &quot;ALERT&quot;, &quot;系统紧急告警：磁盘空间不足&quot;);</span><br><span class="line">    queue_message(BAND_HIGH, &quot;ERROR&quot;, &quot;应用程序错误：数据库连接失败&quot;);</span><br><span class="line">    queue_message(BAND_MEDIUM, &quot;WARNING&quot;, &quot;系统警告：CPU使用率过高&quot;);</span><br><span class="line">    queue_message(BAND_NORMAL, &quot;INFO&quot;, &quot;用户登录成功&quot;);</span><br><span class="line">    queue_message(BAND_LOW, &quot;DEBUG&quot;, &quot;调试信息：函数调用跟踪&quot;);</span><br><span class="line">    queue_message(BAND_CRITICAL, &quot;ALERT&quot;, &quot;安全告警：多次登录失败&quot;);</span><br><span class="line">    queue_message(BAND_HIGH, &quot;ERROR&quot;, &quot;网络错误：连接超时&quot;);</span><br><span class="line">    queue_message(BAND_MEDIUM, &quot;NOTICE&quot;, &quot;系统通知：配置文件已更新&quot;);</span><br><span class="line">    </span><br><span class="line">    show_system_stats();</span><br><span class="line">    show_queue_contents();</span><br><span class="line">    show_priority_statistics();</span><br><span class="line">    </span><br><span class="line">    // 处理消息的示例</span><br><span class="line">    printf(&quot;\n=== 消息处理演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 1. 处理最高优先级消息</span><br><span class="line">    printf(&quot;\n--- 处理最高优先级消息 ---\n&quot;);</span><br><span class="line">    band = 0;</span><br><span class="line">    flags = MSG_HIPRI;</span><br><span class="line">    result = advanced_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;处理成功:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制信息: %s\n&quot;, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  消息内容: %s\n&quot;, databuf.buf);</span><br><span class="line">        printf(&quot;  消息标志: %s\n&quot;, (flags &amp; MSG_HIPRI) ? &quot;高优先级&quot; : &quot;普通优先级&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 2. 处理指定优先级消息</span><br><span class="line">    printf(&quot;\n--- 处理中等优先级消息 ---\n&quot;);</span><br><span class="line">    band = BAND_MEDIUM;</span><br><span class="line">    flags = MSG_BAND;</span><br><span class="line">    result = advanced_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;处理成功:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制信息: %s\n&quot;, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  消息内容: %s\n&quot;, databuf.buf);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 3. 处理任意消息</span><br><span class="line">    printf(&quot;\n--- 处理任意消息 ---\n&quot;);</span><br><span class="line">    band = 0;</span><br><span class="line">    flags = MSG_ANY;</span><br><span class="line">    result = advanced_getpmsg(&amp;ctlbuf, &amp;databuf, &amp;band, &amp;flags);</span><br><span class="line">    </span><br><span class="line">    if (result == 0) &#123;</span><br><span class="line">        printf(&quot;处理成功:\n&quot;);</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, band);</span><br><span class="line">        printf(&quot;  控制信息: %s\n&quot;, ctlbuf.buf);</span><br><span class="line">        printf(&quot;  消息内容: %s\n&quot;, databuf.buf);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 显示处理后的状态</span><br><span class="line">    show_system_stats();</span><br><span class="line">    show_queue_contents();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== STREAMS 优先级消息系统特点 ===\n&quot;);</span><br><span class="line">    printf(&quot;1. 支持 0-255 级优先级\n&quot;);</span><br><span class="line">    printf(&quot;2. 可以按优先级选择性接收消息\n&quot;);</span><br><span class="line">    printf(&quot;3. 高优先级消息可以抢占处理\n&quot;);</span><br><span class="line">    printf(&quot;4. 适用于实时系统和关键任务应用\n&quot;);</span><br><span class="line">    printf(&quot;\nLinux 替代方案:\n&quot;);</span><br><span class="line">    printf(&quot;- 实时信号 (RT signals)\n&quot;);</span><br><span class="line">    printf(&quot;- D-Bus 消息系统\n&quot;);</span><br><span class="line">    printf(&quot;- systemd journal\n&quot;);</span><br><span class="line">    printf(&quot;- 自定义优先级队列\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>编译和运行说明</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"># 编译示例程序</span><br><span class="line">gcc -o getpmsg_example1 example1.c</span><br><span class="line">gcc -o getpmsg_example2 example2.c</span><br><span class="line">gcc -o getpmsg_example3 example3.c</span><br><span class="line"></span><br><span class="line"># 运行示例</span><br><span class="line">./getpmsg_example1</span><br><span class="line">./getpmsg_example2</span><br><span class="line">./getpmsg_example3</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>STREAMS 系统检查</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 检查系统是否支持 STREAMS</span><br><span class="line">ls /usr/include/stropts.h</span><br><span class="line"></span><br><span class="line"># 在 Solaris 等系统上编译</span><br><span class="line">gcc -D_SOLARIS -o getpmsg_real example_real.c -lstrmi</span><br><span class="line"></span><br><span class="line"># 查看 STREAMS 相关信息</span><br><span class="line">modinfo | grep stream</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>重要注意事项</p><p>系统支持: getpmsg 主要在 System V Unix 系统中可用</p><p>Linux 限制: 大多数 Linux 系统不完全支持 STREAMS</p><p>移植性: 代码可移植性较差</p><p>优先级范围: band 值范围为 0-255</p><p>错误处理: 始终检查返回值和 errno</p><p>现代 Linux 替代方案</p><h3 id="使用实时信号"><a href="#使用实时信号" class="headerlink" title="使用实时信号"></a>使用实时信号</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;signal.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">// 发送带优先级的实时信号</span><br><span class="line">int send_priority_signal(pid_t pid, int sig, int priority) &#123;</span><br><span class="line">    union sigval value;</span><br><span class="line">    value.sival_int = priority;</span><br><span class="line">    return sigqueue(pid, sig, value);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="使用自定义优先级队列"><a href="#使用自定义优先级队列" class="headerlink" title="使用自定义优先级队列"></a>使用自定义优先级队列</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;pthread.h&gt;</span><br><span class="line">#include &lt;sys/queue.h&gt;</span><br><span class="line"></span><br><span class="line">// 自定义优先级消息队列</span><br><span class="line">struct priority_msg &#123;</span><br><span class="line">    int priority;</span><br><span class="line">    void *data;</span><br><span class="line">    SLIST_ENTRY(priority_msg) entries;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">SLIST_HEAD(msg_head, priority_msg) msg_queue = SLIST_HEAD_INITIALIZER(msg_queue);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>实际应用场景</p><p>实时系统: 需要按优先级处理消息的实时应用</p><p>网络协议: 实现复杂的网络协议栈</p><p>设备驱动: 设备驱动中的消息处理</p><p>系统管理: 系统管理工具的优先级消息</p><p>多媒体应用: 音视频处理中的实时消息</p><p>优先级消息处理流程</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">消息生产者</span><br><span class="line">    ↓ (putpmsg)</span><br><span class="line">STREAMS 系统</span><br><span class="line">    ↓ (按优先级排队)</span><br><span class="line">消息消费者</span><br><span class="line">    ↓ (getpmsg)</span><br><span class="line">应用层处理</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>虽然 getpmsg 在现代 Linux 系统中使用较少，但它体现了优先级消息处理的重要概念。在实际开发中，可以根据需求选择合适的现代替代方案来实现类似的功能。</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getpmsg-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getpmsg-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="getpmsg-函数详解"><a href="#getpmsg-函数详解" class="headerlink" title="getpmsg 函数详解"></a>getpmsg 函数详解</h1><ol>
<li>函数介绍</li>
</ol>
<p>getpm]]>
    </summary>
    <title>getpmsg系统调用及示例</title>
    <updated>2026-06-15T07:56:28.171Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getpriority - 获取进程或进程组的优先级</p><p>getpriority 是 Linux 系统调用，用于查询进程、进程组或用户的调度优先级。优先级范围 -20（最高）到 +19（最低）。函数原型为 int getpriority(int which, id_t who)，参数 which 指定查询类型（PRIO_PROCESS&#x2F;PRIO_PGRP&#x2F;PRIO_USER），who 为对应 ID。成功返回优先级值，失败返回 -1 并设置 errno。需注意返回值可能为 -1（成功时），应先清除 errno 再调用。示例代码展示了如何获取当前进程、进程组和用户的优</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getpriority 是一个 Linux 系统调用，用于获取指定进程或进程组的调度优先级。它是 Unix&#x2F;Linux 系统中进程调度管理的重要组成部分，允许程序查询进程的当前优先级设置。</p><p>在 Linux 系统中，进程优先级影响 CPU 调度，优先级高的进程会获得更多 CPU 时间。getpriority 与 setpriority 配合使用，提供了完整的优先级管理功能。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/resource.h&gt;</span><br><span class="line"></span><br><span class="line">int getpriority(int which, id_t who);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><p>获取指定进程、进程组或用户的所有进程的调度优先级。优先级值范围通常为 -20 到 +19，其中 -20 表示最高优先级，+19 表示最低优先级。</p><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><p>int which: 指定查询的类型</p><ul><li><p>PRIO_PROCESS: 查询单个进程的优先级</p></li><li><p>PRIO_PGRP: 查询进程组中所有进程的优先级</p></li><li><p>PRIO_USER: 查询指定用户的所有进程的优先级</p></li></ul><p>id_t who: 根据 which 参数指定的具体 ID</p><ul><li><p>PRIO_PROCESS: 进程 ID（0 表示当前进程）</p></li><li><p>PRIO_PGRP: 进程组 ID（0 表示当前进程组）</p></li><li><p>PRIO_USER: 用户 ID（0 表示当前用户）</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时：返回优先级值（范围 -20 到 +19）</p></li><li><p>失败时：返回 -1，并设置 errno</p></li><li><p>注意：由于成功时可能返回 -1，需要先清除 errno 再调用</p></li></ul><h3 id="6-常见-errno-错误码"><a href="#6-常见-errno-错误码" class="headerlink" title="6. 常见 errno 错误码"></a>6. 常见 errno 错误码</h3><ul><li><p>ESRCH: 指定的进程、进程组或用户不存在</p></li><li><p>EINVAL: which 参数无效</p></li><li><p>EPERM: 权限不足（无法访问指定进程的信息）</p></li><li><p>EACCES: 访问被拒绝（某些安全策略下）</p></li></ul><h3 id="7-相似函数，或关联函数"><a href="#7-相似函数，或关联函数" class="headerlink" title="7. 相似函数，或关联函数"></a>7. 相似函数，或关联函数</h3><ul><li><p>setpriority(): 设置进程优先级</p></li><li><p>nice(): 调整当前进程的优先级</p></li><li><p>getrlimit(), setrlimit(): 获取&#x2F;设置资源限制</p></li><li><p>sched_getparam(), sched_setparam(): 更高级的调度参数管理</p></li><li><p>sched_getscheduler(), sched_setscheduler(): 获取&#x2F;设置调度策略</p></li><li><p>getrusage(): 获取进程资源使用情况</p></li><li><p>&#x2F;proc&#x2F;[pid]&#x2F;stat: 查看进程状态信息</p></li></ul><h3 id="8-示例代码"><a href="#8-示例代码" class="headerlink" title="8. 示例代码"></a>8. 示例代码</h3><h4 id="示例1：基本使用-获取进程优先级"><a href="#示例1：基本使用-获取进程优先级" class="headerlink" title="示例1：基本使用 - 获取进程优先级"></a>示例1：基本使用 - 获取进程优先级</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/resource.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">int safe_getpriority(int which, id_t who) &#123;</span><br><span class="line">    errno = 0;  // 必须先清除 errno</span><br><span class="line">    int priority = getpriority(which, who);</span><br><span class="line">    if (priority == -1 &amp;&amp; errno != 0) &#123;</span><br><span class="line">        return -1;  // 真正的错误</span><br><span class="line">    &#125;</span><br><span class="line">    return priority;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int priority;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程优先级获取 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取当前进程的优先级</span><br><span class="line">    priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">    if (priority == -1) &#123;</span><br><span class="line">        perror(&quot;获取当前进程优先级失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;当前进程优先级: %d\n&quot;, priority);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取当前进程组的优先级</span><br><span class="line">    priority = safe_getpriority(PRIO_PGRP, 0);</span><br><span class="line">    if (priority == -1) &#123;</span><br><span class="line">        perror(&quot;获取当前进程组优先级失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;当前进程组优先级: %d\n&quot;, priority);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取当前用户的进程优先级</span><br><span class="line">    priority = safe_getpriority(PRIO_USER, 0);</span><br><span class="line">    if (priority == -1) &#123;</span><br><span class="line">        perror(&quot;获取当前用户进程优先级失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;当前用户进程优先级: %d\n&quot;, priority);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取 init 进程的优先级</span><br><span class="line">    priority = safe_getpriority(PRIO_PROCESS, 1);</span><br><span class="line">    if (priority == -1) &#123;</span><br><span class="line">        if (errno == EPERM) &#123;</span><br><span class="line">            printf(&quot;权限不足，无法获取 init 进程优先级\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            perror(&quot;获取 init 进程优先级失败&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;init 进程优先级: %d\n&quot;, priority);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：错误处理和特殊情况"><a href="#示例2：错误处理和特殊情况" class="headerlink" title="示例2：错误处理和特殊情况"></a>示例2：错误处理和特殊情况</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/resource.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;sys/wait.h&gt;</span><br><span class="line"></span><br><span class="line">void test_getpriority(int which, id_t who, const char *description) &#123;</span><br><span class="line">    printf(&quot;\n测试 %s:\n&quot;, description);</span><br><span class="line">    </span><br><span class="line">    errno = 0;  // 清除 errno</span><br><span class="line">    int priority = getpriority(which, who);</span><br><span class="line">    </span><br><span class="line">    if (priority == -1 &amp;&amp; errno != 0) &#123;</span><br><span class="line">        printf(&quot;  getpriority 调用失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        switch (errno) &#123;</span><br><span class="line">            case ESRCH:</span><br><span class="line">                printf(&quot;  原因: 指定的进程/组/用户不存在\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            case EINVAL:</span><br><span class="line">                printf(&quot;  原因: 无效的 which 参数\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            case EPERM:</span><br><span class="line">                printf(&quot;  原因: 权限不足\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            default:</span><br><span class="line">                printf(&quot;  其他错误\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  优先级: %d\n&quot;, priority);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== getpriority 错误处理测试 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试正常情况</span><br><span class="line">    test_getpriority(PRIO_PROCESS, 0, &quot;当前进程&quot;);</span><br><span class="line">    test_getpriority(PRIO_PGRP, 0, &quot;当前进程组&quot;);</span><br><span class="line">    test_getpriority(PRIO_USER, getuid(), &quot;当前用户&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试无效参数</span><br><span class="line">    test_getpriority(999, 0, &quot;无效的 which 参数&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试不存在的进程</span><br><span class="line">    test_getpriority(PRIO_PROCESS, 999999, &quot;不存在的进程&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试不存在的进程组</span><br><span class="line">    test_getpriority(PRIO_PGRP, 999999, &quot;不存在的进程组&quot;);</span><br><span class="line">    </span><br><span class="line">    // 创建子进程进行测试</span><br><span class="line">    pid_t child_pid = fork();</span><br><span class="line">    if (child_pid == -1) &#123;</span><br><span class="line">        perror(&quot;fork 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (child_pid == 0) &#123;</span><br><span class="line">        // 子进程</span><br><span class="line">        printf(&quot;\n=== 子进程信息 ===\n&quot;);</span><br><span class="line">        printf(&quot;子进程 ID: %d\n&quot;, getpid());</span><br><span class="line">        printf(&quot;父进程 ID: %d\n&quot;, getppid());</span><br><span class="line">        </span><br><span class="line">        // 子进程设置自己的优先级</span><br><span class="line">        if (setpriority(PRIO_PROCESS, 0, 10) == 0) &#123;</span><br><span class="line">            printf(&quot;子进程成功设置优先级为 10\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            perror(&quot;子进程设置优先级失败&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 显示子进程优先级</span><br><span class="line">        errno = 0;</span><br><span class="line">        int child_priority = getpriority(PRIO_PROCESS, 0);</span><br><span class="line">        if (!(child_priority == -1 &amp;&amp; errno != 0)) &#123;</span><br><span class="line">            printf(&quot;子进程当前优先级: %d\n&quot;, child_priority);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 子进程睡眠一段时间</span><br><span class="line">        sleep(3);</span><br><span class="line">        exit(0);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        // 父进程</span><br><span class="line">        printf(&quot;\n=== 父进程测试子进程 ===\n&quot;);</span><br><span class="line">        printf(&quot;子进程 ID: %d\n&quot;, child_pid);</span><br><span class="line">        </span><br><span class="line">        // 父进程获取子进程优先级</span><br><span class="line">        test_getpriority(PRIO_PROCESS, child_pid, &quot;子进程（运行中）&quot;);</span><br><span class="line">        </span><br><span class="line">        // 等待子进程结束</span><br><span class="line">        int status;</span><br><span class="line">        waitpid(child_pid, &amp;status, 0);</span><br><span class="line">        printf(&quot;子进程已结束\n&quot;);</span><br><span class="line">        </span><br><span class="line">        // 再次测试已结束的进程</span><br><span class="line">        test_getpriority(PRIO_PROCESS, child_pid, &quot;已结束的子进程&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：优先级监控和管理工具"><a href="#示例3：优先级监控和管理工具" class="headerlink" title="示例3：优先级监控和管理工具"></a>示例3：优先级监控和管理工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/resource.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    pid_t pid;</span><br><span class="line">    int priority;</span><br><span class="line">    char process_name&amp;#91;256];</span><br><span class="line">&#125; process_priority_t;</span><br><span class="line"></span><br><span class="line">int safe_getpriority(int which, id_t who) &#123;</span><br><span class="line">    errno = 0;</span><br><span class="line">    int priority = getpriority(which, who);</span><br><span class="line">    if (priority == -1 &amp;&amp; errno != 0) &#123;</span><br><span class="line">        return -999;  // 特殊错误值</span><br><span class="line">    &#125;</span><br><span class="line">    return priority;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_priority_info(const char *label, int priority) &#123;</span><br><span class="line">    if (priority == -999) &#123;</span><br><span class="line">        printf(&quot;%s: 无法获取\n&quot;, label);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;%s: %d&quot;, label, priority);</span><br><span class="line">        if (priority &lt; 0) &#123;</span><br><span class="line">            printf(&quot; (高优先级)&quot;);</span><br><span class="line">        &#125; else if (priority &gt; 0) &#123;</span><br><span class="line">            printf(&quot; (低优先级)&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot; (正常优先级)&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void analyze_process_priorities() &#123;</span><br><span class="line">    printf(&quot;=== 进程优先级分析 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 当前进程信息</span><br><span class="line">    printf(&quot;当前进程信息:\n&quot;);</span><br><span class="line">    printf(&quot;  PID: %d\n&quot;, getpid());</span><br><span class="line">    printf(&quot;  UID: %d&quot;, getuid());</span><br><span class="line">    struct passwd *pwd = getpwuid(getuid());</span><br><span class="line">    if (pwd) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, pwd-&gt;pw_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;  GID: %d&quot;, getgid());</span><br><span class="line">    struct group *grp = getgrgid(getgid());</span><br><span class="line">    if (grp) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 各种优先级信息</span><br><span class="line">    int current_priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">    print_priority_info(&quot;  当前进程优先级&quot;, current_priority);</span><br><span class="line">    </span><br><span class="line">    int pgrp_priority = safe_getpriority(PRIO_PGRP, 0);</span><br><span class="line">    print_priority_info(&quot;  当前进程组优先级&quot;, pgrp_priority);</span><br><span class="line">    </span><br><span class="line">    int user_priority = safe_getpriority(PRIO_USER, getuid());</span><br><span class="line">    print_priority_info(&quot;  当前用户进程优先级&quot;, user_priority);</span><br><span class="line">    </span><br><span class="line">    // 系统关键进程优先级</span><br><span class="line">    printf(&quot;\n系统关键进程优先级:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    int init_priority = safe_getpriority(PRIO_PROCESS, 1);</span><br><span class="line">    print_priority_info(&quot;  init 进程 (PID 1)&quot;, init_priority);</span><br><span class="line">    </span><br><span class="line">    // 获取 shell 进程优先级</span><br><span class="line">    pid_t shell_pid = getppid();</span><br><span class="line">    int shell_priority = safe_getpriority(PRIO_PROCESS, shell_pid);</span><br><span class="line">    printf(&quot;  父进程 (shell) PID %d&quot;, shell_pid);</span><br><span class="line">    print_priority_info(&quot;&quot;, shell_priority);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void priority_statistics() &#123;</span><br><span class="line">    printf(&quot;\n=== 优先级统计信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取当前用户的进程优先级范围</span><br><span class="line">    int min_priority = 20, max_priority = -20;</span><br><span class="line">    int sum_priority = 0, count = 0;</span><br><span class="line">    </span><br><span class="line">    // 这里简化处理，实际应用中可能需要扫描 /proc</span><br><span class="line">    int current_priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">    if (current_priority != -999) &#123;</span><br><span class="line">        min_priority = max_priority = sum_priority = current_priority;</span><br><span class="line">        count = 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;当前会话优先级统计:\n&quot;);</span><br><span class="line">    printf(&quot;  进程数量: %d\n&quot;, count);</span><br><span class="line">    if (count &gt; 0) &#123;</span><br><span class="line">        printf(&quot;  最低优先级: %d\n&quot;, min_priority);</span><br><span class="line">        printf(&quot;  最高优先级: %d\n&quot;, max_priority);</span><br><span class="line">        printf(&quot;  平均优先级: %.2f\n&quot;, (double)sum_priority / count);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    analyze_process_priorities();</span><br><span class="line">    priority_statistics();</span><br><span class="line">    </span><br><span class="line">    // 交互式优先级查询</span><br><span class="line">    printf(&quot;\n=== 交互式查询 ===\n&quot;);</span><br><span class="line">    printf(&quot;输入进程 ID 查询优先级 (输入 0 退出): &quot;);</span><br><span class="line">    </span><br><span class="line">    pid_t target_pid;</span><br><span class="line">    while (scanf(&quot;%d&quot;, &amp;target_pid) == 1 &amp;&amp; target_pid != 0) &#123;</span><br><span class="line">        if (target_pid &gt; 0) &#123;</span><br><span class="line">            int priority = safe_getpriority(PRIO_PROCESS, target_pid);</span><br><span class="line">            if (priority != -999) &#123;</span><br><span class="line">                printf(&quot;进程 %d 的优先级: %d\n&quot;, target_pid, priority);</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                printf(&quot;无法获取进程 %d 的优先级\n&quot;, target_pid);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        printf(&quot;继续输入进程 ID (输入 0 退出): &quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：优先级调整和监控"><a href="#示例4：优先级调整和监控" class="headerlink" title="示例4：优先级调整和监控"></a>示例4：优先级调整和监控</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/resource.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;signal.h&gt;</span><br><span class="line"></span><br><span class="line">volatile sig_atomic_t running = 1;</span><br><span class="line"></span><br><span class="line">void signal_handler(int sig) &#123;</span><br><span class="line">    running = 0;</span><br><span class="line">    printf(&quot;\n收到信号 %d，停止监控\n&quot;, sig);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int safe_getpriority(int which, id_t who) &#123;</span><br><span class="line">    errno = 0;</span><br><span class="line">    int priority = getpriority(which, who);</span><br><span class="line">    if (priority == -1 &amp;&amp; errno != 0) &#123;</span><br><span class="line">        return -999;</span><br><span class="line">    &#125;</span><br><span class="line">    return priority;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void monitor_priority_changes(pid_t target_pid, int duration) &#123;</span><br><span class="line">    int last_priority = -999;</span><br><span class="line">    time_t start_time = time(NULL);</span><br><span class="line">    time_t current_time;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;开始监控进程 %d 的优先级变化 (%d 秒)...\n&quot;, target_pid, duration);</span><br><span class="line">    printf(&quot;%-10s %-12s %s\n&quot;, &quot;时间&quot;, &quot;优先级&quot;, &quot;状态&quot;);</span><br><span class="line">    printf(&quot;%-10s %-12s %s\n&quot;, &quot;----&quot;, &quot;----&quot;, &quot;----&quot;);</span><br><span class="line">    </span><br><span class="line">    while (running &amp;&amp; (current_time = time(NULL)) - start_time &lt; duration) &#123;</span><br><span class="line">        int current_priority = safe_getpriority(PRIO_PROCESS, target_pid);</span><br><span class="line">        </span><br><span class="line">        if (current_priority != -999) &#123;</span><br><span class="line">            char status&amp;#91;20] = &quot;稳定&quot;;</span><br><span class="line">            </span><br><span class="line">            if (last_priority != -999 &amp;&amp; current_priority != last_priority) &#123;</span><br><span class="line">                snprintf(status, sizeof(status), &quot;变化 %d-&gt;%d&quot;, </span><br><span class="line">                        last_priority, current_priority);</span><br><span class="line">            &#125;</span><br><span class="line">            </span><br><span class="line">            printf(&quot;%-10ld %-12d %s\n&quot;, </span><br><span class="line">                   current_time - start_time, </span><br><span class="line">                   current_priority, </span><br><span class="line">                   status);</span><br><span class="line">            </span><br><span class="line">            last_priority = current_priority;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;%-10ld %-12s %s\n&quot;, </span><br><span class="line">                   current_time - start_time, </span><br><span class="line">                   &quot;无法获取&quot;, </span><br><span class="line">                   &quot;错误&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        sleep(1);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void demonstrate_priority_adjustment() &#123;</span><br><span class="line">    printf(&quot;=== 优先级调整演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    int original_priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">    printf(&quot;原始优先级: %d\n&quot;, original_priority);</span><br><span class="line">    </span><br><span class="line">    // 提高优先级（需要权限）</span><br><span class="line">    printf(&quot;尝试提高优先级到 -5...\n&quot;);</span><br><span class="line">    if (setpriority(PRIO_PROCESS, 0, -5) == 0) &#123;</span><br><span class="line">        int new_priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">        printf(&quot;优先级调整成功: %d\n&quot;, new_priority);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        if (errno == EPERM) &#123;</span><br><span class="line">            printf(&quot;权限不足，无法提高优先级（需要 root 权限）\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            perror(&quot;优先级调整失败&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 降低优先级</span><br><span class="line">    printf(&quot;尝试降低优先级到 10...\n&quot;);</span><br><span class="line">    if (setpriority(PRIO_PROCESS, 0, 10) == 0) &#123;</span><br><span class="line">        int new_priority = safe_getpriority(PRIO_PROCESS, 0);</span><br><span class="line">        printf(&quot;优先级调整成功: %d\n&quot;, new_priority);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;优先级调整失败&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 恢复原始优先级</span><br><span class="line">    if (original_priority != -999) &#123;</span><br><span class="line">        if (setpriority(PRIO_PROCESS, 0, original_priority) == 0) &#123;</span><br><span class="line">            printf(&quot;已恢复原始优先级: %d\n&quot;, </span><br><span class="line">                   safe_getpriority(PRIO_PROCESS, 0));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    signal(SIGINT, signal_handler);</span><br><span class="line">    signal(SIGTERM, signal_handler);</span><br><span class="line">    </span><br><span class="line">    demonstrate_priority_adjustment();</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n当前进程优先级: %d\n&quot;, safe_getpriority(PRIO_PROCESS, 0));</span><br><span class="line">    </span><br><span class="line">    // 如果需要，可以监控优先级变化</span><br><span class="line">    char choice;</span><br><span class="line">    printf(&quot;\n是否监控当前进程优先级变化? (y/N): &quot;);</span><br><span class="line">    getchar();  // 清除缓冲区</span><br><span class="line">    if (scanf(&quot;%c&quot;, &amp;choice) == 1 &amp;&amp; (choice == &#x27;y&#x27; || choice == &#x27;Y&#x27;)) &#123;</span><br><span class="line">        monitor_priority_changes(getpid(), 10);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-优先级值说明"><a href="#9-优先级值说明" class="headerlink" title="9. 优先级值说明"></a>9. 优先级值说明</h3><p>Linux 进程优先级系统：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">// 优先级范围：-20 到 +19</span><br><span class="line">// -20: 最高优先级</span><br><span class="line">// 0:   默认优先级</span><br><span class="line">// +19: 最低优先级</span><br><span class="line"></span><br><span class="line">// 特殊优先级值</span><br><span class="line">#define PRIO_MIN -20</span><br><span class="line">#define PRIO_MAX 19</span><br><span class="line"></span><br><span class="line">// 优先级类别</span><br><span class="line">-20 to -1:  高优先级进程</span><br><span class="line">0:          正常优先级进程</span><br><span class="line">+1 to +19:  低优先级进程</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-实际应用场景"><a href="#10-实际应用场景" class="headerlink" title="10. 实际应用场景"></a>10. 实际应用场景</h3><h4 id="场景1：系统监控工具"><a href="#场景1：系统监控工具" class="headerlink" title="场景1：系统监控工具"></a>场景1：系统监控工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">int is_high_priority_process(pid_t pid) &#123;</span><br><span class="line">    int priority = safe_getpriority(PRIO_PROCESS, pid);</span><br><span class="line">    return (priority != -999 &amp;&amp; priority &lt; 0);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：资源管理"><a href="#场景2：资源管理" class="headerlink" title="场景2：资源管理"></a>场景2：资源管理</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">void adjust_batch_job_priority() &#123;</span><br><span class="line">    // 批处理作业使用较低优先级</span><br><span class="line">    setpriority(PRIO_PROCESS, 0, 15);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：性能优化"><a href="#场景3：性能优化" class="headerlink" title="场景3：性能优化"></a>场景3：性能优化</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">void optimize_critical_process() &#123;</span><br><span class="line">    // 关键进程使用较高优先级</span><br><span class="line">    setpriority(PRIO_PROCESS, 0, -5);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="11-注意事项"><a href="#11-注意事项" class="headerlink" title="11. 注意事项"></a>11. 注意事项</h3><p>使用 getpriority 时的重要注意事项：</p><p>返回值检查: 必须先清除 errno，因为成功时可能返回 -1</p><p>权限问题: 访问其他进程信息可能需要适当权限</p><p>进程生命周期: 进程结束后相关信息可能不可用</p><p>实时性: 优先级可能在查询期间发生变化</p><p>系统限制: 某些优先级值可能需要特殊权限才能设置</p><h3 id="12-优先级与调度策略"><a href="#12-优先级与调度策略" class="headerlink" title="12. 优先级与调度策略"></a>12. 优先级与调度策略</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// 不同调度策略的优先级处理</span><br><span class="line">void explain_scheduling_policies() &#123;</span><br><span class="line">    printf(&quot;Linux 调度策略优先级说明:\n&quot;);</span><br><span class="line">    printf(&quot;1. SCHED_FIFO: 实时优先级 1-99\n&quot;);</span><br><span class="line">    printf(&quot;2. SCHED_RR:   实时优先级 1-99\n&quot;);</span><br><span class="line">    printf(&quot;3. SCHED_OTHER: 静态优先级 -20 到 +19\n&quot;);</span><br><span class="line">    printf(&quot;4. SCHED_BATCH: 批处理优化\n&quot;);</span><br><span class="line">    printf(&quot;5. SCHED_IDLE:  空闲任务\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getpriority 是进程优先级管理的重要函数，关键要点：</p><p>优先级查询: 获取进程、进程组或用户的调度优先级</p><p>错误处理: 特殊的返回值处理机制（需要清除 errno）</p><p>权限控制: 访问其他进程信息需要适当权限</p><p>系统管理: 在系统监控和资源管理中广泛使用</p><p>性能优化: 帮助识别和调整关键进程的优先级</p><p>正确使用 getpriority 可以帮助程序了解当前的调度状态，实现更精细的性能管理和资源控制。</p><p>getpriority系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getpriority-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getpriority-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getpriority - 获取进程或进程组的优先级</p>
<p>getpriority 是 Linux 系统调用，用于查询进程、进程组或用户的调度优先级。优先级范围 -20（最高）到 +19（最低）。函数原型为 int getpriority(int which, id]]>
    </summary>
    <title>getpriority系统调用及示例</title>
    <updated>2026-06-15T07:56:28.171Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<h1 id="getrandom-函数详解"><a href="#getrandom-函数详解" class="headerlink" title="getrandom 函数详解"></a>getrandom 函数详解</h1><p>getrandom是Linux系统中获取高质量随机数的系统调用，从内核熵池中提取真正的随机数据。它比传统rand()更安全可靠，适用于加密、安全令牌等场景。函数原型为ssize_t getrandom(void *buf, size_t buflen, unsigned int flags)，支持GRND_RANDOM（阻塞模式）和GRND_NONBLOCK（非阻塞模式）两种标志位。文章详细介绍了函数参数、返回值、错误处理和示例代码，展示了如何生成随机数据和使用不同标志位。getrandom相比传统随机数设备更安全高效，是安全敏感应用的理想选择。</p><ol><li>函数介绍</li></ol><p>getrandom 是 Linux 系统中用于获取高质量随机数的系统调用。可以把这个函数想象成一个”真随机数生成器”——它从系统的熵池中获取真正的随机数据，就像从大自然的噪声中提取随机性一样。</p><p>在计算机系统中，随机数非常重要：</p><ul><li><p>加密操作: 生成密钥、初始化向量等</p></li><li><p>安全令牌: 会话 ID、验证码等</p></li><li><p>模拟和游戏: 游戏中的随机事件</p></li><li><p>负载均衡: 分布式系统中的随机选择</p></li></ul><p>getrandom 提供了比传统 rand() 函数更安全、更高质量的随机数，特别适合安全相关的应用。</p><ol start="2"><li>函数原型</li></ol><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/random.h&gt;</span><br><span class="line"></span><br><span class="line">ssize_t getrandom(void *buf, size_t buflen, unsigned int flags);</span><br><span class="line"></span><br></pre></td></tr></table></figure><ol start="3"><li>功能</li></ol><p>getrandom 函数用于从内核的随机数生成器中获取随机字节，并将其存储在提供的缓冲区中。它可以直接访问系统的熵源，提供密码学安全的随机数。</p><ol start="4"><li>参数</li></ol><ul><li><p>buf: 指向缓冲区的指针，用于存储生成的随机数据</p></li><li><p>buflen: 请求的随机数据字节数</p></li><li><p>flags: 控制随机数生成行为的标志位</p></li></ul><ol start="5"><li>标志位（flags 参数）</li></ol><p>标志值说明GRND_RANDOM0x0001使用 &#x2F;dev&#x2F;random 而不是 &#x2F;dev&#x2F;urandomGRND_NONBLOCK0x0002非阻塞模式，熵不足时不等待</p><ol start="6"><li>标志位详细说明</li></ol><h3 id="GRND-RANDOM"><a href="#GRND-RANDOM" class="headerlink" title="GRND_RANDOM"></a>GRND_RANDOM</h3><ul><li><p>默认情况下，getrandom 使用 &#x2F;dev&#x2F;urandom（非阻塞）</p></li><li><p>设置此标志后，使用 &#x2F;dev&#x2F;random（阻塞模式）</p></li><li><p>&#x2F;dev&#x2F;random 在熵不足时会阻塞，直到收集到足够熵</p></li></ul><h3 id="GRND-NONBLOCK"><a href="#GRND-NONBLOCK" class="headerlink" title="GRND_NONBLOCK"></a>GRND_NONBLOCK</h3><ul><li><p>默认情况下，如果熵池未初始化，函数会阻塞等待</p></li><li><p>设置此标志后，如果熵不足则立即返回错误（errno &#x3D; EAGAIN）</p></li></ul><ol start="7"><li>返回值</li></ol><ul><li><p>成功: 返回实际获取的随机字节数</p></li><li><p>失败: 返回 -1，并设置相应的 errno 错误码</p></li></ul><p>常见错误码：</p><ul><li><p>EAGAIN: 非阻塞模式下熵不足</p></li><li><p>EFAULT: buf 指针无效</p></li><li><p>EINVAL: flags 参数无效</p></li><li><p>EIO: 系统错误</p></li></ul><ol start="8"><li>相似函数或关联函数</li></ol><ul><li><p>&#x2F;dev&#x2F;random: 传统的阻塞随机数设备</p></li><li><p>&#x2F;dev&#x2F;urandom: 传统的非阻塞随机数设备</p></li><li><p>rand(): 标准库伪随机数生成器</p></li><li><p>random(): 更好的伪随机数生成器</p></li><li><p>arc4random(): BSD 风格的加密安全随机数</p></li><li><p>openssl RAND_bytes(): OpenSSL 库的随机数函数</p></li></ul><ol start="9"><li>示例代码</li></ol><h3 id="示例1：基础用法-生成随机数据"><a href="#示例1：基础用法-生成随机数据" class="headerlink" title="示例1：基础用法 - 生成随机数据"></a>示例1：基础用法 - 生成随机数据</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/random.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 将二进制数据转换为十六进制字符串</span><br><span class="line">void bin_to_hex(const unsigned char *bin, size_t len, char *hex) &#123;</span><br><span class="line">    for (size_t i = 0; i &lt; len; i++) &#123;</span><br><span class="line">        sprintf(hex + i * 2, &quot;%02x&quot;, bin&amp;#91;i]);</span><br><span class="line">    &#125;</span><br><span class="line">    hex&amp;#91;len * 2] = &#x27;\0&#x27;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 将二进制数据转换为可打印字符（用于显示）</span><br><span class="line">void bin_to_printable(const unsigned char *bin, size_t len, char *printable) &#123;</span><br><span class="line">    for (size_t i = 0; i &lt; len; i++) &#123;</span><br><span class="line">        if (bin&amp;#91;i] &gt;= 32 &amp;&amp; bin&amp;#91;i] &lt;= 126) &#123;</span><br><span class="line">            printable&amp;#91;i] = bin&amp;#91;i];</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printable&amp;#91;i] = &#x27;.&#x27;;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    printable&amp;#91;len] = &#x27;\0&#x27;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    unsigned char random_data&amp;#91;32];</span><br><span class="line">    char hex_string&amp;#91;65];</span><br><span class="line">    char printable_string&amp;#91;33];</span><br><span class="line">    ssize_t bytes_read;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== getrandom 基础示例 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 生成 32 字节的随机数据</span><br><span class="line">    printf(&quot;生成 32 字节随机数据...\n&quot;);</span><br><span class="line">    bytes_read = getrandom(random_data, sizeof(random_data), 0);</span><br><span class="line">    </span><br><span class="line">    if (bytes_read == -1) &#123;</span><br><span class="line">        perror(&quot;getrandom&quot;);</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功生成 %zd 字节随机数据\n&quot;, bytes_read);</span><br><span class="line">    </span><br><span class="line">    // 显示十六进制格式</span><br><span class="line">    bin_to_hex(random_data, bytes_read, hex_string);</span><br><span class="line">    printf(&quot;十六进制: %s\n&quot;, hex_string);</span><br><span class="line">    </span><br><span class="line">    // 显示可打印字符格式</span><br><span class="line">    bin_to_printable(random_data, bytes_read, printable_string);</span><br><span class="line">    printf(&quot;可打印: %s\n&quot;, printable_string);</span><br><span class="line">    </span><br><span class="line">    // 生成不同长度的随机数据</span><br><span class="line">    printf(&quot;\n生成不同长度的随机数据:\n&quot;);</span><br><span class="line">    for (int len = 1; len &lt;= 16; len++) &#123;</span><br><span class="line">        unsigned char small_data&amp;#91;16];</span><br><span class="line">        bytes_read = getrandom(small_data, len, 0);</span><br><span class="line">        if (bytes_read &gt; 0) &#123;</span><br><span class="line">            bin_to_hex(small_data, bytes_read, hex_string);</span><br><span class="line">            printf(&quot;  %2d 字节: %s\n&quot;, len, hex_string);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例2：不同标志位的使用"><a href="#示例2：不同标志位的使用" class="headerlink" title="示例2：不同标志位的使用"></a>示例2：不同标志位的使用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/random.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">// 显示随机数据的统计信息</span><br><span class="line">void show_random_stats(const unsigned char *data, size_t len) &#123;</span><br><span class="line">    unsigned long sum = 0;</span><br><span class="line">    for (size_t i = 0; i &lt; len; i++) &#123;</span><br><span class="line">        sum += data&amp;#91;i];</span><br><span class="line">    &#125;</span><br><span class="line">    double average = (double)sum / len;</span><br><span class="line">    printf(&quot;  平均值: %.2f\n&quot;, average);</span><br><span class="line">    printf(&quot;  数据范围: 0x%02x - 0x%02x\n&quot;, </span><br><span class="line">           data&amp;#91;0], data&amp;#91;len-1]);  // 简化的范围显示</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    unsigned char buffer&amp;#91;64];</span><br><span class="line">    ssize_t result;</span><br><span class="line">    struct timespec start, end;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== getrandom 标志位使用示例 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 1. 默认模式（推荐）</span><br><span class="line">    printf(&quot;1. 默认模式 (GRND_URANDOM):\n&quot;);</span><br><span class="line">    clock_gettime(CLOCK_MONOTONIC, &amp;start);</span><br><span class="line">    result = getrandom(buffer, sizeof(buffer), 0);</span><br><span class="line">    clock_gettime(CLOCK_MONOTONIC, &amp;end);</span><br><span class="line">    </span><br><span class="line">    if (result &gt; 0) &#123;</span><br><span class="line">        printf(&quot;  成功获取 %zd 字节随机数据\n&quot;, result);</span><br><span class="line">        printf(&quot;  耗时: %ld 纳秒\n&quot;, </span><br><span class="line">               (end.tv_sec - start.tv_sec) * 1000000000L + </span><br><span class="line">               (end.tv_nsec - start.tv_nsec));</span><br><span class="line">        show_random_stats(buffer, result);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getrandom 失败&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 2. 使用 GRND_RANDOM（阻塞模式）</span><br><span class="line">    printf(&quot;\n2. GRND_RANDOM 模式 (使用 /dev/random):\n&quot;);</span><br><span class="line">    printf(&quot;  注意: 如果熵不足可能会阻塞\n&quot;);</span><br><span class="line">    </span><br><span class="line">    clock_gettime(CLOCK_MONOTONIC, &amp;start);</span><br><span class="line">    result = getrandom(buffer, 16, GRND_RANDOM);</span><br><span class="line">    clock_gettime(CLOCK_MONOTONIC, &amp;end);</span><br><span class="line">    </span><br><span class="line">    if (result &gt; 0) &#123;</span><br><span class="line">        printf(&quot;  成功获取 %zd 字节随机数据\n&quot;, result);</span><br><span class="line">        printf(&quot;  耗时: %ld 纳秒\n&quot;, </span><br><span class="line">               (end.tv_sec - start.tv_sec) * 1000000000L + </span><br><span class="line">               (end.tv_nsec - start.tv_nsec));</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getrandom 失败&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 3. 非阻塞模式</span><br><span class="line">    printf(&quot;\n3. 非阻塞模式 (GRND_NONBLOCK):\n&quot;);</span><br><span class="line">    result = getrandom(buffer, sizeof(buffer), GRND_NONBLOCK);</span><br><span class="line">    </span><br><span class="line">    if (result &gt; 0) &#123;</span><br><span class="line">        printf(&quot;  成功获取 %zd 字节随机数据\n&quot;, result);</span><br><span class="line">    &#125; else if (result == -1 &amp;&amp; errno == EAGAIN) &#123;</span><br><span class="line">        printf(&quot;  熵不足，非阻塞模式下立即返回\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getrandom 失败&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 4. 组合标志</span><br><span class="line">    printf(&quot;\n4. 组合标志 (GRND_RANDOM | GRND_NONBLOCK):\n&quot;);</span><br><span class="line">    result = getrandom(buffer, 16, GRND_RANDOM | GRND_NONBLOCK);</span><br><span class="line">    </span><br><span class="line">    if (result &gt; 0) &#123;</span><br><span class="line">        printf(&quot;  成功获取 %zd 字节随机数据\n&quot;, result);</span><br><span class="line">    &#125; else if (result == -1 &amp;&amp; errno == EAGAIN) &#123;</span><br><span class="line">        printf(&quot;  /dev/random 熵不足，非阻塞模式下立即返回\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        perror(&quot;  getrandom 失败&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 使用建议 ===\n&quot;);</span><br><span class="line">    printf(&quot;1. 一般情况下使用默认模式（flags=0）\n&quot;);</span><br><span class="line">    printf(&quot;2. 加密应用可以考虑 GRND_RANDOM\n&quot;);</span><br><span class="line">    printf(&quot;3. 非阻塞场景使用 GRND_NONBLOCK\n&quot;);</span><br><span class="line">    printf(&quot;4. 避免在循环中频繁调用\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例3：完整的随机数工具"><a href="#示例3：完整的随机数工具" class="headerlink" title="示例3：完整的随机数工具"></a>示例3：完整的随机数工具</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/random.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;getopt.h&gt;</span><br><span class="line"></span><br><span class="line">// 输出格式类型</span><br><span class="line">enum output_format &#123;</span><br><span class="line">    FORMAT_HEX,      // 十六进制</span><br><span class="line">    FORMAT_BASE64,   // Base64</span><br><span class="line">    FORMAT_BINARY,   // 二进制</span><br><span class="line">    FORMAT_DECIMAL   // 十进制</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">// 将二进制数据转换为十六进制</span><br><span class="line">void to_hex(const unsigned char *data, size_t len, char *output) &#123;</span><br><span class="line">    for (size_t i = 0; i &lt; len; i++) &#123;</span><br><span class="line">        sprintf(output + i * 2, &quot;%02x&quot;, data&amp;#91;i]);</span><br><span class="line">    &#125;</span><br><span class="line">    output&amp;#91;len * 2] = &#x27;\0&#x27;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 简化的 Base64 编码（仅用于演示）</span><br><span class="line">void to_base64(const unsigned char *data, size_t len, char *output) &#123;</span><br><span class="line">    const char *base64_chars = </span><br><span class="line">        &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/&quot;;</span><br><span class="line">    </span><br><span class="line">    size_t i = 0, j = 0;</span><br><span class="line">    while (i &lt; len) &#123;</span><br><span class="line">        uint32_t octet_a = i &lt; len ? data&amp;#91;i++] : 0;</span><br><span class="line">        uint32_t octet_b = i &lt; len ? data&amp;#91;i++] : 0;</span><br><span class="line">        uint32_t octet_c = i &lt; len ? data&amp;#91;i++] : 0;</span><br><span class="line">        </span><br><span class="line">        uint32_t triple = (octet_a &lt;&lt; 16) + (octet_b &lt;&lt; 8) + octet_c;</span><br><span class="line">        </span><br><span class="line">        output&amp;#91;j++] = base64_chars&amp;#91;(triple &gt;&gt; 18) &amp; 63];</span><br><span class="line">        output&amp;#91;j++] = base64_chars&amp;#91;(triple &gt;&gt; 12) &amp; 63];</span><br><span class="line">        output&amp;#91;j++] = base64_chars&amp;#91;(triple &gt;&gt; 6) &amp; 63];</span><br><span class="line">        output&amp;#91;j++] = base64_chars&amp;#91;triple &amp; 63];</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 处理填充</span><br><span class="line">    int pad = len % 3;</span><br><span class="line">    if (pad == 1) &#123;</span><br><span class="line">        output&amp;#91;j-2] = &#x27;=&#x27;;</span><br><span class="line">        output&amp;#91;j-1] = &#x27;=&#x27;;</span><br><span class="line">    &#125; else if (pad == 2) &#123;</span><br><span class="line">        output&amp;#91;j-1] = &#x27;=&#x27;;</span><br><span class="line">    &#125;</span><br><span class="line">    output&amp;#91;j] = &#x27;\0&#x27;;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示帮助信息</span><br><span class="line">void show_help(const char *program_name) &#123;</span><br><span class="line">    printf(&quot;用法: %s &amp;#91;选项]\n&quot;, program_name);</span><br><span class="line">    printf(&quot;\n选项:\n&quot;);</span><br><span class="line">    printf(&quot;  -n, --bytes=NUM     生成 NUM 字节的随机数据 (默认 32)\n&quot;);</span><br><span class="line">    printf(&quot;  -f, --format=TYPE   输出格式: hex, base64, binary, decimal\n&quot;);</span><br><span class="line">    printf(&quot;  -r, --random        使用 /dev/random (阻塞模式)\n&quot;);</span><br><span class="line">    printf(&quot;  -b, --non-block     非阻塞模式\n&quot;);</span><br><span class="line">    printf(&quot;  -h, --help          显示此帮助信息\n&quot;);</span><br><span class="line">    printf(&quot;\n输出格式说明:\n&quot;);</span><br><span class="line">    printf(&quot;  hex     - 十六进制字符串\n&quot;);</span><br><span class="line">    printf(&quot;  base64  - Base64 编码\n&quot;);</span><br><span class="line">    printf(&quot;  binary  - 原始二进制数据\n&quot;);</span><br><span class="line">    printf(&quot;  decimal - 十进制数字序列\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main(int argc, char *argv&amp;#91;]) &#123;</span><br><span class="line">    size_t num_bytes = 32;</span><br><span class="line">    enum output_format format = FORMAT_HEX;</span><br><span class="line">    unsigned int flags = 0;</span><br><span class="line">    int c;</span><br><span class="line">    </span><br><span class="line">    // 解析命令行参数</span><br><span class="line">    static struct option long_options&amp;#91;] = &#123;</span><br><span class="line">        &#123;&quot;bytes&quot;,     required_argument, 0, &#x27;n&#x27;&#125;,</span><br><span class="line">        &#123;&quot;format&quot;,    required_argument, 0, &#x27;f&#x27;&#125;,</span><br><span class="line">        &#123;&quot;random&quot;,    no_argument,       0, &#x27;r&#x27;&#125;,</span><br><span class="line">        &#123;&quot;non-block&quot;, no_argument,       0, &#x27;b&#x27;&#125;,</span><br><span class="line">        &#123;&quot;help&quot;,      no_argument,       0, &#x27;h&#x27;&#125;,</span><br><span class="line">        &#123;0, 0, 0, 0&#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    </span><br><span class="line">    while (1) &#123;</span><br><span class="line">        int option_index = 0;</span><br><span class="line">        c = getopt_long(argc, argv, &quot;n:f:rbh&quot;, long_options, &amp;option_index);</span><br><span class="line">        </span><br><span class="line">        if (c == -1)</span><br><span class="line">            break;</span><br><span class="line">            </span><br><span class="line">        switch (c) &#123;</span><br><span class="line">            case &#x27;n&#x27;:</span><br><span class="line">                num_bytes = atoi(optarg);</span><br><span class="line">                if (num_bytes == 0) &#123;</span><br><span class="line">                    fprintf(stderr, &quot;错误: 无效的字节数\n&quot;);</span><br><span class="line">                    return 1;</span><br><span class="line">                &#125;</span><br><span class="line">                break;</span><br><span class="line">                </span><br><span class="line">            case &#x27;f&#x27;:</span><br><span class="line">                if (strcmp(optarg, &quot;hex&quot;) == 0) &#123;</span><br><span class="line">                    format = FORMAT_HEX;</span><br><span class="line">                &#125; else if (strcmp(optarg, &quot;base64&quot;) == 0) &#123;</span><br><span class="line">                    format = FORMAT_BASE64;</span><br><span class="line">                &#125; else if (strcmp(optarg, &quot;binary&quot;) == 0) &#123;</span><br><span class="line">                    format = FORMAT_BINARY;</span><br><span class="line">                &#125; else if (strcmp(optarg, &quot;decimal&quot;) == 0) &#123;</span><br><span class="line">                    format = FORMAT_DECIMAL;</span><br><span class="line">                &#125; else &#123;</span><br><span class="line">                    fprintf(stderr, &quot;错误: 未知的格式 &#x27;%s&#x27;\n&quot;, optarg);</span><br><span class="line">                    return 1;</span><br><span class="line">                &#125;</span><br><span class="line">                break;</span><br><span class="line">                </span><br><span class="line">            case &#x27;r&#x27;:</span><br><span class="line">                flags |= GRND_RANDOM;</span><br><span class="line">                break;</span><br><span class="line">                </span><br><span class="line">            case &#x27;b&#x27;:</span><br><span class="line">                flags |= GRND_NONBLOCK;</span><br><span class="line">                break;</span><br><span class="line">                </span><br><span class="line">            case &#x27;h&#x27;:</span><br><span class="line">                show_help(argv&amp;#91;0]);</span><br><span class="line">                return 0;</span><br><span class="line">                </span><br><span class="line">            case &#x27;?&#x27;:</span><br><span class="line">                return 1;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分配缓冲区</span><br><span class="line">    unsigned char *buffer = malloc(num_bytes);</span><br><span class="line">    if (!buffer) &#123;</span><br><span class="line">        fprintf(stderr, &quot;错误: 内存分配失败\n&quot;);</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 生成随机数据</span><br><span class="line">    ssize_t result = getrandom(buffer, num_bytes, flags);</span><br><span class="line">    if (result == -1) &#123;</span><br><span class="line">        if (errno == EAGAIN &amp;&amp; (flags &amp; GRND_NONBLOCK)) &#123;</span><br><span class="line">            fprintf(stderr, &quot;错误: 熵不足（非阻塞模式）\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            perror(&quot;getrandom&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">        free(buffer);</span><br><span class="line">        return 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 根据格式输出</span><br><span class="line">    switch (format) &#123;</span><br><span class="line">        case FORMAT_HEX: &#123;</span><br><span class="line">            char *hex_output = malloc(result * 2 + 1);</span><br><span class="line">            if (hex_output) &#123;</span><br><span class="line">                to_hex(buffer, result, hex_output);</span><br><span class="line">                printf(&quot;%s\n&quot;, hex_output);</span><br><span class="line">                free(hex_output);</span><br><span class="line">            &#125;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        case FORMAT_BASE64: &#123;</span><br><span class="line">            char *base64_output = malloc((result * 4 / 3) + 4);</span><br><span class="line">            if (base64_output) &#123;</span><br><span class="line">                to_base64(buffer, result, base64_output);</span><br><span class="line">                printf(&quot;%s\n&quot;, base64_output);</span><br><span class="line">                free(base64_output);</span><br><span class="line">            &#125;</span><br><span class="line">            break;</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        case FORMAT_BINARY:</span><br><span class="line">            fwrite(buffer, 1, result, stdout);</span><br><span class="line">            break;</span><br><span class="line">            </span><br><span class="line">        case FORMAT_DECIMAL:</span><br><span class="line">            for (size_t i = 0; i &lt; result; i++) &#123;</span><br><span class="line">                printf(&quot;%d &quot;, buffer&amp;#91;i]);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;\n&quot;);</span><br><span class="line">            break;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    free(buffer);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="示例4：加密安全的随机数应用"><a href="#示例4：加密安全的随机数应用" class="headerlink" title="示例4：加密安全的随机数应用"></a>示例4：加密安全的随机数应用</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br></pre></td><td class="code"><pre><span class="line">#define _GNU_SOURCE</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/random.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">// 生成加密安全的会话 ID</span><br><span class="line">char* generate_session_id(size_t length) &#123;</span><br><span class="line">    static const char charset&amp;#91;] = </span><br><span class="line">        &quot;0123456789&quot;</span><br><span class="line">        &quot;ABCDEFGHIJKLMNOPQRSTUVWXYZ&quot;</span><br><span class="line">        &quot;abcdefghijklmnopqrstuvwxyz&quot;;</span><br><span class="line">    </span><br><span class="line">    char *session_id = malloc(length + 1);</span><br><span class="line">    if (!session_id) return NULL;</span><br><span class="line">    </span><br><span class="line">    unsigned char random_bytes&amp;#91;length];</span><br><span class="line">    ssize_t result = getrandom(random_bytes, length, 0);</span><br><span class="line">    if (result != (ssize_t)length) &#123;</span><br><span class="line">        free(session_id);</span><br><span class="line">        return NULL;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    for (size_t i = 0; i &lt; length; i++) &#123;</span><br><span class="line">        session_id&amp;#91;i] = charset&amp;#91;random_bytes&amp;#91;i] % (sizeof(charset) - 1)];</span><br><span class="line">    &#125;</span><br><span class="line">    session_id&amp;#91;length] = &#x27;\0&#x27;;</span><br><span class="line">    </span><br><span class="line">    return session_id;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 生成加密密钥</span><br><span class="line">int generate_crypto_key(unsigned char *key, size_t key_size) &#123;</span><br><span class="line">    ssize_t result = getrandom(key, key_size, GRND_NONBLOCK);</span><br><span class="line">    return (result == (ssize_t)key_size) ? 0 : -1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 生成盐值</span><br><span class="line">int generate_salt(unsigned char *salt, size_t salt_size) &#123;</span><br><span class="line">    return (getrandom(salt, salt_size, 0) == (ssize_t)salt_size) ? 0 : -1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 显示密钥（以十六进制格式）</span><br><span class="line">void print_key(const unsigned char *key, size_t key_size, const char *label) &#123;</span><br><span class="line">    printf(&quot;%s: &quot;, label);</span><br><span class="line">    for (size_t i = 0; i &lt; key_size; i++) &#123;</span><br><span class="line">        printf(&quot;%02x&quot;, key&amp;#91;i]);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 加密安全随机数应用示例 ===\n\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 1. 生成会话 ID</span><br><span class="line">    printf(&quot;1. 生成会话 ID:\n&quot;);</span><br><span class="line">    for (int i = 0; i &lt; 5; i++) &#123;</span><br><span class="line">        char *session_id = generate_session_id(32);</span><br><span class="line">        if (session_id) &#123;</span><br><span class="line">            printf(&quot;  会话 ID %d: %s\n&quot;, i + 1, session_id);</span><br><span class="line">            free(session_id);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 2. 生成加密密钥</span><br><span class="line">    printf(&quot;\n2. 生成加密密钥:\n&quot;);</span><br><span class="line">    unsigned char aes_key&amp;#91;32];  // 256-bit AES key</span><br><span class="line">    unsigned char hmac_key&amp;#91;64]; // 512-bit HMAC key</span><br><span class="line">    </span><br><span class="line">    if (generate_crypto_key(aes_key, sizeof(aes_key)) == 0) &#123;</span><br><span class="line">        print_key(aes_key, sizeof(aes_key), &quot;AES-256 密钥&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  AES 密钥生成失败\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (generate_crypto_key(hmac_key, sizeof(hmac_key)) == 0) &#123;</span><br><span class="line">        print_key(hmac_key, sizeof(hmac_key), &quot;HMAC 密钥&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  HMAC 密钥生成失败\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 3. 生成盐值</span><br><span class="line">    printf(&quot;\n3. 生成盐值:\n&quot;);</span><br><span class="line">    unsigned char salt&amp;#91;16];</span><br><span class="line">    for (int i = 0; i &lt; 3; i++) &#123;</span><br><span class="line">        if (generate_salt(salt, sizeof(salt)) == 0) &#123;</span><br><span class="line">            printf(&quot;  盐值 %d: &quot;, i + 1);</span><br><span class="line">            for (size_t j = 0; j &lt; sizeof(salt); j++) &#123;</span><br><span class="line">                printf(&quot;%02x&quot;, salt&amp;#91;j]);</span><br><span class="line">            &#125;</span><br><span class="line">            printf(&quot;\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 4. 生成初始化向量 (IV)</span><br><span class="line">    printf(&quot;\n4. 生成初始化向量 (IV):\n&quot;);</span><br><span class="line">    unsigned char iv&amp;#91;16];  // AES block size</span><br><span class="line">    if (getrandom(iv, sizeof(iv), 0) == sizeof(iv)) &#123;</span><br><span class="line">        print_key(iv, sizeof(iv), &quot;AES IV&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 5. 性能测试</span><br><span class="line">    printf(&quot;\n5. 性能测试:\n&quot;);</span><br><span class="line">    const size_t test_size = 1024;</span><br><span class="line">    unsigned char *test_buffer = malloc(test_size);</span><br><span class="line">    if (test_buffer) &#123;</span><br><span class="line">        struct timespec start, end;</span><br><span class="line">        const int iterations = 1000;</span><br><span class="line">        </span><br><span class="line">        clock_gettime(CLOCK_MONOTONIC, &amp;start);</span><br><span class="line">        for (int i = 0; i &lt; iterations; i++) &#123;</span><br><span class="line">            if (getrandom(test_buffer, test_size, GRND_NONBLOCK) != test_size) &#123;</span><br><span class="line">                printf(&quot;  测试失败\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        clock_gettime(CLOCK_MONOTONIC, &amp;end);</span><br><span class="line">        </span><br><span class="line">        long long duration = (end.tv_sec - start.tv_sec) * 1000000000LL + </span><br><span class="line">                            (end.tv_nsec - start.tv_nsec);</span><br><span class="line">        double avg_time = (double)duration / iterations / 1000000.0;  // 毫秒</span><br><span class="line">        </span><br><span class="line">        printf(&quot;  生成 %zu 字节随机数据 %d 次\n&quot;, test_size, iterations);</span><br><span class="line">        printf(&quot;  平均耗时: %.3f 毫秒\n&quot;, avg_time);</span><br><span class="line">        printf(&quot;  吞吐量: %.2f MB/s\n&quot;, </span><br><span class="line">               (test_size * iterations) / (duration / 1000.0) / 1024.0);</span><br><span class="line">        </span><br><span class="line">        free(test_buffer);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n=== 安全建议 ===\n&quot;);</span><br><span class="line">    printf(&quot;1. 使用 getrandom 而不是 rand() 生成安全随机数\n&quot;);</span><br><span class="line">    printf(&quot;2. 对于加密密钥，考虑使用 GRND_RANDOM\n&quot;);</span><br><span class="line">    printf(&quot;3. 避免在循环中频繁调用 getrandom\n&quot;);</span><br><span class="line">    printf(&quot;4. 检查返回值确保成功获取随机数据\n&quot;);</span><br><span class="line">    printf(&quot;5. 不要将随机数据存储在可预测的位置\n&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>编译和运行说明</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"># 编译示例程序</span><br><span class="line">gcc -o getrandom_example1 example1.c</span><br><span class="line">gcc -o getrandom_example2 example2.c</span><br><span class="line">gcc -o getrandom_example3 example3.c</span><br><span class="line">gcc -o getrandom_example4 example4.c</span><br><span class="line"></span><br><span class="line"># 运行示例</span><br><span class="line">./getrandom_example1</span><br><span class="line">./getrandom_example2</span><br><span class="line">./getrandom_example3 --help</span><br><span class="line">./getrandom_example3 -n 16 -f hex</span><br><span class="line">./getrandom_example3 -n 32 -f base64</span><br><span class="line">./getrandom_example4</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>系统要求检查</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"># 检查内核版本（需要 3.17+）</span><br><span class="line">uname -r</span><br><span class="line"></span><br><span class="line"># 检查 glibc 版本（需要 2.25+）</span><br><span class="line">ldd --version</span><br><span class="line"></span><br><span class="line"># 检查 /dev/random 和 /dev/urandom</span><br><span class="line">ls -l /dev/random /dev/urandom</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>重要注意事项</p><p>内核版本: 需要 Linux 3.17+ 内核支持</p><p>glibc 版本: 需要 glibc 2.25+ 支持</p><p>性能考虑: 避免频繁调用，批量获取随机数据</p><p>安全性: 比 rand() 等伪随机数生成器更安全</p><p>阻塞行为: 默认非阻塞，GRND_RANDOM 可能阻塞</p><p>错误处理: 始终检查返回值和 errno</p><p>与其他随机数生成器的比较</p><p>特性getrandom&#x2F;dev&#x2F;urandomrand()random()安全性高高低低阻塞可选否否否性能中等中等高高可移植性Linux 特有Unix-like标准 CBSD 扩展加密适用是是否否</p><p>实际应用场景</p><p>加密密钥生成: 生成 AES、RSA 等加密密钥</p><p>会话管理: 生成会话 ID、CSRF 令牌</p><p>密码盐值: 为密码哈希生成随机盐值</p><p>初始化向量: 生成加密算法的 IV</p><p>临时文件名: 生成唯一的临时文件名</p><p>游戏随机数: 游戏中的随机事件生成</p><p>最佳实践</p><p>默认使用: 一般情况下使用 getrandom(buffer, size, 0)</p><p>加密场景: 重要加密操作可考虑 GRND_RANDOM</p><p>批量获取: 一次获取较多随机数据，避免频繁调用</p><p>错误检查: 始终检查返回值确保成功</p><p>内存清理: 使用后及时清理敏感的随机数据</p><p>这些示例展示了 getrandom 函数的各种使用方法，从基础的随机数据生成到完整的安全应用，帮助你全面掌握这个重要的安全随机数生成接口。</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getrandom-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getrandom-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1 id="getrandom-函数详解"><a href="#getrandom-函数详解" class="headerlink" title="getrandom 函数详解"></a>getrandom 函数详解</h1><p>getrandom是Linux系统中获取高质]]>
    </summary>
    <title>getrandom系统调用及示例</title>
    <updated>2026-06-15T07:56:28.172Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getresuid - 获取进程的真实、有效和保存的用户ID</p><p>getresuid和getresgid是Linux系统调用，用于获取进程的用户和组ID信息。getresuid获取真实用户ID、有效用户ID和保存的设置用户ID；getresgid获取对应的组ID。两者都通过指针参数返回三个ID值，成功返回0，失败返回-1并设置errno。示例代码展示了如何获取并分析这些ID信息，包括错误处理和权限状态分析。相关函数包括getuid、setuid等用于用户&#x2F;组ID管理的系统调用。</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getresuid 是一个 Linux 系统调用，用于同时获取当前进程的真实用户 ID（Real User ID）、有效用户 ID（Effective User ID）和保存的设置用户 ID（Saved Set-user-ID）。这三个 ID 构成了 Unix&#x2F;Linux 系统中完整的用户身份管理体系。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">int getresuid(uid_t *ruid, uid_t *euid, uid_t *suid);</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>getresgid - 获取进程的真实、有效和保存的组ID</p><h3 id="1-函数介绍-1"><a href="#1-函数介绍-1" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getresgid 是一个 Linux 系统调用，用于同时获取当前进程的真实组 ID（Real Group ID）、有效组 ID（Effective Group ID）和保存的设置组 ID（Saved Set-group-ID）。</p><h3 id="2-函数原型-1"><a href="#2-函数原型-1" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能对比"><a href="#3-功能对比" class="headerlink" title="3. 功能对比"></a>3. 功能对比</h3><p>函数功能参数getresuid(ruid, euid, suid)获取用户 ID 三元组3个 uid_t* 指针getresgid(rgid, egid, sgid)获取组 ID 三元组3个 gid_t* 指针</p><h3 id="4-参数说明"><a href="#4-参数说明" class="headerlink" title="4. 参数说明"></a>4. 参数说明</h3><p>getresuid 参数:</p><ul><li><p>uid_t *ruid: 指向存储真实用户 ID 的变量的指针</p></li><li><p>uid_t *euid: 指向存储有效用户 ID 的变量的指针</p></li><li><p>uid_t *suid: 指向存储保存的设置用户 ID 的变量的指针</p></li></ul><p>getresgid 参数:</p><ul><li><p>gid_t *rgid: 指向存储真实组 ID 的变量的指针</p></li><li><p>gid_t *egid: 指向存储有效组 ID 的变量的指针</p></li><li><p>gid_t *sgid: 指向存储保存的设置组 ID 的变量的指针</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时：返回 0</p></li><li><p>失败时：返回 -1，并设置 errno</p></li></ul><h3 id="6-常见-errno-错误码"><a href="#6-常见-errno-错误码" class="headerlink" title="6. 常见 errno 错误码"></a>6. 常见 errno 错误码</h3><ul><li>EFAULT: 指针参数指向无效内存地址</li></ul><h3 id="7-相似函数，或关联函数"><a href="#7-相似函数，或关联函数" class="headerlink" title="7. 相似函数，或关联函数"></a>7. 相似函数，或关联函数</h3><ul><li><p>getuid(), geteuid(): 分别获取真实和有效用户 ID</p></li><li><p>getgid(), getegid(): 分别获取真实和有效组 ID</p></li><li><p>setresuid(), setresgid(): 设置用户&#x2F;组 ID 三元组</p></li><li><p>setreuid(), setregid(): 设置真实和有效 ID</p></li><li><p>setuid(), setgid(): 设置用户&#x2F;组 ID</p></li><li><p>seteuid(), setegid(): 设置有效用户&#x2F;组 ID</p></li></ul><h3 id="8-示例代码"><a href="#8-示例代码" class="headerlink" title="8. 示例代码"></a>8. 示例代码</h3><h4 id="示例1：基本使用-获取完整的-ID-信息"><a href="#示例1：基本使用-获取完整的-ID-信息" class="headerlink" title="示例1：基本使用 - 获取完整的 ID 信息"></a>示例1：基本使用 - 获取完整的 ID 信息</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void print_user_info(const char *label, uid_t uid) &#123;</span><br><span class="line">    printf(&quot;%-20s %d&quot;, label, uid);</span><br><span class="line">    </span><br><span class="line">    struct passwd *pwd = getpwuid(uid);</span><br><span class="line">    if (pwd != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, pwd-&gt;pw_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_group_info(const char *label, gid_t gid) &#123;</span><br><span class="line">    printf(&quot;%-20s %d&quot;, label, gid);</span><br><span class="line">    </span><br><span class="line">    struct group *grp = getgrgid(gid);</span><br><span class="line">    if (grp != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    int ret;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程完整身份信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取用户 ID 三元组</span><br><span class="line">    ret = getresuid(&amp;ruid, &amp;euid, &amp;suid);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;getresuid 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;用户 ID 信息:\n&quot;);</span><br><span class="line">    print_user_info(&quot;真实用户 ID:&quot;, ruid);</span><br><span class="line">    print_user_info(&quot;有效用户 ID:&quot;, euid);</span><br><span class="line">    print_user_info(&quot;保存的设置 UID:&quot;, suid);</span><br><span class="line">    </span><br><span class="line">    // 获取组 ID 三元组</span><br><span class="line">    ret = getresgid(&amp;rgid, &amp;egid, &amp;sgid);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;getresgid 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n组 ID 信息:\n&quot;);</span><br><span class="line">    print_group_info(&quot;真实组 ID:&quot;, rgid);</span><br><span class="line">    print_group_info(&quot;有效组 ID:&quot;, egid);</span><br><span class="line">    print_group_info(&quot;保存的设置 GID:&quot;, sgid);</span><br><span class="line">    </span><br><span class="line">    // 分析身份状态</span><br><span class="line">    printf(&quot;\n身份状态分析:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (euid == 0) &#123;</span><br><span class="line">        printf(&quot;✓ 当前进程具有 root 用户权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (egid == 0) &#123;</span><br><span class="line">        printf(&quot;✓ 当前进程具有 root 组权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (ruid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 用户身份已被切换 (真实: %d, 有效: %d)\n&quot;, ruid, euid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (rgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 组身份已被切换 (真实: %d, 有效: %d)\n&quot;, rgid, egid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (suid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 保存的设置 UID 可用于权限恢复 (%d -&gt; %d)\n&quot;, suid, euid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (sgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 保存的设置 GID 可用于权限恢复 (%d -&gt; %d)\n&quot;, sgid, egid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：错误处理和权限分析"><a href="#示例2：错误处理和权限分析" class="headerlink" title="示例2：错误处理和权限分析"></a>示例2：错误处理和权限分析</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void safe_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) &#123;</span><br><span class="line">    if (getresuid(ruid, euid, suid) == -1) &#123;</span><br><span class="line">        printf(&quot;getresuid 失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        *ruid = *euid = *suid = (uid_t)-1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void safe_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) &#123;</span><br><span class="line">    if (getresgid(rgid, egid, sgid) == -1) &#123;</span><br><span class="line">        printf(&quot;getresgid 失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        *rgid = *egid = *sgid = (gid_t)-1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void analyze_privilege_status() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 权限状态详细分析 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    safe_getresuid(&amp;ruid, &amp;euid, &amp;suid);</span><br><span class="line">    safe_getresgid(&amp;rgid, &amp;egid, &amp;sgid);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;用户权限分析:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 UID:  %d\n&quot;, ruid);</span><br><span class="line">    printf(&quot;  有效 UID:  %d&quot;, euid);</span><br><span class="line">    if (euid == 0) printf(&quot; (ROOT 权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    printf(&quot;  保存 SUID: %d&quot;, suid);</span><br><span class="line">    if (suid == 0) printf(&quot; (保存 ROOT 权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n组权限分析:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 GID:  %d\n&quot;, rgid);</span><br><span class="line">    printf(&quot;  有效 GID:  %d&quot;, egid);</span><br><span class="line">    if (egid == 0) printf(&quot; (ROOT 组权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    printf(&quot;  保存 SGID: %d&quot;, sgid);</span><br><span class="line">    if (sgid == 0) printf(&quot; (保存 ROOT 组权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 权限切换能力分析</span><br><span class="line">    printf(&quot;\n权限切换能力:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (suid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过 setuid() 恢复到保存的 UID %d\n&quot;, suid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (sgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过 setgid() 恢复到保存的 GID %d\n&quot;, sgid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 特权状态</span><br><span class="line">    if (euid == 0 || egid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 当前进程具有特权权限，注意安全操作\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if ((euid != ruid || egid != rgid) &amp;&amp; (suid == ruid &amp;&amp; sgid == rgid)) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过保存的 ID 完全恢复到原始身份\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void demonstrate_invalid_pointer_handling() &#123;</span><br><span class="line">    printf(&quot;\n=== 无效指针处理测试 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试 NULL 指针</span><br><span class="line">    if (getresuid(NULL, NULL, NULL) == -1) &#123;</span><br><span class="line">        if (errno == EFAULT) &#123;</span><br><span class="line">            printf(&quot;✓ 正确处理了 NULL 指针 (EFAULT)\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;✗ 意外错误: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试部分 NULL 指针</span><br><span class="line">    uid_t ruid, euid;</span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, NULL) == -1) &#123;</span><br><span class="line">        if (errno == EFAULT) &#123;</span><br><span class="line">            printf(&quot;✓ 正确处理了部分 NULL 指针\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    analyze_privilege_status();</span><br><span class="line">    demonstrate_invalid_pointer_handling();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：权限切换和恢复演示"><a href="#示例3：权限切换和恢复演示" class="headerlink" title="示例3：权限切换和恢复演示"></a>示例3：权限切换和恢复演示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">void print_current_ids(const char *context) &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        printf(&quot;获取 ID 信息失败\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;%s:\n&quot;, context);</span><br><span class="line">    printf(&quot;  UID: %d/%d/%d (真实/有效/保存)\n&quot;, ruid, euid, suid);</span><br><span class="line">    printf(&quot;  GID: %d/%d/%d (真实/有效/保存)\n&quot;, rgid, egid, sgid);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 权限切换和恢复演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始状态</span><br><span class="line">    print_current_ids(&quot;初始状态&quot;);</span><br><span class="line">    </span><br><span class="line">    // 检查是否具有特权权限</span><br><span class="line">    uid_t euid;</span><br><span class="line">    getresuid(NULL, &amp;euid, NULL);</span><br><span class="line">    </span><br><span class="line">    if (euid != 0) &#123;</span><br><span class="line">        printf(&quot;注意: 当前进程不是 root，某些权限操作可能失败\n&quot;);</span><br><span class="line">        printf(&quot;建议以 root 权限运行此演示\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 演示 setuid/setgid 的效果</span><br><span class="line">    printf(&quot;尝试进行权限操作...\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 如果是 root，可以进行权限切换演示</span><br><span class="line">    if (euid == 0) &#123;</span><br><span class="line">        // 切换到 nobody 用户（假设 UID 65534）</span><br><span class="line">        uid_t nobody_uid = 65534;</span><br><span class="line">        gid_t nogroup_gid = 65534;</span><br><span class="line">        </span><br><span class="line">        printf(&quot;尝试切换到 nobody 用户...\n&quot;);</span><br><span class="line">        </span><br><span class="line">        if (setresuid(nobody_uid, nobody_uid, nobody_uid) == 0 &amp;&amp;</span><br><span class="line">            setresgid(nogroup_gid, nogroup_gid, nogroup_gid) == 0) &#123;</span><br><span class="line">            print_current_ids(&quot;切换到 nobody 后&quot;);</span><br><span class="line">            printf(&quot;✓ 成功切换到 nobody 用户\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;✗ 切换失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 尝试恢复权限（应该失败，因为保存的 ID 已改变）</span><br><span class="line">        if (setuid(0) == -1) &#123;</span><br><span class="line">            printf(&quot;✓ 无法恢复到 root 权限（保存的 ID 已改变）\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;跳过权限切换演示（需要 root 权限）\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 显示最终状态</span><br><span class="line">    print_current_ids(&quot;最终状态&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：安全审计和监控工具"><a href="#示例4：安全审计和监控工具" class="headerlink" title="示例4：安全审计和监控工具"></a>示例4：安全审计和监控工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    time_t timestamp;</span><br><span class="line">    pid_t pid;</span><br><span class="line">&#125; identity_snapshot_t;</span><br><span class="line"></span><br><span class="line">int capture_identity_snapshot(identity_snapshot_t *snapshot) &#123;</span><br><span class="line">    snapshot-&gt;pid = getpid();</span><br><span class="line">    snapshot-&gt;timestamp = time(NULL);</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;snapshot-&gt;ruid, &amp;snapshot-&gt;euid, &amp;snapshot-&gt;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;snapshot-&gt;rgid, &amp;snapshot-&gt;egid, &amp;snapshot-&gt;sgid) == -1) &#123;</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_identity_snapshot(const identity_snapshot_t *snapshot) &#123;</span><br><span class="line">    char time_str&amp;#91;32];</span><br><span class="line">    strftime(time_str, sizeof(time_str), &quot;%Y-%m-%d %H:%M:%S&quot;,</span><br><span class="line">             localtime(&amp;snapshot-&gt;timestamp));</span><br><span class="line">    </span><br><span class="line">    printf(&quot;时间: %s\n&quot;, time_str);</span><br><span class="line">    printf(&quot;进程: %d\n&quot;, snapshot-&gt;pid);</span><br><span class="line">    printf(&quot;用户 ID: %d/%d/%d (真实/有效/保存)\n&quot;,</span><br><span class="line">           snapshot-&gt;ruid, snapshot-&gt;euid, snapshot-&gt;suid);</span><br><span class="line">    printf(&quot;组 ID: %d/%d/%d (真实/有效/保存)\n&quot;,</span><br><span class="line">           snapshot-&gt;rgid, snapshot-&gt;egid, snapshot-&gt;sgid);</span><br><span class="line">    </span><br><span class="line">    // 显示用户名和组名</span><br><span class="line">    struct passwd *pwd = getpwuid(snapshot-&gt;ruid);</span><br><span class="line">    if (pwd) printf(&quot;真实用户: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    </span><br><span class="line">    pwd = getpwuid(snapshot-&gt;euid);</span><br><span class="line">    if (pwd) printf(&quot;有效用户: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    </span><br><span class="line">    struct group *grp = getgrgid(snapshot-&gt;rgid);</span><br><span class="line">    if (grp) printf(&quot;真实组: %s\n&quot;, grp-&gt;gr_name);</span><br><span class="line">    </span><br><span class="line">    grp = getgrgid(snapshot-&gt;egid);</span><br><span class="line">    if (grp) printf(&quot;有效组: %s\n&quot;, grp-&gt;gr_name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void security_audit() &#123;</span><br><span class="line">    identity_snapshot_t snapshot;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 安全审计报告 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (capture_identity_snapshot(&amp;snapshot) == -1) &#123;</span><br><span class="line">        printf(&quot;获取身份信息失败\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    print_identity_snapshot(&amp;snapshot);</span><br><span class="line">    </span><br><span class="line">    // 安全检查</span><br><span class="line">    printf(&quot;\n安全检查结果:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 检查特权权限</span><br><span class="line">    if (snapshot.euid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 警告: 进程以 root 权限运行\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.egid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 警告: 进程具有 root 组权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查权限不一致</span><br><span class="line">    if (snapshot.ruid != snapshot.euid) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 用户权限已被切换\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.rgid != snapshot.egid) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 组权限已被切换\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查保存的权限</span><br><span class="line">    if (snapshot.suid == 0 &amp;&amp; snapshot.euid != 0) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 保存了 root 用户权限，可用于恢复\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.sgid == 0 &amp;&amp; snapshot.egid != 0) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 保存了 root 组权限，可用于恢复\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查潜在安全风险</span><br><span class="line">    if ((snapshot.ruid != snapshot.euid || snapshot.rgid != snapshot.egid) &amp;&amp;</span><br><span class="line">        (snapshot.suid == snapshot.ruid &amp;&amp; snapshot.sgid == snapshot.rgid)) &#123;</span><br><span class="line">        printf(&quot;✓ 安全: 可以完全恢复到原始身份\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void monitor_privilege_changes() &#123;</span><br><span class="line">    printf(&quot;\n=== 权限变化监控 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    identity_snapshot_t initial, current;</span><br><span class="line">    </span><br><span class="line">    if (capture_identity_snapshot(&amp;initial) == -1) &#123;</span><br><span class="line">        printf(&quot;无法获取初始身份信息\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;监控 5 秒钟内的权限变化...\n&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; 5; i++) &#123;</span><br><span class="line">        sleep(1);</span><br><span class="line">        </span><br><span class="line">        if (capture_identity_snapshot(&amp;current) == 0) &#123;</span><br><span class="line">            // 检查是否有变化</span><br><span class="line">            if (current.ruid != initial.ruid ||</span><br><span class="line">                current.euid != initial.euid ||</span><br><span class="line">                current.suid != initial.suid ||</span><br><span class="line">                current.rgid != initial.rgid ||</span><br><span class="line">                current.egid != initial.egid ||</span><br><span class="line">                current.sgid != initial.sgid) &#123;</span><br><span class="line">                </span><br><span class="line">                printf(&quot;检测到权限变化:\n&quot;);</span><br><span class="line">                printf(&quot;之前: UID(%d/%d/%d) GID(%d/%d/%d)\n&quot;,</span><br><span class="line">                       initial.ruid, initial.euid, initial.suid,</span><br><span class="line">                       initial.rgid, initial.egid, initial.sgid);</span><br><span class="line">                printf(&quot;现在: UID(%d/%d/%d) GID(%d/%d/%d)\n&quot;,</span><br><span class="line">                       current.ruid, current.euid, current.suid,</span><br><span class="line">                       current.rgid, current.egid, current.sgid);</span><br><span class="line">                </span><br><span class="line">                // 更新初始状态</span><br><span class="line">                initial = current;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;监控结束\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    security_audit();</span><br><span class="line">    monitor_privilege_changes();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-ID-类型说明"><a href="#9-ID-类型说明" class="headerlink" title="9. ID 类型说明"></a>9. ID 类型说明</h3><p>Unix&#x2F;Linux 系统中的三类 ID：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// 用户 ID 三元组</span><br><span class="line">ruid  // Real User ID: 启动进程的用户</span><br><span class="line">euid  // Effective User ID: 当前权限检查使用的用户 ID</span><br><span class="line">suid  // Saved Set-user-ID: 保存的设置用户 ID</span><br><span class="line"></span><br><span class="line">// 组 ID 三元组</span><br><span class="line">rgid  // Real Group ID: 启动进程的组</span><br><span class="line">egid  // Effective Group ID: 当前权限检查使用的组 ID</span><br><span class="line">sgid  // Saved Set-group-ID: 保存的设置组 ID</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-实际应用场景"><a href="#10-实际应用场景" class="headerlink" title="10. 实际应用场景"></a>10. 实际应用场景</h3><h4 id="场景1：权限管理工具"><a href="#场景1：权限管理工具" class="headerlink" title="场景1：权限管理工具"></a>场景1：权限管理工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">int can_drop_privileges_completely() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否可以完全丢弃特权</span><br><span class="line">    return (ruid == euid &amp;&amp; euid == suid &amp;&amp;</span><br><span class="line">            rgid == egid &amp;&amp; egid == sgid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：安全审计"><a href="#场景2：安全审计" class="headerlink" title="场景2：安全审计"></a>场景2：安全审计</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">void audit_process_privileges() &#123;</span><br><span class="line">    identity_snapshot_t snapshot;</span><br><span class="line">    if (capture_identity_snapshot(&amp;snapshot) == 0) &#123;</span><br><span class="line">        if (snapshot.euid == 0) &#123;</span><br><span class="line">            syslog(LOG_WARNING, &quot;进程 %d 以 root 权限运行&quot;, snapshot.pid);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：权限恢复"><a href="#场景3：权限恢复" class="headerlink" title="场景3：权限恢复"></a>场景3：权限恢复</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">int restore_original_privileges() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 恢复到原始身份</span><br><span class="line">    return setresuid(ruid, ruid, ruid) || setresgid(rgid, rgid, rgid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="11-注意事项"><a href="#11-注意事项" class="headerlink" title="11. 注意事项"></a>11. 注意事项</h3><p>使用 getresuid 和 getresgid 时需要注意：</p><p>指针有效性: 所有指针参数必须指向有效的内存地址</p><p>错误处理: 虽然很少失败，但仍需检查返回值</p><p>权限检查: 获取其他进程的 ID 信息可能需要权限</p><p>并发安全: 在多线程环境中注意数据一致性</p><p>系统兼容: 在所有现代 Unix&#x2F;Linux 系统中都可用</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getresuid 和 getresgid 是管理进程身份信息的重要函数：</p><p>关键特性:</p><p>完整信息: 一次性获取所有相关的 ID 信息</p><p>原子操作: 保证获取的 ID 组是一致的</p><p>安全相关: 是权限管理和安全审计的基础</p><p>系统调用: 直接访问内核信息，性能良好</p><p>主要应用:</p><p>安全审计和监控工具</p><p>权限管理和切换程序</p><p>系统管理和调试工具</p><p>容器和虚拟化环境中的权限控制</p><p>正确理解和使用这些函数对于编写安全、可靠的 Unix&#x2F;Linux 程序至关重要，特别是在需要进行权限管理和安全检查的场景中。</p><p><a href="https://www.calcguide.tech/2025/09/09/getresuid-syscall-demo/">https://www.calcguide.tech/2025/09/09/getresuid-syscall-demo/</a></p><p>getresuid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getresuid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getresuid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getresuid - 获取进程的真实、有效和保存的用户ID</p>
<p>getresuid和getresgid是Linux系统调用，用于获取进程的用户和组ID信息。getresuid获取真实用户ID、有效用户ID和保存的设置用户ID；getresgid获取对应的组ID。]]>
    </summary>
    <title>getresuid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.172Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getresgid - 获取进程的真实、有效和保存的组ID</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getresgid 是一个 Linux 系统调用，用于同时获取当前进程的真实组 ID（Real Group ID）、有效组 ID（Effective Group ID）和保存的设置组 ID（Saved Set-group-ID）。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line"></span><br><span class="line">int getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能对比"><a href="#3-功能对比" class="headerlink" title="3. 功能对比"></a>3. 功能对比</h3><p>函数功能参数getresuid(ruid, euid, suid)获取用户 ID 三元组3个 uid_t* 指针getresgid(rgid, egid, sgid)获取组 ID 三元组3个 gid_t* 指针</p><h3 id="4-参数说明"><a href="#4-参数说明" class="headerlink" title="4. 参数说明"></a>4. 参数说明</h3><p>getresuid 参数:</p><ul><li><p>uid_t *ruid: 指向存储真实用户 ID 的变量的指针</p></li><li><p>uid_t *euid: 指向存储有效用户 ID 的变量的指针</p></li><li><p>uid_t *suid: 指向存储保存的设置用户 ID 的变量的指针</p></li></ul><p>getresgid 参数:</p><ul><li><p>gid_t *rgid: 指向存储真实组 ID 的变量的指针</p></li><li><p>gid_t *egid: 指向存储有效组 ID 的变量的指针</p></li><li><p>gid_t *sgid: 指向存储保存的设置组 ID 的变量的指针</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时：返回 0</p></li><li><p>失败时：返回 -1，并设置 errno</p></li></ul><h3 id="6-常见-errno-错误码"><a href="#6-常见-errno-错误码" class="headerlink" title="6. 常见 errno 错误码"></a>6. 常见 errno 错误码</h3><ul><li>EFAULT: 指针参数指向无效内存地址</li></ul><h3 id="7-相似函数，或关联函数"><a href="#7-相似函数，或关联函数" class="headerlink" title="7. 相似函数，或关联函数"></a>7. 相似函数，或关联函数</h3><ul><li><p>getuid(), geteuid(): 分别获取真实和有效用户 ID</p></li><li><p>getgid(), getegid(): 分别获取真实和有效组 ID</p></li><li><p>setresuid(), setresgid(): 设置用户&#x2F;组 ID 三元组</p></li><li><p>setreuid(), setregid(): 设置真实和有效 ID</p></li><li><p>setuid(), setgid(): 设置用户&#x2F;组 ID</p></li><li><p>seteuid(), setegid(): 设置有效用户&#x2F;组 ID</p></li></ul><h3 id="8-示例代码"><a href="#8-示例代码" class="headerlink" title="8. 示例代码"></a>8. 示例代码</h3><h4 id="示例1：基本使用-获取完整的-ID-信息"><a href="#示例1：基本使用-获取完整的-ID-信息" class="headerlink" title="示例1：基本使用 - 获取完整的 ID 信息"></a>示例1：基本使用 - 获取完整的 ID 信息</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void print_user_info(const char *label, uid_t uid) &#123;</span><br><span class="line">    printf(&quot;%-20s %d&quot;, label, uid);</span><br><span class="line">    </span><br><span class="line">    struct passwd *pwd = getpwuid(uid);</span><br><span class="line">    if (pwd != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, pwd-&gt;pw_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_group_info(const char *label, gid_t gid) &#123;</span><br><span class="line">    printf(&quot;%-20s %d&quot;, label, gid);</span><br><span class="line">    </span><br><span class="line">    struct group *grp = getgrgid(gid);</span><br><span class="line">    if (grp != NULL) &#123;</span><br><span class="line">        printf(&quot; (%s)&quot;, grp-&gt;gr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    int ret;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 进程完整身份信息 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 获取用户 ID 三元组</span><br><span class="line">    ret = getresuid(&amp;ruid, &amp;euid, &amp;suid);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;getresuid 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;用户 ID 信息:\n&quot;);</span><br><span class="line">    print_user_info(&quot;真实用户 ID:&quot;, ruid);</span><br><span class="line">    print_user_info(&quot;有效用户 ID:&quot;, euid);</span><br><span class="line">    print_user_info(&quot;保存的设置 UID:&quot;, suid);</span><br><span class="line">    </span><br><span class="line">    // 获取组 ID 三元组</span><br><span class="line">    ret = getresgid(&amp;rgid, &amp;egid, &amp;sgid);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;getresgid 失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n组 ID 信息:\n&quot;);</span><br><span class="line">    print_group_info(&quot;真实组 ID:&quot;, rgid);</span><br><span class="line">    print_group_info(&quot;有效组 ID:&quot;, egid);</span><br><span class="line">    print_group_info(&quot;保存的设置 GID:&quot;, sgid);</span><br><span class="line">    </span><br><span class="line">    // 分析身份状态</span><br><span class="line">    printf(&quot;\n身份状态分析:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (euid == 0) &#123;</span><br><span class="line">        printf(&quot;✓ 当前进程具有 root 用户权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (egid == 0) &#123;</span><br><span class="line">        printf(&quot;✓ 当前进程具有 root 组权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (ruid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 用户身份已被切换 (真实: %d, 有效: %d)\n&quot;, ruid, euid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (rgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 组身份已被切换 (真实: %d, 有效: %d)\n&quot;, rgid, egid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (suid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 保存的设置 UID 可用于权限恢复 (%d -&gt; %d)\n&quot;, suid, euid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (sgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 保存的设置 GID 可用于权限恢复 (%d -&gt; %d)\n&quot;, sgid, egid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：错误处理和权限分析"><a href="#示例2：错误处理和权限分析" class="headerlink" title="示例2：错误处理和权限分析"></a>示例2：错误处理和权限分析</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void safe_getresuid(uid_t *ruid, uid_t *euid, uid_t *suid) &#123;</span><br><span class="line">    if (getresuid(ruid, euid, suid) == -1) &#123;</span><br><span class="line">        printf(&quot;getresuid 失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        *ruid = *euid = *suid = (uid_t)-1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void safe_getresgid(gid_t *rgid, gid_t *egid, gid_t *sgid) &#123;</span><br><span class="line">    if (getresgid(rgid, egid, sgid) == -1) &#123;</span><br><span class="line">        printf(&quot;getresgid 失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        *rgid = *egid = *sgid = (gid_t)-1;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void analyze_privilege_status() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 权限状态详细分析 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    safe_getresuid(&amp;ruid, &amp;euid, &amp;suid);</span><br><span class="line">    safe_getresgid(&amp;rgid, &amp;egid, &amp;sgid);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;用户权限分析:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 UID:  %d\n&quot;, ruid);</span><br><span class="line">    printf(&quot;  有效 UID:  %d&quot;, euid);</span><br><span class="line">    if (euid == 0) printf(&quot; (ROOT 权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    printf(&quot;  保存 SUID: %d&quot;, suid);</span><br><span class="line">    if (suid == 0) printf(&quot; (保存 ROOT 权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;\n组权限分析:\n&quot;);</span><br><span class="line">    printf(&quot;  真实 GID:  %d\n&quot;, rgid);</span><br><span class="line">    printf(&quot;  有效 GID:  %d&quot;, egid);</span><br><span class="line">    if (egid == 0) printf(&quot; (ROOT 组权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    printf(&quot;  保存 SGID: %d&quot;, sgid);</span><br><span class="line">    if (sgid == 0) printf(&quot; (保存 ROOT 组权限)&quot;);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 权限切换能力分析</span><br><span class="line">    printf(&quot;\n权限切换能力:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (suid != euid) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过 setuid() 恢复到保存的 UID %d\n&quot;, suid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (sgid != egid) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过 setgid() 恢复到保存的 GID %d\n&quot;, sgid);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 特权状态</span><br><span class="line">    if (euid == 0 || egid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 当前进程具有特权权限，注意安全操作\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if ((euid != ruid || egid != rgid) &amp;&amp; (suid == ruid &amp;&amp; sgid == rgid)) &#123;</span><br><span class="line">        printf(&quot;✓ 可以通过保存的 ID 完全恢复到原始身份\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void demonstrate_invalid_pointer_handling() &#123;</span><br><span class="line">    printf(&quot;\n=== 无效指针处理测试 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试 NULL 指针</span><br><span class="line">    if (getresuid(NULL, NULL, NULL) == -1) &#123;</span><br><span class="line">        if (errno == EFAULT) &#123;</span><br><span class="line">            printf(&quot;✓ 正确处理了 NULL 指针 (EFAULT)\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;✗ 意外错误: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试部分 NULL 指针</span><br><span class="line">    uid_t ruid, euid;</span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, NULL) == -1) &#123;</span><br><span class="line">        if (errno == EFAULT) &#123;</span><br><span class="line">            printf(&quot;✓ 正确处理了部分 NULL 指针\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    analyze_privilege_status();</span><br><span class="line">    demonstrate_invalid_pointer_handling();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：权限切换和恢复演示"><a href="#示例3：权限切换和恢复演示" class="headerlink" title="示例3：权限切换和恢复演示"></a>示例3：权限切换和恢复演示</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line"></span><br><span class="line">void print_current_ids(const char *context) &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        printf(&quot;获取 ID 信息失败\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;%s:\n&quot;, context);</span><br><span class="line">    printf(&quot;  UID: %d/%d/%d (真实/有效/保存)\n&quot;, ruid, euid, suid);</span><br><span class="line">    printf(&quot;  GID: %d/%d/%d (真实/有效/保存)\n&quot;, rgid, egid, sgid);</span><br><span class="line">    printf(&quot;\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    printf(&quot;=== 权限切换和恢复演示 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 初始状态</span><br><span class="line">    print_current_ids(&quot;初始状态&quot;);</span><br><span class="line">    </span><br><span class="line">    // 检查是否具有特权权限</span><br><span class="line">    uid_t euid;</span><br><span class="line">    getresuid(NULL, &amp;euid, NULL);</span><br><span class="line">    </span><br><span class="line">    if (euid != 0) &#123;</span><br><span class="line">        printf(&quot;注意: 当前进程不是 root，某些权限操作可能失败\n&quot;);</span><br><span class="line">        printf(&quot;建议以 root 权限运行此演示\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 演示 setuid/setgid 的效果</span><br><span class="line">    printf(&quot;尝试进行权限操作...\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 如果是 root，可以进行权限切换演示</span><br><span class="line">    if (euid == 0) &#123;</span><br><span class="line">        // 切换到 nobody 用户（假设 UID 65534）</span><br><span class="line">        uid_t nobody_uid = 65534;</span><br><span class="line">        gid_t nogroup_gid = 65534;</span><br><span class="line">        </span><br><span class="line">        printf(&quot;尝试切换到 nobody 用户...\n&quot;);</span><br><span class="line">        </span><br><span class="line">        if (setresuid(nobody_uid, nobody_uid, nobody_uid) == 0 &amp;&amp;</span><br><span class="line">            setresgid(nogroup_gid, nogroup_gid, nogroup_gid) == 0) &#123;</span><br><span class="line">            print_current_ids(&quot;切换到 nobody 后&quot;);</span><br><span class="line">            printf(&quot;✓ 成功切换到 nobody 用户\n&quot;);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;✗ 切换失败: %s\n&quot;, strerror(errno));</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        // 尝试恢复权限（应该失败，因为保存的 ID 已改变）</span><br><span class="line">        if (setuid(0) == -1) &#123;</span><br><span class="line">            printf(&quot;✓ 无法恢复到 root 权限（保存的 ID 已改变）\n&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;跳过权限切换演示（需要 root 权限）\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 显示最终状态</span><br><span class="line">    print_current_ids(&quot;最终状态&quot;);</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例4：安全审计和监控工具"><a href="#示例4：安全审计和监控工具" class="headerlink" title="示例4：安全审计和监控工具"></a>示例4：安全审计和监控工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;pwd.h&gt;</span><br><span class="line">#include &lt;grp.h&gt;</span><br><span class="line">#include &lt;time.h&gt;</span><br><span class="line"></span><br><span class="line">typedef struct &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    time_t timestamp;</span><br><span class="line">    pid_t pid;</span><br><span class="line">&#125; identity_snapshot_t;</span><br><span class="line"></span><br><span class="line">int capture_identity_snapshot(identity_snapshot_t *snapshot) &#123;</span><br><span class="line">    snapshot-&gt;pid = getpid();</span><br><span class="line">    snapshot-&gt;timestamp = time(NULL);</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;snapshot-&gt;ruid, &amp;snapshot-&gt;euid, &amp;snapshot-&gt;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;snapshot-&gt;rgid, &amp;snapshot-&gt;egid, &amp;snapshot-&gt;sgid) == -1) &#123;</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_identity_snapshot(const identity_snapshot_t *snapshot) &#123;</span><br><span class="line">    char time_str&amp;#91;32];</span><br><span class="line">    strftime(time_str, sizeof(time_str), &quot;%Y-%m-%d %H:%M:%S&quot;,</span><br><span class="line">             localtime(&amp;snapshot-&gt;timestamp));</span><br><span class="line">    </span><br><span class="line">    printf(&quot;时间: %s\n&quot;, time_str);</span><br><span class="line">    printf(&quot;进程: %d\n&quot;, snapshot-&gt;pid);</span><br><span class="line">    printf(&quot;用户 ID: %d/%d/%d (真实/有效/保存)\n&quot;,</span><br><span class="line">           snapshot-&gt;ruid, snapshot-&gt;euid, snapshot-&gt;suid);</span><br><span class="line">    printf(&quot;组 ID: %d/%d/%d (真实/有效/保存)\n&quot;,</span><br><span class="line">           snapshot-&gt;rgid, snapshot-&gt;egid, snapshot-&gt;sgid);</span><br><span class="line">    </span><br><span class="line">    // 显示用户名和组名</span><br><span class="line">    struct passwd *pwd = getpwuid(snapshot-&gt;ruid);</span><br><span class="line">    if (pwd) printf(&quot;真实用户: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    </span><br><span class="line">    pwd = getpwuid(snapshot-&gt;euid);</span><br><span class="line">    if (pwd) printf(&quot;有效用户: %s\n&quot;, pwd-&gt;pw_name);</span><br><span class="line">    </span><br><span class="line">    struct group *grp = getgrgid(snapshot-&gt;rgid);</span><br><span class="line">    if (grp) printf(&quot;真实组: %s\n&quot;, grp-&gt;gr_name);</span><br><span class="line">    </span><br><span class="line">    grp = getgrgid(snapshot-&gt;egid);</span><br><span class="line">    if (grp) printf(&quot;有效组: %s\n&quot;, grp-&gt;gr_name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void security_audit() &#123;</span><br><span class="line">    identity_snapshot_t snapshot;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;=== 安全审计报告 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    if (capture_identity_snapshot(&amp;snapshot) == -1) &#123;</span><br><span class="line">        printf(&quot;获取身份信息失败\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    print_identity_snapshot(&amp;snapshot);</span><br><span class="line">    </span><br><span class="line">    // 安全检查</span><br><span class="line">    printf(&quot;\n安全检查结果:\n&quot;);</span><br><span class="line">    </span><br><span class="line">    // 检查特权权限</span><br><span class="line">    if (snapshot.euid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 警告: 进程以 root 权限运行\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.egid == 0) &#123;</span><br><span class="line">        printf(&quot;⚠ 警告: 进程具有 root 组权限\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查权限不一致</span><br><span class="line">    if (snapshot.ruid != snapshot.euid) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 用户权限已被切换\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.rgid != snapshot.egid) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 组权限已被切换\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查保存的权限</span><br><span class="line">    if (snapshot.suid == 0 &amp;&amp; snapshot.euid != 0) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 保存了 root 用户权限，可用于恢复\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (snapshot.sgid == 0 &amp;&amp; snapshot.egid != 0) &#123;</span><br><span class="line">        printf(&quot;ℹ 信息: 保存了 root 组权限，可用于恢复\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查潜在安全风险</span><br><span class="line">    if ((snapshot.ruid != snapshot.euid || snapshot.rgid != snapshot.egid) &amp;&amp;</span><br><span class="line">        (snapshot.suid == snapshot.ruid &amp;&amp; snapshot.sgid == snapshot.rgid)) &#123;</span><br><span class="line">        printf(&quot;✓ 安全: 可以完全恢复到原始身份\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void monitor_privilege_changes() &#123;</span><br><span class="line">    printf(&quot;\n=== 权限变化监控 ===\n&quot;);</span><br><span class="line">    </span><br><span class="line">    identity_snapshot_t initial, current;</span><br><span class="line">    </span><br><span class="line">    if (capture_identity_snapshot(&amp;initial) == -1) &#123;</span><br><span class="line">        printf(&quot;无法获取初始身份信息\n&quot;);</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;监控 5 秒钟内的权限变化...\n&quot;);</span><br><span class="line">    </span><br><span class="line">    for (int i = 0; i &lt; 5; i++) &#123;</span><br><span class="line">        sleep(1);</span><br><span class="line">        </span><br><span class="line">        if (capture_identity_snapshot(&amp;current) == 0) &#123;</span><br><span class="line">            // 检查是否有变化</span><br><span class="line">            if (current.ruid != initial.ruid ||</span><br><span class="line">                current.euid != initial.euid ||</span><br><span class="line">                current.suid != initial.suid ||</span><br><span class="line">                current.rgid != initial.rgid ||</span><br><span class="line">                current.egid != initial.egid ||</span><br><span class="line">                current.sgid != initial.sgid) &#123;</span><br><span class="line">                </span><br><span class="line">                printf(&quot;检测到权限变化:\n&quot;);</span><br><span class="line">                printf(&quot;之前: UID(%d/%d/%d) GID(%d/%d/%d)\n&quot;,</span><br><span class="line">                       initial.ruid, initial.euid, initial.suid,</span><br><span class="line">                       initial.rgid, initial.egid, initial.sgid);</span><br><span class="line">                printf(&quot;现在: UID(%d/%d/%d) GID(%d/%d/%d)\n&quot;,</span><br><span class="line">                       current.ruid, current.euid, current.suid,</span><br><span class="line">                       current.rgid, current.egid, current.sgid);</span><br><span class="line">                </span><br><span class="line">                // 更新初始状态</span><br><span class="line">                initial = current;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;监控结束\n&quot;);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    security_audit();</span><br><span class="line">    monitor_privilege_changes();</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-ID-类型说明"><a href="#9-ID-类型说明" class="headerlink" title="9. ID 类型说明"></a>9. ID 类型说明</h3><p>Unix&#x2F;Linux 系统中的三类 ID：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">// 用户 ID 三元组</span><br><span class="line">ruid  // Real User ID: 启动进程的用户</span><br><span class="line">euid  // Effective User ID: 当前权限检查使用的用户 ID</span><br><span class="line">suid  // Saved Set-user-ID: 保存的设置用户 ID</span><br><span class="line"></span><br><span class="line">// 组 ID 三元组</span><br><span class="line">rgid  // Real Group ID: 启动进程的组</span><br><span class="line">egid  // Effective Group ID: 当前权限检查使用的组 ID</span><br><span class="line">sgid  // Saved Set-group-ID: 保存的设置组 ID</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="10-实际应用场景"><a href="#10-实际应用场景" class="headerlink" title="10. 实际应用场景"></a>10. 实际应用场景</h3><h4 id="场景1：权限管理工具"><a href="#场景1：权限管理工具" class="headerlink" title="场景1：权限管理工具"></a>场景1：权限管理工具</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">int can_drop_privileges_completely() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 检查是否可以完全丢弃特权</span><br><span class="line">    return (ruid == euid &amp;&amp; euid == suid &amp;&amp;</span><br><span class="line">            rgid == egid &amp;&amp; egid == sgid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景2：安全审计"><a href="#场景2：安全审计" class="headerlink" title="场景2：安全审计"></a>场景2：安全审计</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">void audit_process_privileges() &#123;</span><br><span class="line">    identity_snapshot_t snapshot;</span><br><span class="line">    if (capture_identity_snapshot(&amp;snapshot) == 0) &#123;</span><br><span class="line">        if (snapshot.euid == 0) &#123;</span><br><span class="line">            syslog(LOG_WARNING, &quot;进程 %d 以 root 权限运行&quot;, snapshot.pid);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="场景3：权限恢复"><a href="#场景3：权限恢复" class="headerlink" title="场景3：权限恢复"></a>场景3：权限恢复</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">int restore_original_privileges() &#123;</span><br><span class="line">    uid_t ruid, euid, suid;</span><br><span class="line">    gid_t rgid, egid, sgid;</span><br><span class="line">    </span><br><span class="line">    if (getresuid(&amp;ruid, &amp;euid, &amp;suid) == -1 ||</span><br><span class="line">        getresgid(&amp;rgid, &amp;egid, &amp;sgid) == -1) &#123;</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 恢复到原始身份</span><br><span class="line">    return setresuid(ruid, ruid, ruid) || setresgid(rgid, rgid, rgid);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="11-注意事项"><a href="#11-注意事项" class="headerlink" title="11. 注意事项"></a>11. 注意事项</h3><p>使用 getresuid 和 getresgid 时需要注意：</p><p>指针有效性: 所有指针参数必须指向有效的内存地址</p><p>错误处理: 虽然很少失败，但仍需检查返回值</p><p>权限检查: 获取其他进程的 ID 信息可能需要权限</p><p>并发安全: 在多线程环境中注意数据一致性</p><p>系统兼容: 在所有现代 Unix&#x2F;Linux 系统中都可用</p><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>getresuid 和 getresgid 是管理进程身份信息的重要函数：</p><p>关键特性:</p><p>完整信息: 一次性获取所有相关的 ID 信息</p><p>原子操作: 保证获取的 ID 组是一致的</p><p>安全相关: 是权限管理和安全审计的基础</p><p>系统调用: 直接访问内核信息，性能良好</p><p>主要应用:</p><p>安全审计和监控工具</p><p>权限管理和切换程序</p><p>系统管理和调试工具</p><p>容器和虚拟化环境中的权限控制</p><p>正确理解和使用这些函数对于编写安全、可靠的 Unix&#x2F;Linux 程序至关重要，特别是在需要进行权限管理和安全检查的场景中。</p><p>getresgid 是 Linux 系统调用，用于获取进程的组 ID 三元组（真实组 ID、有效组 ID 和保存的组 ID）。该函数通过三个 gid_t* 参数返回 ID 值，成功时返回 0，失败返回 -1 并设置 errno。典型用法是检查进程权限状态，常与 getresuid 配合使用。示例代码展示了如何获取并分析这些 ID，包括错误处理和权限切换能力检测。该函数在需要精细控制进程权限时非常有用，特别是在特权程序设计中。</p><p>getresgid系统调用及示例-CSDN博客</p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-getresgid-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-getresgid-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getresgid - 获取进程的真实、有效和保存的组ID</p>
<h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getresgid 是一个 L]]>
    </summary>
    <title>getresgid系统调用及示例</title>
    <updated>2026-06-15T07:56:28.172Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>getitimer系统调用及示例</p><p>继续学习 Linux 系统编程中的重要函数。这次我们介绍 getitimer 和 setitimer 函数，它们用于管理和控制进程的间隔计时器（interval timers）。这些计时器可以在指定的时间后产生信号（通常是 SIGALRM, SIGVTALRM, SIGPROF），从而实现定时执行代码、测量程序执行时间等功能。</p><p>本文介绍了 Linux 系统编程中的间隔计时器函数 getitimer 和 setitimer，它们用于管理和控制进程的定时器。这些计时器可以在指定时间后产生信号（如 SIGALRM），实现定时执行代码或测量程序执行时间等功能。setitimer 设置计时器的超时时间和重载时间，支持三种类型：ITIMER_REAL（实时）、ITIMER_VIRTUAL（用户态 CPU 时间）和 ITIMER_PROF（总 CPU 时间）。getitimer 则获取计时器的当前状态。文章还提供了示例代码，演示如何使用 ITIMER_REAL 和 SIGALRM 实现超时机制，并对比了相关函数如 alarm 和 POSIX 定时器 API。这些功能为系统编程提供了灵活的定时解决方案。</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>getitimer 和 setitimer 是一对 Linux 系统调用，用于获取和设置进程的间隔计时器（interval timers）。</p><ul><li>间隔计时器 (Interval Timer): 这是内核为每个进程维护的一个或多个计时器。每个计时器都有一个类型，当计时器超时（倒计时到 0）时，内核会向进程发送一个特定的信号。</li></ul><p>setitimer: 设置指定类型计时器的超时时间和重载时间。</p><ul><li><p>超时时间 (Value): 从现在开始，计时器倒计时多久后第一次超时并发送信号。</p></li><li><p>重载时间 (Interval): 每次超时后，计时器自动重置并重新开始倒计时的时间。如果重载时间为 0，则计时器是一次性的；如果非 0，则计时器是周期性的。</p></li></ul><p>getitimer: 获取指定类型计时器的当前剩余时间（Value）和设置的重载时间（Interval）。</p><p>这提供了一种基于信号的定时机制，不同于 sleep 或 nanosleep 的主动睡眠，也不同于 alarm 的单一秒级定时器。</p><p>你可以把间隔计时器想象成一个可以设置闹钟和重复周期的高级闹钟：</p><ul><li><p>你可以说：“5 秒后响一次，然后每 2 秒再响一次”（周期性）。</p></li><li><p>或者：“3 秒后响一次，之后不再响”（一次性）。</p></li></ul><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/time.h&gt; // 必需</span><br><span class="line"></span><br><span class="line">// 获取间隔计时器的当前设置</span><br><span class="line">int getitimer(int which, struct itimerval *curr_value);</span><br><span class="line"></span><br><span class="line">// 设置间隔计时器</span><br><span class="line">int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><ul><li><p>getitimer: 查询由 which 指定的计时器的当前状态（剩余时间和重载时间），并将结果存储在 curr_value 指向的 struct itimerval 结构体中。</p></li><li><p>setitimer: 根据 new_value 设置由 which 指定的计时器。如果 old_value 非 NULL，则在设置新值之前，将计时器的旧值（设置前的剩余时间和重载时间）存储在 old_value 指向的结构体中。</p></li></ul><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><h4 id="共同参数"><a href="#共同参数" class="headerlink" title="共同参数"></a>共同参数</h4><p>int which: 指定要操作的计时器类型。Linux 上有三种主要类型：</p><p>ITIMER_REAL: 实时计时器。</p><ul><li><p>时钟源: 系统实时时间（墙上时钟时间）。</p></li><li><p>超时信号: SIGALRM。</p></li><li><p>用途: 测量真实世界流逝的时间。</p></li></ul><p>ITIMER_VIRTUAL: 虚拟计时器。</p><ul><li><p>时钟源: 进程在用户态（执行程序代码）下花费的 CPU 时间。</p></li><li><p>超时信号: SIGVTALRM。</p></li><li><p>用途: 测量进程自身执行代码所用的时间，不包括内核态时间和被阻塞的时间。</p></li></ul><p>ITIMER_PROF: 性能计时器（Profile Timer）。</p><ul><li><p>时钟源: 进程在用户态和内核态（执行系统调用等）下花费的总 CPU 时间。</p></li><li><p>超时信号: SIGPROF。</p></li><li><p>用途: 常用于性能分析（profiling），测量程序执行（包括系统调用）的总 CPU 时间。</p></li></ul><h4 id="setitimer-特有参数"><a href="#setitimer-特有参数" class="headerlink" title="setitimer 特有参数"></a>setitimer 特有参数</h4><ul><li><p>const struct itimerval *new_value: 指向一个 struct itimerval 结构体的指针，该结构体定义了新的计时器设置。</p></li><li><p>struct itimerval *old_value: 指向一个 struct itimerval 结构体的指针，用于接收计时器的旧设置。如果不需要旧值，可以传入 NULL。</p></li></ul><h4 id="struct-itimerval-结构体"><a href="#struct-itimerval-结构体" class="headerlink" title="struct itimerval 结构体"></a>struct itimerval 结构体</h4><p>这两个函数都使用 struct itimerval 来表示时间间隔：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">struct itimerval &#123;</span><br><span class="line">    struct timeval it_interval; // 重载时间 (Interval)</span><br><span class="line">    struct timeval it_value;    // 当前值/超时时间 (Value)</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>其中 struct timeval 定义了秒和微秒：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">struct timeval &#123;</span><br><span class="line">    time_t      tv_sec;         // 秒</span><br><span class="line">    suseconds_t tv_usec;        // 微秒 (0 - 999,999)</span><br><span class="line">&#125;;</span><br><span class="line"></span><br></pre></td></tr></table></figure><ul><li><p>it_value: 当前计时器的剩余时间。当调用 setitimer 时，它指定了第一次超时的时间。当调用 getitimer 时，它返回计时器当前还剩多少时间。</p></li><li><p>it_interval: 重载时间。指定计时器超时后，自动重新开始计时的时间间隔。如果这个值为 0，则计时器是一次性的。</p></li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时: 返回 0。</p></li><li><p>失败时: 返回 -1，并设置全局变量 errno 来指示具体的错误原因（例如 EINVAL which 无效或时间值无效，EFAULT 指针无效等）。</p></li></ul><h3 id="6-相似函数，或关联函数"><a href="#6-相似函数，或关联函数" class="headerlink" title="6. 相似函数，或关联函数"></a>6. 相似函数，或关联函数</h3><ul><li><p>alarm: 一个更简单的函数，只操作 ITIMER_REAL 计时器，且精度为秒。alarm(seconds) 大致等价于 setitimer(ITIMER_REAL, …)，其中 it_value.tv_sec &#x3D; seconds 且 it_interval.tv_sec &#x3D; 0。</p></li><li><p>signal, sigaction: 用于设置当计时器超时时（收到 SIGALRM, SIGVTALRM, SIGPROF 信号）应执行的操作。</p></li><li><p>nanosleep, clock_nanosleep: 提供高精度的主动睡眠，不基于信号。</p></li><li><p>clock_gettime, clock_settime: 用于获取和设置各种系统时钟，更现代和灵活。</p></li><li><p>timer_create, timer_settime, timer_gettime: POSIX 定时器 API，功能更强大，支持多种时钟源和多种通知方式（包括信号和线程通知），是 setitimer 的现代替代品。</p></li></ul><h3 id="7-示例代码"><a href="#7-示例代码" class="headerlink" title="7. 示例代码"></a>7. 示例代码</h3><h4 id="示例-1：使用-ITIMER-REAL-和-SIGALRM-实现超时"><a href="#示例-1：使用-ITIMER-REAL-和-SIGALRM-实现超时" class="headerlink" title="示例 1：使用 ITIMER_REAL 和 SIGALRM 实现超时"></a>示例 1：使用 ITIMER_REAL 和 SIGALRM 实现超时</h4><p>这个例子演示了如何使用 ITIMER_REAL 计时器在 3 秒后发送 SIGALRM 信号来中断一个可能长时间运行的操作。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/time.h&gt; // setitimer, getitimer, ITIMER_REAL, struct itimerval</span><br><span class="line">#include &lt;signal.h&gt;   // signal, SIGALRM</span><br><span class="line">#include &lt;unistd.h&gt;   // pause, write</span><br><span class="line">#include &lt;stdio.h&gt;    // printf, perror</span><br><span class="line">#include &lt;stdlib.h&gt;   // exit</span><br><span class="line">#include &lt;errno.h&gt;    // errno</span><br><span class="line">#include &lt;string.h&gt;   // strerror</span><br><span class="line"></span><br><span class="line">volatile sig_atomic_t alarm_received = 0;</span><br><span class="line"></span><br><span class="line">// SIGALRM 信号处理函数</span><br><span class="line">void alarm_handler(int sig) &#123;</span><br><span class="line">    // 在信号处理函数中，应只调用异步信号安全的函数</span><br><span class="line">    write(STDERR_FILENO, &quot;Timeout! SIGALRM received.\n&quot;, 27);</span><br><span class="line">    alarm_received = 1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct itimerval timer;</span><br><span class="line">    const char *msg = &quot;Doing some work that might take a long time...\n&quot;;</span><br><span class="line">    const char *msg_len = &quot;Done.\n&quot;;</span><br><span class="line"></span><br><span class="line">    // 1. 设置 SIGALRM 信号处理函数</span><br><span class="line">    if (signal(SIGALRM, alarm_handler) == SIG_ERR) &#123;</span><br><span class="line">        perror(&quot;signal SIGALRM&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 2. 配置 ITIMER_REAL 计时器</span><br><span class="line">    // it_value: 3 秒后超时</span><br><span class="line">    timer.it_value.tv_sec = 3;</span><br><span class="line">    timer.it_value.tv_usec = 0;</span><br><span class="line">    // it_interval: 0 表示一次性计时器，超时后不重载</span><br><span class="line">    timer.it_interval.tv_sec = 0;</span><br><span class="line">    timer.it_interval.tv_usec = 0;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Setting ITIMER_REAL to expire in 3 seconds.\n&quot;);</span><br><span class="line"></span><br><span class="line">    // 3. 启动计时器</span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 4. 模拟一个可能长时间运行的操作</span><br><span class="line">    write(STDOUT_FILENO, msg, 46);</span><br><span class="line"></span><br><span class="line">    // 5. 等待操作完成或超时</span><br><span class="line">    // 这里用 pause() 模拟等待，实际可能是 read(), write(), connect() 等阻塞调用</span><br><span class="line">    while (!alarm_received) &#123;</span><br><span class="line">        // 在实际应用中，这里可能是真正的阻塞操作</span><br><span class="line">        // 为了演示，我们用 pause() 等待信号</span><br><span class="line">        printf(&quot;Waiting for work to complete or timeout...\n&quot;);</span><br><span class="line">        pause(); // 进程挂起，直到收到信号</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    write(STDOUT_FILENO, msg_len, 6);</span><br><span class="line">    printf(&quot;Program finished after timeout.\n&quot;);</span><br><span class="line"></span><br><span class="line">    // 6. (可选) 检查计时器状态</span><br><span class="line">    struct itimerval curr_timer;</span><br><span class="line">    if (getitimer(ITIMER_REAL, &amp;curr_timer) == -1) &#123;</span><br><span class="line">        perror(&quot;getitimer&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;Current ITIMER_REAL setting:\n&quot;);</span><br><span class="line">        printf(&quot;  it_value: %ld.%06ld seconds (should be 0)\n&quot;,</span><br><span class="line">               (long)curr_timer.it_value.tv_sec, (long)curr_timer.it_value.tv_usec);</span><br><span class="line">        printf(&quot;  it_interval: %ld.%06ld seconds\n&quot;,</span><br><span class="line">               (long)curr_timer.it_interval.tv_sec, (long)curr_timer.it_interval.tv_usec);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>定义一个全局的 volatile sig_atomic_t 变量 alarm_received 用于信号处理函数和主循环间通信。</p><p>定义 SIGALRM 的信号处理函数 alarm_handler。当计时器超时，内核会发送 SIGALRM 信号，该函数会被调用，打印消息并设置标志。</p><p>在 main 函数中，使用 signal() 注册 SIGALRM 处理函数。</p><p>定义一个 struct itimerval 变量 timer。</p><p>设置 timer.it_value 为 3 秒，表示 3 秒后第一次超时。</p><p>设置 timer.it_interval 为 0，表示这是一次性计时器。</p><p>调用 setitimer(ITIMER_REAL, &amp;timer, NULL) 启动计时器。</p><p>模拟一个长时间运行的操作（这里只是打印一条消息）。</p><p>进入一个循环，等待操作完成或超时。这里用 pause() 模拟等待，实际应用中可能是 read, write, connect 等阻塞调用。</p><p>当 SIGALRM 信号到达，alarm_handler 被调用，设置 alarm_received 为 1，主循环退出。</p><p>程序结束。</p><p>最后，调用 getitimer 检查计时器的当前状态（超时后，it_value 应该接近 0）。</p><h4 id="示例-2：使用-ITIMER-VIRTUAL-测量-CPU-时间"><a href="#示例-2：使用-ITIMER-VIRTUAL-测量-CPU-时间" class="headerlink" title="示例 2：使用 ITIMER_VIRTUAL 测量 CPU 时间"></a>示例 2：使用 ITIMER_VIRTUAL 测量 CPU 时间</h4><p>这个例子演示如何使用 ITIMER_VIRTUAL 来测量进程在用户态执行代码所花费的 CPU 时间。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/time.h&gt;</span><br><span class="line">#include &lt;signal.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;time.h&gt; // clock()</span><br><span class="line"></span><br><span class="line">volatile sig_atomic_t vt_alarm = 0;</span><br><span class="line"></span><br><span class="line">void vt_alarm_handler(int sig) &#123;</span><br><span class="line">    write(STDERR_FILENO, &quot;Virtual timer expired! (SIGVTALRM)\n&quot;, 35);</span><br><span class="line">    vt_alarm = 1;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">// 模拟一个消耗 CPU 的函数</span><br><span class="line">void cpu_intensive_task() &#123;</span><br><span class="line">    volatile unsigned long sum = 0;</span><br><span class="line">    for (unsigned long i = 0; i &lt; 1000000000UL; ++i) &#123;</span><br><span class="line">        sum += i;</span><br><span class="line">    &#125;</span><br><span class="line">    // 使用 sum 防止编译器优化掉循环</span><br><span class="line">    if (sum % 2 == 0) &#123;</span><br><span class="line">        // do nothing</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct itimerval timer;</span><br><span class="line"></span><br><span class="line">    if (signal(SIGVTALRM, vt_alarm_handler) == SIG_ERR) &#123;</span><br><span class="line">        perror(&quot;signal SIGVTALRM&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 设置 ITIMER_VIRTUAL 在 2 秒 CPU 用户态时间后超时</span><br><span class="line">    timer.it_value.tv_sec = 2;</span><br><span class="line">    timer.it_value.tv_usec = 0;</span><br><span class="line">    timer.it_interval.tv_sec = 0; // 一次性</span><br><span class="line">    timer.it_interval.tv_usec = 0;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Setting ITIMER_VIRTUAL to expire after 2 seconds of user CPU time.\n&quot;);</span><br><span class="line">    printf(&quot;Starting CPU-intensive task...\n&quot;);</span><br><span class="line"></span><br><span class="line">    if (setitimer(ITIMER_VIRTUAL, &amp;timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer ITIMER_VIRTUAL&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 执行消耗 CPU 的任务</span><br><span class="line">    cpu_intensive_task();</span><br><span class="line"></span><br><span class="line">    if (vt_alarm) &#123;</span><br><span class="line">        printf(&quot;Task was interrupted by virtual timer.\n&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;Task completed before virtual timer expired.\n&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 检查计时器状态</span><br><span class="line">    if (getitimer(ITIMER_VIRTUAL, &amp;timer) == -1) &#123;</span><br><span class="line">        perror(&quot;getitimer ITIMER_VIRTUAL&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;ITIMER_VIRTUAL status after task:\n&quot;);</span><br><span class="line">        printf(&quot;  it_value: %ld.%06ld seconds\n&quot;,</span><br><span class="line">               (long)timer.it_value.tv_sec, (long)timer.it_value.tv_usec);</span><br><span class="line">        printf(&quot;  it_interval: %ld.%06ld seconds\n&quot;,</span><br><span class="line">               (long)timer.it_interval.tv_sec, (long)timer.it_interval.tv_usec);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>设置 SIGVTALRM 信号处理函数。</p><p>配置 ITIMER_VIRTUAL 计时器，在进程使用 2 秒用户态 CPU 时间后超时。</p><p>调用 setitimer 启动计时器。</p><p>执行一个消耗大量 CPU 时间的函数 cpu_intensive_task。</p><p>如果在函数执行完毕前计时器超时，vt_alarm 标志会被设置，表示任务被中断。</p><p>最后检查计时器状态。</p><h4 id="示例-3：使用-ITIMER-REAL-实现周期性操作"><a href="#示例-3：使用-ITIMER-REAL-实现周期性操作" class="headerlink" title="示例 3：使用 ITIMER_REAL 实现周期性操作"></a>示例 3：使用 ITIMER_REAL 实现周期性操作</h4><p>这个例子演示如何使用 ITIMER_REAL 实现一个周期性的“心跳”信号，每秒触发一次。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/time.h&gt;</span><br><span class="line">#include &lt;signal.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;stdatomic.h&gt; // C11 原子操作</span><br><span class="line"></span><br><span class="line">volatile atomic_int heartbeat_count = 0;</span><br><span class="line"></span><br><span class="line">void heartbeat_handler(int sig) &#123;</span><br><span class="line">    // 原子性地增加计数</span><br><span class="line">    atomic_fetch_add(&amp;heartbeat_count, 1);</span><br><span class="line">    // write 是异步信号安全的</span><br><span class="line">    write(STDERR_FILENO, &quot;Heartbeat (SIGALRM)!\n&quot;, 21);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct itimerval timer;</span><br><span class="line">    int count_before_exit = 5;</span><br><span class="line"></span><br><span class="line">    if (signal(SIGALRM, heartbeat_handler) == SIG_ERR) &#123;</span><br><span class="line">        perror(&quot;signal SIGALRM&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 设置周期性计时器：立即启动，每 1 秒触发一次</span><br><span class="line">    timer.it_value.tv_sec = 1;    // 1 秒后第一次超时</span><br><span class="line">    timer.it_value.tv_usec = 0;</span><br><span class="line">    timer.it_interval.tv_sec = 1; // 之后每 1 秒超时一次 (周期性)</span><br><span class="line">    timer.it_interval.tv_usec = 0;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Setting periodic ITIMER_REAL (heartbeat every 1 second)...\n&quot;);</span><br><span class="line">    printf(&quot;Will exit after %d heartbeats.\n&quot;, count_before_exit);</span><br><span class="line"></span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer periodic&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 等待指定次数的心跳</span><br><span class="line">    while (atomic_load(&amp;heartbeat_count) &lt; count_before_exit) &#123;</span><br><span class="line">        pause(); // 等待信号</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Received %d heartbeats. Exiting.\n&quot;, count_before_exit);</span><br><span class="line"></span><br><span class="line">    // 停止计时器 (设置所有时间为 0)</span><br><span class="line">    struct itimerval stop_timer = &#123;&#123;0, 0&#125;, &#123;0, 0&#125;&#125;;</span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;stop_timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer stop&quot;);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>使用 atomic_int 和 atomic_fetch_add 来安全地在信号处理函数中增加计数。</p><p>配置 ITIMER_REAL 计时器：</p><ul><li><p>it_value: 1 秒后第一次超时。</p></li><li><p>it_interval: 1 秒，使计时器周期性地每秒超时一次。</p></li></ul><p>调用 setitimer 启动周期性计时器。</p><p>在主循环中使用 pause() 等待信号。</p><p>每次收到 SIGALRM 信号，信号处理函数打印消息并增加计数。</p><p>当计数达到预定值时，主循环退出。</p><p>通过设置计时器的 it_value 和 it_interval 都为 0 来停止计时器。</p><h4 id="示例-4：使用-setitimer-的-old-value-参数"><a href="#示例-4：使用-setitimer-的-old-value-参数" class="headerlink" title="示例 4：使用 setitimer 的 old_value 参数"></a>示例 4：使用 setitimer 的 old_value 参数</h4><p>这个例子演示如何使用 old_value 参数来保存和恢复计时器的旧设置。</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/time.h&gt;</span><br><span class="line">#include &lt;signal.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line"></span><br><span class="line">void alarm_handler(int sig) &#123;</span><br><span class="line">    write(STDERR_FILENO, &quot;SIGALRM received.\n&quot;, 18);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">void print_timer(const char *name, const struct itimerval *timer) &#123;</span><br><span class="line">    printf(&quot;%s:\n&quot;, name);</span><br><span class="line">    printf(&quot;  Current value: %ld.%06ld seconds\n&quot;,</span><br><span class="line">           (long)timer-&gt;it_value.tv_sec, (long)timer-&gt;it_value.tv_usec);</span><br><span class="line">    printf(&quot;  Interval: %ld.%06ld seconds\n&quot;,</span><br><span class="line">           (long)timer-&gt;it_interval.tv_sec, (long)timer-&gt;it_interval.tv_usec);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    struct itimerval old_timer, new_timer;</span><br><span class="line"></span><br><span class="line">    if (signal(SIGALRM, alarm_handler) == SIG_ERR) &#123;</span><br><span class="line">        perror(&quot;signal SIGALRM&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    // 1. 设置一个初始的计时器 (5秒后超时，不重复)</span><br><span class="line">    new_timer.it_value.tv_sec = 5;</span><br><span class="line">    new_timer.it_value.tv_usec = 0;</span><br><span class="line">    new_timer.it_interval.tv_sec = 0;</span><br><span class="line">    new_timer.it_interval.tv_usec = 0;</span><br><span class="line"></span><br><span class="line">    printf(&quot;Setting initial timer for 5 seconds.\n&quot;);</span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;new_timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer initial&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    sleep(2); // 等待 2 秒</span><br><span class="line"></span><br><span class="line">    // 2. 获取当前计时器状态 (应该剩余约 3 秒)</span><br><span class="line">    if (getitimer(ITIMER_REAL, &amp;old_timer) == -1) &#123;</span><br><span class="line">        perror(&quot;getitimer before override&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    print_timer(&quot;Timer status after 2 seconds&quot;, &amp;old_timer);</span><br><span class="line"></span><br><span class="line">    // 3. 设置一个新计时器 (1秒后超时)，并保存旧设置</span><br><span class="line">    new_timer.it_value.tv_sec = 1;</span><br><span class="line">    new_timer.it_value.tv_usec = 0;</span><br><span class="line">    new_timer.it_interval.tv_sec = 0;</span><br><span class="line">    new_timer.it_interval.tv_usec = 0;</span><br><span class="line"></span><br><span class="line">    printf(&quot;\nOverriding timer to expire in 1 second, saving old setting.\n&quot;);</span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;new_timer, &amp;old_timer) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer override&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    print_timer(&quot;Old timer setting saved&quot;, &amp;old_timer);</span><br><span class="line"></span><br><span class="line">    printf(&quot;Waiting for 1-second timer to expire...\n&quot;);</span><br><span class="line">    pause(); // 等待 1 秒计时器超时</span><br><span class="line"></span><br><span class="line">    // 4. 恢复旧的计时器设置</span><br><span class="line">    printf(&quot;\nRestoring old timer setting.\n&quot;);</span><br><span class="line">    if (setitimer(ITIMER_REAL, &amp;old_timer, NULL) == -1) &#123;</span><br><span class="line">        perror(&quot;setitimer restore&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    if (getitimer(ITIMER_REAL, &amp;new_timer) == -1) &#123;</span><br><span class="line">        perror(&quot;getitimer after restore&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    print_timer(&quot;Timer status after restore&quot;, &amp;new_timer);</span><br><span class="line"></span><br><span class="line">    printf(&quot;Waiting for restored timer to expire...\n&quot;);</span><br><span class="line">    pause(); // 等待恢复的计时器超时</span><br><span class="line"></span><br><span class="line">    printf(&quot;Restored timer expired. Program finished.\n&quot;);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>代码解释:</p><p>设置一个 5 秒后超时的初始计时器。</p><p>等待 2 秒后，调用 getitimer 获取当前计时器状态（剩余约 3 秒）。</p><p>调用 setitimer(ITIMER_REAL, &amp;new_timer, &amp;old_timer) 设置一个 1 秒后超时的新计时器，并将旧计时器的设置（剩余约 3 秒）保存在 old_timer 变量中。</p><p>等待 1 秒计时器超时。</p><p>调用 setitimer(ITIMER_REAL, &amp;old_timer, NULL) 将计时器恢复为之前保存的设置（约 3 秒）。</p><p>再次调用 getitimer 验证恢复是否成功。</p><p>等待恢复的计时器超时。</p><p>重要提示与注意事项:</p><p>精度: setitimer 的时间精度是微秒（tv_usec），而 nanosleep 和 POSIX 定时器 (timer_) 支持纳秒精度。对于高精度需求，后者是更好的选择。</p><p>信号处理: 使用 setitimer 必然涉及信号处理。必须小心编写信号处理函数，只使用异步信号安全的函数。</p><p>竞态条件: 在设置信号处理函数和启动计时器之间，或者在检查标志和调用 pause 之间，可能存在竞态条件。使用 sigsuspend 可以更安全地处理。</p><p>现代替代: timer_create, timer_settime 等 POSIX 定时器函数提供了更强大和灵活的功能，例如可以选择不同的通知方式（信号、线程特定信号、过期计数等）和不同的时钟源（CLOCK_REALTIME, CLOCK_MONOTONIC 等），是 setitimer 的推荐现代替代方案。</p><p>总结:</p><p>getitimer 和 setitimer 提供了一套基于信号的进程间隔计时器机制。它们可以用于实现超时、周期性任务和 CPU 时间测量等功能。理解三种计时器类型（ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF）及其对应的信号是掌握这些函数的关键。虽然它们功能强大，但在现代编程中，timer_ 系列的 POSIX 定时器通常被认为是更优的选择。</p><p>getitimer系统调用及示例-CSDN博客</p><p><a href="https://www.calcguide.tech/2025/09/09/gettitimer-syscall-demo/">https://www.calcguide.tech/2025/09/09/gettitimer-syscall-demo/</a></p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/09/2025-09-09-gettitimer-syscall-demo/</id>
    <link href="https://blog.calcguide.tech/2025/09/09/2025-09-09-gettitimer-syscall-demo/"/>
    <published>2025-09-08T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>getitimer系统调用及示例</p>
<p>继续学习 Linux 系统编程中的重要函数。这次我们介绍 getitimer 和 setitimer 函数，它们用于管理和控制进程的间隔计时器（interval timers）。这些计时器可以在指定的时间后产生信号（通常是 S]]>
    </summary>
    <title>getitimer系统调用及示例</title>
    <updated>2026-06-15T07:56:28.173Z</updated>
  </entry>
  <entry>
    <author>
      <name>CalcGuide</name>
    </author>
    <category term="Linux系统编程" scheme="https://blog.calcguide.tech/categories/Linux%E7%B3%BB%E7%BB%9F%E7%BC%96%E7%A8%8B/"/>
    <category term="技术" scheme="https://blog.calcguide.tech/tags/%E6%8A%80%E6%9C%AF/"/>
    <content>
      <![CDATA[<p>fremovexattr - 删除文件的扩展属性（通过文件描述符）</p><h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>fremovexattr 是一个 Linux 系统调用，用于删除指定文件的特定扩展属性（extended attribute）。与 removexattr 不同，fremovexattr 通过文件描述符而不是文件路径来操作文件，这样可以避免在多线程环境中因文件重命名或删除而导致的竞态条件。</p><p>扩展属性是文件系统提供的一种机制，允许用户为文件关联额外的元数据，这些元数据以键值对的形式存储。删除扩展属性可以清理不再需要的元数据信息。</p><h3 id="2-函数原型"><a href="#2-函数原型" class="headerlink" title="2. 函数原型"></a>2. 函数原型</h3><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;attr/xattr.h&gt;</span><br><span class="line"></span><br><span class="line">int fremovexattr(int fd, const char *name);</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="3-功能"><a href="#3-功能" class="headerlink" title="3. 功能"></a>3. 功能</h3><p>删除通过文件描述符指定的文件的指定名称的扩展属性。如果该属性不存在，则返回错误。</p><h3 id="4-参数"><a href="#4-参数" class="headerlink" title="4. 参数"></a>4. 参数</h3><ul><li>int fd: 文件描述符，通过 open() 等函数获得</li></ul><p>const char *name: 要删除的扩展属性的名称（包括命名空间前缀）</p><ul><li>例如：”user.my_attribute”, “security.selinux”, “trusted.my_trusted_attr”</li></ul><h3 id="5-返回值"><a href="#5-返回值" class="headerlink" title="5. 返回值"></a>5. 返回值</h3><ul><li><p>成功时返回 0</p></li><li><p>失败时返回 -1，并设置 errno</p></li></ul><h3 id="6-常见-errno-错误码"><a href="#6-常见-errno-错误码" class="headerlink" title="6. 常见 errno 错误码"></a>6. 常见 errno 错误码</h3><ul><li><p>EBADF: 无效的文件描述符</p></li><li><p>ENOTSUP: 文件系统不支持扩展属性</p></li><li><p>EACCES: 权限不足（删除某些命名空间的属性需要特殊权限）</p></li><li><p>ENODATA: 指定的扩展属性不存在</p></li><li><p>ENOTDIR: 文件描述符指向的不是目录（在某些情况下）</p></li><li><p>EPERM: 操作被拒绝（如尝试删除系统保护的属性）</p></li><li><p>EROFS: 文件位于只读文件系统上</p></li><li><p>ENOMEM: 内存不足</p></li></ul><h3 id="7-相似函数，或关联函数"><a href="#7-相似函数，或关联函数" class="headerlink" title="7. 相似函数，或关联函数"></a>7. 相似函数，或关联函数</h3><ul><li><p>removexattr(): 通过文件路径删除扩展属性</p></li><li><p>lremovexattr(): 删除符号链接本身的扩展属性（不跟随链接）</p></li><li><p>fgetxattr(): 通过文件描述符获取扩展属性值</p></li><li><p>fsetxattr(): 通过文件描述符设置扩展属性</p></li><li><p>flistxattr(): 通过文件描述符列出所有扩展属性名称</p></li><li><p>getxattr(), setxattr(), listxattr(): 对应的路径版本</p></li></ul><h3 id="8-示例代码"><a href="#8-示例代码" class="headerlink" title="8. 示例代码"></a>8. 示例代码</h3><h4 id="示例1：基本使用-删除扩展属性"><a href="#示例1：基本使用-删除扩展属性" class="headerlink" title="示例1：基本使用 - 删除扩展属性"></a>示例1：基本使用 - 删除扩展属性</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;attr/xattr.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    int ret;</span><br><span class="line">    </span><br><span class="line">    // 创建测试文件</span><br><span class="line">    fd = open(&quot;test_file.txt&quot;, O_CREAT | O_RDWR | O_TRUNC, 0644);</span><br><span class="line">    if (fd == -1) &#123;</span><br><span class="line">        perror(&quot;创建文件失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功创建文件，文件描述符: %d\n&quot;, fd);</span><br><span class="line">    </span><br><span class="line">    // 先设置一个扩展属性</span><br><span class="line">    const char *attr_name = &quot;user.test_attribute&quot;;</span><br><span class="line">    const char *attr_value = &quot;This is a test value&quot;;</span><br><span class="line">    </span><br><span class="line">    ret = fsetxattr(fd, attr_name, attr_value, strlen(attr_value), 0);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;设置扩展属性失败&quot;);</span><br><span class="line">        close(fd);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功设置扩展属性: %s = %s\n&quot;, attr_name, attr_value);</span><br><span class="line">    </span><br><span class="line">    // 验证属性是否存在</span><br><span class="line">    char buffer&amp;#91;256];</span><br><span class="line">    ssize_t size = fgetxattr(fd, attr_name, buffer, sizeof(buffer) - 1);</span><br><span class="line">    if (size != -1) &#123;</span><br><span class="line">        buffer&amp;#91;size] = &#x27;\0&#x27;;</span><br><span class="line">        printf(&quot;验证 - 属性值: %s\n&quot;, buffer);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 删除扩展属性</span><br><span class="line">    ret = fremovexattr(fd, attr_name);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        perror(&quot;删除扩展属性失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;成功删除扩展属性: %s\n&quot;, attr_name);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 再次尝试获取已删除的属性（应该失败）</span><br><span class="line">    size = fgetxattr(fd, attr_name, buffer, sizeof(buffer) - 1);</span><br><span class="line">    if (size == -1) &#123;</span><br><span class="line">        if (errno == ENODATA) &#123;</span><br><span class="line">            printf(&quot;确认：扩展属性 %s 已被成功删除\n&quot;, attr_name);</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            perror(&quot;获取已删除属性时出现意外错误&quot;);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    close(fd);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例2：错误处理和权限检查"><a href="#示例2：错误处理和权限检查" class="headerlink" title="示例2：错误处理和权限检查"></a>示例2：错误处理和权限检查</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;attr/xattr.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">void test_remove_attribute(int fd, const char *attr_name) &#123;</span><br><span class="line">    printf(&quot;\n尝试删除属性: %s\n&quot;, attr_name);</span><br><span class="line">    </span><br><span class="line">    int ret = fremovexattr(fd, attr_name);</span><br><span class="line">    if (ret == -1) &#123;</span><br><span class="line">        switch (errno) &#123;</span><br><span class="line">            case ENODATA:</span><br><span class="line">                printf(&quot;  错误: 属性 &#x27;%s&#x27; 不存在\n&quot;, attr_name);</span><br><span class="line">                break;</span><br><span class="line">            case EACCES:</span><br><span class="line">                printf(&quot;  错误: 权限不足，无法删除属性 &#x27;%s&#x27;\n&quot;, attr_name);</span><br><span class="line">                break;</span><br><span class="line">            case ENOTSUP:</span><br><span class="line">                printf(&quot;  错误: 文件系统不支持扩展属性\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            case EPERM:</span><br><span class="line">                printf(&quot;  错误: 操作被拒绝，无法删除属性 &#x27;%s&#x27;\n&quot;, attr_name);</span><br><span class="line">                break;</span><br><span class="line">            case EROFS:</span><br><span class="line">                printf(&quot;  错误: 文件系统为只读，无法删除属性\n&quot;);</span><br><span class="line">                break;</span><br><span class="line">            default:</span><br><span class="line">                printf(&quot;  错误: %s (errno: %d)\n&quot;, strerror(errno), errno);</span><br><span class="line">                break;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;  成功删除属性: %s\n&quot;, attr_name);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    </span><br><span class="line">    // 打开系统文件进行测试（需要适当权限）</span><br><span class="line">    fd = open(&quot;test_file.txt&quot;, O_CREAT | O_RDWR | O_TRUNC, 0644);</span><br><span class="line">    if (fd == -1) &#123;</span><br><span class="line">        perror(&quot;创建测试文件失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;成功创建测试文件，文件描述符: %d\n&quot;, fd);</span><br><span class="line">    </span><br><span class="line">    // 设置一些测试属性</span><br><span class="line">    const char *user_attr = &quot;user.test_attr&quot;;</span><br><span class="line">    const char *value = &quot;test value&quot;;</span><br><span class="line">    </span><br><span class="line">    if (fsetxattr(fd, user_attr, value, strlen(value), 0) == -1) &#123;</span><br><span class="line">        perror(&quot;设置测试属性失败&quot;);</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        printf(&quot;设置测试属性: %s\n&quot;, user_attr);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 测试删除存在的属性</span><br><span class="line">    test_remove_attribute(fd, user_attr);</span><br><span class="line">    </span><br><span class="line">    // 测试删除不存在的属性</span><br><span class="line">    test_remove_attribute(fd, &quot;user.nonexistent_attr&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试删除无效命名空间的属性</span><br><span class="line">    test_remove_attribute(fd, &quot;invalid.namespace.attr&quot;);</span><br><span class="line">    </span><br><span class="line">    // 测试删除空名称的属性</span><br><span class="line">    test_remove_attribute(fd, &quot;&quot;);</span><br><span class="line">    </span><br><span class="line">    close(fd);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h4 id="示例3：批量操作和属性管理"><a href="#示例3：批量操作和属性管理" class="headerlink" title="示例3：批量操作和属性管理"></a>示例3：批量操作和属性管理</h4><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br></pre></td><td class="code"><pre><span class="line">#include &lt;stdio.h&gt;</span><br><span class="line">#include &lt;stdlib.h&gt;</span><br><span class="line">#include &lt;fcntl.h&gt;</span><br><span class="line">#include &lt;unistd.h&gt;</span><br><span class="line">#include &lt;sys/types.h&gt;</span><br><span class="line">#include &lt;attr/xattr.h&gt;</span><br><span class="line">#include &lt;errno.h&gt;</span><br><span class="line">#include &lt;string.h&gt;</span><br><span class="line"></span><br><span class="line">// 列出并删除所有 user.* 命名空间的属性</span><br><span class="line">int remove_user_attributes(int fd) &#123;</span><br><span class="line">    ssize_t list_size;</span><br><span class="line">    char *list_buffer;</span><br><span class="line">    char *current;</span><br><span class="line">    int removed_count = 0;</span><br><span class="line">    </span><br><span class="line">    // 获取扩展属性列表大小</span><br><span class="line">    list_size = flistxattr(fd, NULL, 0);</span><br><span class="line">    if (list_size == -1) &#123;</span><br><span class="line">        perror(&quot;获取属性列表大小失败&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    if (list_size == 0) &#123;</span><br><span class="line">        printf(&quot;没有扩展属性需要删除\n&quot;);</span><br><span class="line">        return 0;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 分配缓冲区</span><br><span class="line">    list_buffer = malloc(list_size);</span><br><span class="line">    if (list_buffer == NULL) &#123;</span><br><span class="line">        perror(&quot;内存分配失败&quot;);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 获取扩展属性列表</span><br><span class="line">    if (flistxattr(fd, list_buffer, list_size) == -1) &#123;</span><br><span class="line">        perror(&quot;获取属性列表失败&quot;);</span><br><span class="line">        free(list_buffer);</span><br><span class="line">        return -1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 遍历所有属性，删除 user.* 命名空间的属性</span><br><span class="line">    current = list_buffer;</span><br><span class="line">    while (current &lt; list_buffer + list_size) &#123;</span><br><span class="line">        // 检查是否为 user. 命名空间</span><br><span class="line">        if (strncmp(current, &quot;user.&quot;, 5) == 0) &#123;</span><br><span class="line">            printf(&quot;删除 user 属性: %s\n&quot;, current);</span><br><span class="line">            </span><br><span class="line">            if (fremovexattr(fd, current) == -1) &#123;</span><br><span class="line">                fprintf(stderr, &quot;删除属性 %s 失败: %s\n&quot;, current, strerror(errno));</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                removed_count++;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;跳过非 user 属性: %s\n&quot;, current);</span><br><span class="line">        &#125;</span><br><span class="line">        </span><br><span class="line">        current += strlen(current) + 1;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    free(list_buffer);</span><br><span class="line">    return removed_count;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">int main() &#123;</span><br><span class="line">    int fd;</span><br><span class="line">    int result;</span><br><span class="line">    </span><br><span class="line">    // 创建测试文件</span><br><span class="line">    fd = open(&quot;managed_file.txt&quot;, O_CREAT | O_RDWR | O_TRUNC, 0644);</span><br><span class="line">    if (fd == -1) &#123;</span><br><span class="line">        perror(&quot;创建文件失败&quot;);</span><br><span class="line">        exit(EXIT_FAILURE);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    printf(&quot;创建测试文件，文件描述符: %d\n&quot;, fd);</span><br><span class="line">    </span><br><span class="line">    // 设置多个不同命名空间的属性</span><br><span class="line">    const char *attrs&amp;#91;]&amp;#91;2] = &#123;</span><br><span class="line">        &#123;&quot;user.attr1&quot;, &quot;value1&quot;&#125;,</span><br><span class="line">        &#123;&quot;user.attr2&quot;, &quot;value2&quot;&#125;,</span><br><span class="line">        &#123;&quot;user.backup_info&quot;, &quot;backup data&quot;&#125;,</span><br><span class="line">        &#123;&quot;trusted.admin_note&quot;, &quot;admin only&quot;&#125;,</span><br><span class="line">        &#123;&quot;security.context&quot;, &quot;security label&quot;&#125;</span><br><span class="line">    &#125;;</span><br><span class="line">    </span><br><span class="line">    int attr_count = sizeof(attrs) / sizeof(attrs&amp;#91;0]);</span><br><span class="line">    </span><br><span class="line">    printf(&quot;设置测试属性:\n&quot;);</span><br><span class="line">    for (int i = 0; i &lt; attr_count; i++) &#123;</span><br><span class="line">        if (fsetxattr(fd, attrs&amp;#91;i]&amp;#91;0], attrs&amp;#91;i]&amp;#91;1], strlen(attrs&amp;#91;i]&amp;#91;1]), 0) == -1) &#123;</span><br><span class="line">            fprintf(stderr, &quot;设置属性 %s 失败: %s\n&quot;, attrs&amp;#91;i]&amp;#91;0], strerror(errno));</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            printf(&quot;  %s = %s\n&quot;, attrs&amp;#91;i]&amp;#91;0], attrs&amp;#91;i]&amp;#91;1]);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 列出所有属性</span><br><span class="line">    printf(&quot;\n当前所有扩展属性:\n&quot;);</span><br><span class="line">    ssize_t list_size = flistxattr(fd, NULL, 0);</span><br><span class="line">    if (list_size &gt; 0) &#123;</span><br><span class="line">        char *list_buffer = malloc(list_size);</span><br><span class="line">        if (list_buffer) &#123;</span><br><span class="line">            flistxattr(fd, list_buffer, list_size);</span><br><span class="line">            char *current = list_buffer;</span><br><span class="line">            while (current &lt; list_buffer + list_size) &#123;</span><br><span class="line">                printf(&quot;  %s\n&quot;, current);</span><br><span class="line">                current += strlen(current) + 1;</span><br><span class="line">            &#125;</span><br><span class="line">            free(list_buffer);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 删除所有 user.* 属性</span><br><span class="line">    printf(&quot;\n删除 user.* 命名空间的属性:\n&quot;);</span><br><span class="line">    result = remove_user_attributes(fd);</span><br><span class="line">    if (result &gt;= 0) &#123;</span><br><span class="line">        printf(&quot;成功删除 %d 个 user.* 属性\n&quot;, result);</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    // 验证剩余属性</span><br><span class="line">    printf(&quot;\n删除后的扩展属性:\n&quot;);</span><br><span class="line">    list_size = flistxattr(fd, NULL, 0);</span><br><span class="line">    if (list_size &gt; 0) &#123;</span><br><span class="line">        char *list_buffer = malloc(list_size);</span><br><span class="line">        if (list_buffer) &#123;</span><br><span class="line">            flistxattr(fd, list_buffer, list_size);</span><br><span class="line">            char *current = list_buffer;</span><br><span class="line">            while (current &lt; list_buffer + list_size) &#123;</span><br><span class="line">                printf(&quot;  %s\n&quot;, current);</span><br><span class="line">                current += strlen(current) + 1;</span><br><span class="line">            &#125;</span><br><span class="line">            free(list_buffer);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    close(fd);</span><br><span class="line">    return 0;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><h3 id="9-扩展属性命名空间权限说明"><a href="#9-扩展属性命名空间权限说明" class="headerlink" title="9. 扩展属性命名空间权限说明"></a>9. 扩展属性命名空间权限说明</h3><p>不同命名空间的扩展属性有不同的权限要求：</p><ul><li><p>user.*: 普通用户可以读写自己文件的属性</p></li><li><p>trusted.*: 需要特权权限（CAP_SYS_ADMIN）才能访问</p></li><li><p>system.*: 系统内部使用，通常需要特殊权限</p></li><li><p>security.*: 安全相关，可能需要特定安全模块的权限</p></li></ul><h3 id="10-实际应用场景"><a href="#10-实际应用场景" class="headerlink" title="10. 实际应用场景"></a>10. 实际应用场景</h3><p>fremovexattr 常用于以下场景：</p><ul><li><p>清理文件的自定义元数据</p></li><li><p>移除备份工具添加的临时标记</p></li><li><p>删除安全标签或访问控制信息</p></li><li><p>文件管理工具的属性清理功能</p></li><li><p>系统维护和清理脚本</p></li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>fremovexattr 是管理文件扩展属性的重要函数，通过文件描述符提供了安全的删除接口。使用时需要注意：</p><p>确保属性名称完整且正确（包括命名空间前缀）</p><p>处理属性不存在的情况（ENODATA 错误）</p><p>注意不同命名空间的权限要求</p><p>在只读文件系统上操作会失败（EROFS）</p><p>正确处理各种可能的错误情况</p><p>在多线程环境中使用文件描述符可以避免竞态条件</p><p>扩展属性的删除操作是文件元数据管理的重要组成部分，在现代 Linux 系统中被广泛应用于各种高级文件管理场景。</p><p>fremovexattr系统调用及示例-CSDN博客</p><p><a href="https://www.calcguide.tech/2025/09/08/fremovexattr%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%8F%8A%E7%A4%BA%E4%BE%8B/">https://www.calcguide.tech/2025/09/08/fremovexattr系统调用及示例/</a></p>]]>
    </content>
    <id>https://blog.calcguide.tech/2025/09/08/2025-09-08-fremovexattr%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%8F%8A%E7%A4%BA%E4%BE%8B/</id>
    <link href="https://blog.calcguide.tech/2025/09/08/2025-09-08-fremovexattr%E7%B3%BB%E7%BB%9F%E8%B0%83%E7%94%A8%E5%8F%8A%E7%A4%BA%E4%BE%8B/"/>
    <published>2025-09-07T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>fremovexattr - 删除文件的扩展属性（通过文件描述符）</p>
<h3 id="1-函数介绍"><a href="#1-函数介绍" class="headerlink" title="1. 函数介绍"></a>1. 函数介绍</h3><p>fremovexatt]]>
    </summary>
    <title>fremovexattr系统调用及示例</title>
    <updated>2026-06-15T07:56:28.165Z</updated>
  </entry>
</feed>
