<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leo Liu</title>
    <description>The latest articles on DEV Community by Leo Liu (@sienovoleo).</description>
    <link>https://dev.to/sienovoleo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3909612%2F830db132-9003-4ab2-9291-22d84be18f91.png</url>
      <title>DEV Community: Leo Liu</title>
      <link>https://dev.to/sienovoleo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sienovoleo"/>
    <language>en</language>
    <item>
      <title>Linux Process Switching and Return Values of Kernel Threads</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Fri, 29 May 2026 07:16:53 +0000</pubDate>
      <link>https://dev.to/sienovoleo/linux-process-switching-and-return-values-of-kernel-threads-5fmf</link>
      <guid>https://dev.to/sienovoleo/linux-process-switching-and-return-values-of-kernel-threads-5fmf</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;The process in Linux is a fundamental concept. A process has two starting points when transitioning from the run queue to execution: one is label 1 in the &lt;code&gt;switch_to&lt;/code&gt; macro: &lt;code&gt;"1:\t"&lt;/code&gt;, and the other is &lt;code&gt;ret_from_fork&lt;/code&gt;. Almost all processes that are not newly created start from label 1 mentioned above. The &lt;code&gt;switch_to&lt;/code&gt; macro is a mandatory path for all processes except the kernel itself to go through in order to run. Thus, although the Linux process system and scheduling mechanism are highly complex, the overall structure resembles an hourglass, with the &lt;code&gt;switch_to&lt;/code&gt; macro representing the narrowest point in the middle. To move from one end to the other, every process must pass through this point. For non-newly-created processes, execution always begins at label 1. Let's first examine how this works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#define switch_to(prev,next,last) do {                            \
         unsigned long esi,edi;                                   \
         asm volatile("pushfl\n\t"                                 \
                     "pushl %%ebp\n\t"                            \
                     "movl %%esp,%0\n\t"        &lt;/span&gt;&lt;span class="cm"&gt;/* save ESP */&lt;/span&gt;&lt;span class="cp"&gt;    \
                     "movl %5,%%esp\n\t"        &lt;/span&gt;&lt;span class="cm"&gt;/* restore ESP */&lt;/span&gt;&lt;span class="cp"&gt; \
                     &lt;/span&gt;&lt;span class="cm"&gt;/* Note: the kernel stack has now switched. Hence, local variables on the original stack become invalid. To preserve their values, they must be saved. For efficiency, 'prev' is stored in a register for later use */&lt;/span&gt;&lt;span class="cp"&gt; \
                     "movl $1f,%1\n\t"          &lt;/span&gt;&lt;span class="cm"&gt;/* save EIP */&lt;/span&gt;&lt;span class="cp"&gt;    \
                     &lt;/span&gt;&lt;span class="cm"&gt;/* Here, any process previously switched out will return with label 1 as its eip */&lt;/span&gt;&lt;span class="cp"&gt; \
                     "pushl %6\n\t"             &lt;/span&gt;&lt;span class="cm"&gt;/* restore EIP */&lt;/span&gt;&lt;span class="cp"&gt; \
                     &lt;/span&gt;&lt;span class="cm"&gt;/* Push the new process's eip onto the stack. Since the next instruction is a jmp, and the called function ends with a return, the return semantics allow eip to be popped from the stack into the eip register. In fact, this jmp to __switch_to acts like a manual call — a clever trick */&lt;/span&gt;&lt;span class="cp"&gt; \
                     "jmp __switch_to\n"                          \
                     "1:\t"                                       \
                     &lt;/span&gt;&lt;span class="cm"&gt;/* The instruction at label 1 is simple, yet this simplicity enables architectural elegance */&lt;/span&gt;&lt;span class="cp"&gt; \
                     "popl %%ebp\n\t"                             \
                     "popfl"                                      \
                     :"=m" (prev-&amp;gt;thread.esp),"=m" (prev-&amp;gt;thread.eip), \
                      "=a" (last),"=S" (esi),"=D" (edi)            \
                     :"m" (next-&amp;gt;thread.esp),"m" (next-&amp;gt;thread.eip), \
                      "2" (prev), "d" (next));                    \
} while (0)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linux implements this single-point switching mechanism to reduce complexity. In fact, many operating system kernels adopt a similar approach. The "single point" here does not refer solely to the &lt;code&gt;switch_to&lt;/code&gt; macro, but specifically to saving and restoring the &lt;code&gt;eip&lt;/code&gt; register, ensuring that all processes resume execution from the same location upon rescheduling. However, there is a minor imperfection: Linux does not make &lt;em&gt;all&lt;/em&gt; processes start from label 1 when transitioning from ready to running. Examining the implementation of &lt;code&gt;do_fork&lt;/code&gt; reveals that newly created processes do not follow this rule — their &lt;code&gt;eip&lt;/code&gt; is set to &lt;code&gt;ret_from_fork&lt;/code&gt;, not label 1. Why is this?&lt;/p&gt;

&lt;p&gt;When creating a new process, a starting address must be manually specified — after all, execution must begin somewhere. But where should this starting point be? (Do not confuse this with &lt;code&gt;regs.eip&lt;/code&gt;, which represents the normal execution &lt;code&gt;eip&lt;/code&gt; of a process. &lt;code&gt;regs.eip&lt;/code&gt; belongs to the process state saved during a system call, whereas the starting point here is used by the kernel for process management and is unrelated to the process or kernel thread itself.) Ideally, the new process should be made to appear as if it were resuming like any other existing process — promoting uniformity and simplifying management. In that case, why not set this starting address to label 1?&lt;/p&gt;

&lt;p&gt;But where exactly is label 1 located? Is the embedded assembly macro making the address of label 1 difficult to obtain? If so, the label could simply be moved outside the macro into a standalone location, allowing both existing and newly created processes to begin execution from that fixed address. Surely the kernel designers are not less intelligent than I am. However, such an indirection would incur extra instruction-fetching overhead in time and space — direct use of an inline assembly label is more efficient. Moreover, using &lt;code&gt;ret_from_fork&lt;/code&gt; achieves the same effect as starting from label 1. Let's examine the design of the process switch function.&lt;/p&gt;

&lt;p&gt;Existing processes enter &lt;code&gt;switch_to&lt;/code&gt; via &lt;code&gt;schedule&lt;/code&gt;, eventually reaching label 1. After &lt;code&gt;switch_to&lt;/code&gt;, only &lt;code&gt;finish_task_switch&lt;/code&gt; and a check for the rescheduling flag remain. Now consider &lt;code&gt;ret_from_fork&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ENTRY(ret_from_fork)
        pushl %eax      // Note: returning from __switch_to called by switch_to, which returns 'prev' in %eax. This push passes 'prev' as the argument to schedule_tail.
        call schedule_tail
        GET_THREAD_INFO(%ebp)
        popl %eax
        jmp syscall_exit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As seen above, &lt;code&gt;ret_from_fork&lt;/code&gt; calls &lt;code&gt;schedule_tail&lt;/code&gt; with the outgoing process (&lt;code&gt;prev&lt;/code&gt;) as the argument. &lt;code&gt;schedule_tail&lt;/code&gt; immediately calls &lt;code&gt;finish_task_switch&lt;/code&gt;, aligning the logic with what follows &lt;code&gt;switch_to&lt;/code&gt; in &lt;code&gt;schedule&lt;/code&gt;. The parameter handling is also correct. What about the logic after &lt;code&gt;finish_task_switch&lt;/code&gt;, such as checking the reschedule flag? That is handled in &lt;code&gt;syscall_exit&lt;/code&gt; called by &lt;code&gt;ret_from_fork&lt;/code&gt;, which checks whether rescheduling is needed and enters the normal &lt;code&gt;schedule&lt;/code&gt; flow if so — perfectly correct.&lt;/p&gt;

&lt;p&gt;In fact, the need for &lt;code&gt;finish_task_switch&lt;/code&gt; cleanup complicates things slightly, but its design is quite clever. It checks whether the previous process still needs to exist. If it's already dead, &lt;code&gt;finish_task_switch&lt;/code&gt; releases its &lt;code&gt;task_struct&lt;/code&gt;. The value of &lt;code&gt;prev&lt;/code&gt; must be preserved because &lt;code&gt;prev&lt;/code&gt; is a local variable in &lt;code&gt;schedule&lt;/code&gt;, stored on the previous process's kernel stack. After switching to the new kernel stack (note that &lt;code&gt;schedule&lt;/code&gt; uses two kernel stacks), &lt;code&gt;prev&lt;/code&gt; becomes inaccessible. Hence, it must be saved.&lt;/p&gt;

&lt;p&gt;Even if a process being exited has no remaining references, its &lt;code&gt;task_struct&lt;/code&gt; cannot be freed immediately in &lt;code&gt;do_exit&lt;/code&gt;. Linux lacks a dedicated scheduler manager that could detect this and automatically switch to another process. Ultimately, the exiting process must call &lt;code&gt;schedule&lt;/code&gt; itself. When it does, it becomes &lt;code&gt;current&lt;/code&gt;, which then becomes &lt;code&gt;prev&lt;/code&gt;. The entire switching process depends on the exiting process's &lt;code&gt;task_struct&lt;/code&gt;. Only after switching to the new process can the now-unused &lt;code&gt;task_struct&lt;/code&gt; of the exiting process be safely freed.&lt;/p&gt;

&lt;p&gt;This design of process exit is elegant. Although the absence of a dedicated scheduling management thread may seem inelegant at first glance, Linux is not a microkernel. The monolithic kernel's advantage lies in efficiency. Letting the process that needs to switch call the switch code directly, and having other ready processes signal the currently running process to initiate scheduling, is clearly the most efficient approach. Introducing a scheduling management thread would require sending notifications for every scheduling event, making many switches inefficient — albeit more aesthetically pleasing. In this respect, Linux's scheduling is a harmonious, self-organized, preemptive collaboration, whereas kernels with a scheduler manager enforce rigid control.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;asmlinkage&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;schedule_tail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;finish_task_switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_child_tid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;put_user&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;current&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;set_child_tid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, Linux process switching is still within the kernel's process management code and has not yet begun user-process-related actions. That is, the registers saved in &lt;code&gt;regs&lt;/code&gt; have not yet taken effect. Only when the kernel determines that all internal tasks are complete and nothing is left will it begin the actual work of the process — the logic of &lt;code&gt;RESTORE_ALL&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Newly created processes use loosely structured code to align with the compact logic of &lt;code&gt;schedule&lt;/code&gt;. Once such a process starts, it enters the large Linux process-switching hourglass and follows the standard single-point switching flow.&lt;/p&gt;

&lt;p&gt;Finally, let's examine the return value of kernel threads — specifically, the return value of &lt;code&gt;kernel_thread&lt;/code&gt;. One could argue that kernel threads should not have been designed this way at all. The implementation of &lt;code&gt;kernel_thread&lt;/code&gt; shows that the kernel essentially reuses the mechanism for creating user processes to create kernel threads. In user space, process creation uses copy-on-write semantics, but kernel threads do not. Moreover, Unix process creation involves duplicating the parent's address space without any special strategy for the child. Special behaviors must be set later via &lt;code&gt;exec&lt;/code&gt; or other means. How a child process runs is determined in the parent's source code by checking the return value of the &lt;code&gt;fork&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;The return value of the user-space &lt;code&gt;fork&lt;/code&gt; function is crucial because parent and child share an address space (with copy-on-write), and the return value distinguishes between them. Although kernel threads are also implemented via &lt;code&gt;do_fork&lt;/code&gt;, the child's execution function — its behavioral strategy — is specified from the start. Thus, the return value of &lt;code&gt;do_fork&lt;/code&gt; becomes less important. In fact, when creating a kernel thread in the kernel, it never returns 0, nor is there a concept of "returning 0 means child process." Even in user space, the 0 returned by &lt;code&gt;fork&lt;/code&gt; is not from &lt;code&gt;do_fork&lt;/code&gt; — &lt;code&gt;do_fork&lt;/code&gt; only returns the new process's PID. The 0 is instead popped into &lt;code&gt;eax&lt;/code&gt; during &lt;code&gt;RESTORE_ALL&lt;/code&gt;, just before returning to user space from &lt;code&gt;ret_from_fork&lt;/code&gt;. The library implementation of &lt;code&gt;fork&lt;/code&gt; then uses &lt;code&gt;eax&lt;/code&gt; as the return value. In reality, the child process never passes through &lt;code&gt;do_fork&lt;/code&gt; when entering user space. Its &lt;code&gt;thread.eip&lt;/code&gt; is set to &lt;code&gt;ret_from_fork&lt;/code&gt;, so as soon as the child begins running, &lt;code&gt;switch_to&lt;/code&gt; executes &lt;code&gt;ret_from_fork&lt;/code&gt;, which proceeds directly to &lt;code&gt;RESTORE_ALL&lt;/code&gt; and then returns to user space.&lt;/p&gt;

&lt;p&gt;For kernel threads, there is no concept of a "child process return." The newly created kernel thread simply runs and exits when done. This is because its execution strategy is already defined at creation time, eliminating the need to return to a common point and use return values to distinguish parent from child. However, kernel threads are indeed created using the same mechanism as user processes — the child is still duplicated from the parent in &lt;code&gt;copy_process&lt;/code&gt;, with no difference in that aspect. So how can it avoid returning to the origin?&lt;/p&gt;

&lt;p&gt;Linux uses a trick: it fabricates a parent process context when creating a kernel thread:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;kernel_thread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;pt_regs&lt;/span&gt; &lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                &lt;span class="c1"&gt;// Fabricated parent context, filled according to kernel mechanisms below&lt;/span&gt;
        &lt;span class="n"&gt;memset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ebx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="c1"&gt;// Execution behavior for the child (i.e., the kernel thread)&lt;/span&gt;
        &lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;edx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// Arguments&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;eip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;kernel_thread_helper&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     &lt;span class="c1"&gt;// This function manages the child's execution and exit&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;do_fork&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CLONE_VM&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;CLONE_UNTRACED&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;regs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Actually create the child process&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;__asm__(".section .text\n"
        ".align 4\n"
        "kernel_thread_helper:\n\t"   // This label function manages the kernel child process
        "movl %edx,%eax\n\t"          // Overwrites the eax set to 0 in copy_thread — shows eax is not kept 0 like in user process creation
        "pushl %edx\n\t"              // edx holds the kernel thread function's argument
        "call *%ebx\n\t"              // ebx holds the kernel thread function pointer
        "pushl %eax\n\t"              // Push the return value of the kernel thread function
        "call do_exit\n"              // Call do_exit with the function's return value as argument
        ".previous");
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There is a reason why, when creating a kernel thread, the fabricated &lt;code&gt;regs.eip&lt;/code&gt; is set to &lt;code&gt;kernel_thread_helper&lt;/code&gt; instead of directly to the target function. Overall, &lt;code&gt;kernel_thread_helper&lt;/code&gt; provides the kernel child process with a complete execution environment and lifecycle, including proper exit handling. If the target function were called directly, it would have to handle its own exit. Process creation and termination are part of the execution mechanism, which should not be the responsibility of the creator — the creator should only define the policy. The mechanism must be provided by the kernel framework.&lt;/p&gt;

&lt;p&gt;Additionally, note the &lt;code&gt;CLONE_VM&lt;/code&gt; flag in &lt;code&gt;do_fork&lt;/code&gt;. Do kernel threads have an address space? Actually, they do not. This flag is set purely for efficiency. Examining the code shows that Linux avoids switching the &lt;code&gt;cr3&lt;/code&gt; register when switching &lt;code&gt;task_struct&lt;/code&gt; for tasks sharing VM (on x86). Since kernel threads lack an &lt;code&gt;mm_struct&lt;/code&gt;, they use an &lt;code&gt;active_mm&lt;/code&gt; field to borrow the &lt;code&gt;mm&lt;/code&gt; of the previous process. All kernel-space memory mappings are identical across processes, and kernel threads only use kernel-space mappings. Thus, &lt;code&gt;cr3&lt;/code&gt; switching is avoided. The processor then enters lazy mode: only when the borrowed process's TLB is flushed is &lt;code&gt;cr3&lt;/code&gt; switched to the physical address of &lt;code&gt;swapper_pg_dir&lt;/code&gt;. In fact, &lt;code&gt;swapper_pg_dir&lt;/code&gt; is the page directory that kernel threads should naturally use. In this sense, all kernel threads can be viewed as belonging to a single kernel process — the one using &lt;code&gt;swapper_pg_dir&lt;/code&gt; as its page directory. Indeed, a process is essentially a thread of execution with its own page directory. For efficiency, kernel threads borrow the &lt;code&gt;mm_struct&lt;/code&gt; of user-space processes. Apart from &lt;code&gt;swapper_pg_dir&lt;/code&gt;, which is the standard page directory for kernel threads, no new PGD should be allocated. Hence, the &lt;code&gt;CLONE_VM&lt;/code&gt; flag ensures no &lt;code&gt;mm_struct&lt;/code&gt; (and thus no PGD) is allocated, avoiding duplication. The issue of sharing the parent's &lt;code&gt;mm&lt;/code&gt; can be resolved by releasing the old &lt;code&gt;mm&lt;/code&gt; and switching to &lt;code&gt;init_mm&lt;/code&gt;. Furthermore, as discussed next, because kernel memory mappings are identical, borrowing any process's &lt;code&gt;mm&lt;/code&gt; makes kernel operations more efficient.&lt;/p&gt;

&lt;p&gt;The TLB lazy mode is described in my article "Lazy Mode of TLB Flush." Briefly, on a single CPU, TLB flush is an active process and thus straightforward — active processes usually have deterministic behavior. However, on SMP systems, it becomes more complex. Consider the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="n"&gt;task_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nf"&gt;context_switch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;runqueue_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rq&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;task_t&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;mm_struct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;mm_struct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;oldmm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;active_mm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unlikely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;             &lt;span class="c1"&gt;// Kernel thread&lt;/span&gt;
                &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;active_mm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldmm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;atomic_inc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;oldmm&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mm_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;enter_lazy_tlb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldmm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;  &lt;span class="c1"&gt;// Does nothing on uniprocessor&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt;
                &lt;span class="n"&gt;switch_mm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;oldmm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;next&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// Perform switch&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unlikely&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;prev&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;active_mm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;WARN_ON&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rq&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prev_mm&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;rq&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;prev_mm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;oldmm&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kr"&gt;inline&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;enter_lazy_tlb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;mm_struct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;mm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;task_struct&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;tsk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="cp"&gt;#ifdef CONFIG_SMP
&lt;/span&gt;        &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;smp_processor_id&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;per_cpu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpu_tlbstate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;TLBSTATE_OK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;per_cpu&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cpu_tlbstate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;cpu&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;TLBSTATE_LAZY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="c1"&gt;// Set this CPU's cpu_tlbstate to lazy mode&lt;/span&gt;
&lt;span class="cp"&gt;#endif
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  On SMP systems, flushing the TLB requires sending inter-processor interrupts (IPIs) to all processors. When a CPU in lazy mode receives a TLB-flush IPI, it removes itself from the &lt;code&gt;cpu_vm_mask&lt;/code&gt; of &lt;code&gt;active_mm&lt;/code&gt; in &lt;code&gt;cpu_tlbstate&lt;/code&gt;, indicating that it should no longer receive TLB-flush IPIs. This is because CPUs in lazy mode are currently running kernel threads, and all processes share identical kernel-space mappings — so using any &lt;code&gt;mm&lt;/code&gt; is acceptable. However, this is not entirely safe. For example, if a kernel thread is using a borrowed &lt;code&gt;mm&lt;/code&gt; and the original process (and its &lt;code&gt;mm&lt;/code&gt;) is freed on another CPU, even though &lt;code&gt;atomic_inc(&amp;amp;oldmm-&amp;gt;mm_count)&lt;/code&gt; delays the release, it's still suboptimal. Why use someone else's &lt;code&gt;mm&lt;/code&gt; when &lt;code&gt;swapper_pg_dir&lt;/code&gt; — which is always safe and never freed — is available? Using borrowed &lt;code&gt;mm&lt;/code&gt; only consumes memory. Therefore, when a CPU in lazy mode receives its first TLB-flush IPI, it should load its page directory with a safe value (i.e., &lt;code&gt;swapper_pg_dir&lt;/code&gt;) before declaring it will no longer accept TLB-flush IPIs. Remember: once a non-kernel thread begins execution, the CPU must resume accepting TLB-flush IPIs — that is, exit lazy mode.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6763073" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6763073" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>struct</category>
      <category>thread</category>
      <category>embedded</category>
    </item>
    <item>
      <title>How to Install MySQL 5.0 on Linux</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Thu, 28 May 2026 07:17:02 +0000</pubDate>
      <link>https://dev.to/sienovoleo/how-to-install-mysql-50-on-linux-4bmn</link>
      <guid>https://dev.to/sienovoleo/how-to-install-mysql-50-on-linux-4bmn</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;For the clearest guide, refer to Baidu Wenku: &lt;a href="http://wenku.baidu.com/view/571968976bec0975f465e25b.html" rel="noopener noreferrer"&gt;http://wenku.baidu.com/view/571968976bec0975f465e25b.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;=============================================&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(I) How to Install MySQL Database on Linux&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;=============================================&lt;/p&gt;

&lt;p&gt;My first setback was with RPM installation. It reported a MySQL version conflict, preventing the installation from proceeding. After querying with &lt;code&gt;rpm -q&lt;/code&gt;, I attempted to remove the system's pre-installed version (3.x.x) using &lt;code&gt;rpm -e&lt;/code&gt;. However, RPM mercilessly returned a slew of other errors. Due to dependencies with other software, version 3.x.x could not be removed. My initial positive impression of RPM vanished in an instant.&lt;/p&gt;

&lt;p&gt;As the saying goes, "Among three people, there must be one who can be my teacher." I immediately found Alin on MSN. When I asked him how to uninstall or upgrade MySQL using RPM, he gleefully told me that he upgraded it in just one minute using "Debian." He then added that he "doesn't know how" to use RPM, all while smirking. I knew he was getting back at me; last time he kept recommending "Debian" and I ignored him, so he found his chance. Actually, I do think "Debian" is good, it's just that the name sounds a bit unpleasant...&lt;/p&gt;

&lt;p&gt;Since RPM wasn't working, I had to settle for a different approach. This time, I chose the binary installation package. I found an installation guide from a pioneer via Google as a reference. I quickly followed in their footsteps, only to be bounced back, bruised and battered. The previous experience didn't suit me; it seems there truly is no silver bullet in this world.&lt;/p&gt;

&lt;p&gt;It became clear that impatience wouldn't solve the problem. I decided to calm down and found several more articles introducing MySQL installation. After multiple attempts, I finally found a small path through the thorny thicket...&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the binary MySQL installation package from &lt;a href="http://www.mysql.com/" rel="noopener noreferrer"&gt;http://www.mysql.com&lt;/a&gt; // This MySQL is a binary version, no compilation needed&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# chmod 755 mysql-standard-5.0.15-linux-gnu-i686-glibc23.tar.gz&lt;/code&gt;
&lt;code&gt;//&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;# tar xfz mysql-standard-5.0.15-linux-gnu-i686-glibc23.tar.gz // Copy the extracted directory to /usr/local/ and rename it to mysql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# groupadd mysql&lt;/code&gt;
&lt;code&gt;# useradd mysql -g mysql // Create the mysql group&lt;/code&gt;
&lt;code&gt;// Create the mysql user and add them to the mysql group&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# cp /usr/local/mysql/support-files/my-medium.cnf /etc/my.cnf&lt;/code&gt;
&lt;code&gt;// In the support-files directory, there are 4 template files. We choose one of them as the MySQL configuration file, overwriting /etc/my.cnf (the system's default configuration, which sets performance parameters and some MySQL path parameters).&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# cd /usr/local/mysql&lt;/code&gt;
&lt;code&gt;# ./scripts/mysql_install_db --user=mysql&lt;/code&gt;
&lt;code&gt;// Enter the mysql directory&lt;/code&gt;
&lt;code&gt;// Initialize tables and specify that the mysql user will access them. After initializing tables, set access permissions for the mysql and root users.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;# chown -R root . // Set root to have access to /usr/local/mysql&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# chown -R mysql data&lt;/code&gt;
&lt;code&gt;// Set the mysql user to have access to /usr/local/mysql/data, which contains MySQL database files. This directory is configured in /etc/my.cnf and created during mysql_install_db.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# chown -R mysql data/.&lt;/code&gt;
&lt;code&gt;// Set the mysql user to have access to all files under /usr/local/mysql/data/mysql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# chgrp -R mysql .&lt;/code&gt;
&lt;code&gt;// Set the mysql group to have access to /usr/local/mysql&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# /usr/local/mysql/bin/mysqld_safe --user=mysql &amp;amp;&lt;/code&gt;
&lt;code&gt;// Run MySQL&lt;/code&gt;
&lt;code&gt;// If there are no issues, you should see a prompt similar to this:&lt;/code&gt;
&lt;code&gt;[1] 42264&lt;/code&gt;
&lt;code&gt;# Starting mysqld daemon with databases from /usr/local/mysql/var&lt;/code&gt;
&lt;code&gt;// If a statement like "mysql ended" appears, it means MySQL did not start correctly. You can check the log for issues; the log file is usually configured in /etc/my.cnf. Most problems are caused by incorrect permission settings.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;// Use the following command to change the MySQL password&lt;/code&gt;
&lt;code&gt;# /usr/local/mysql/bin/mysqladmin -u root password yourpassword // The default installation has no password; for security, you must change it immediately.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# cp support-files/mysql.server /etc/rc.d/init.d/mysqld&lt;/code&gt;
&lt;code&gt;# chmod 700 /etc/init.d/mysqld&lt;/code&gt;
&lt;code&gt;# chkconfig --add mysqld&lt;/code&gt;
&lt;code&gt;# chkconfig --level 345 mysqld on // Copy a script from the compilation directory&lt;/code&gt;
&lt;code&gt;// Configure MySQL to start automatically on every boot.&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;# service mysqld start&lt;/code&gt;
&lt;code&gt;# netstat -atln&lt;/code&gt;
&lt;code&gt;// Start the mysqld service&lt;/code&gt;
&lt;code&gt;// Check if port 3306 is open. Remember to open this port in the firewall.&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;============================================&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(II) How to Install MySQL Database on Linux&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;============================================&lt;/p&gt;

&lt;p&gt;Using Options on the Command Line&lt;/p&gt;

&lt;p&gt;Program options specified on the command line follow these rules:&lt;br&gt;
· Options immediately follow the command name.&lt;br&gt;
· Option parameters begin with one or two hyphens, depending on whether they have a short or long name. Many options have both forms. For example, -? and --help are the short and long names for the option that tells a MySQL program to display help messages.&lt;br&gt;
· Option names are case-sensitive. -v and -V are both valid but have different meanings. (They are the short names for the --verbose and --version options).&lt;br&gt;
· Some options are followed by an option value. For example, -h localhost or --host=localhost indicates the MySQL server host for the client program. The option value tells the program the hostname where the MySQL server is running.&lt;br&gt;
· For long options with values, separate the option name and value with an '='. For short options with values, the option value can immediately follow the option letter, or there can be a space between them. (-hlocalhost and -h localhost are equivalent). An exception to this rule is the option for specifying the MySQL password. This option can be in the form --password=pass_val or --password. In the latter case (no password value given), the program will prompt for the password. The password option can also be given in the short form -ppass_val or -p. However, for the short form, if a password value is given, it must immediately follow the option without any intervening space. The reason for this requirement is that if there is a space after the option, the program has no way of knowing whether the subsequent argument is the password value or some other argument. Therefore, the following two commands have completely different meanings:&lt;br&gt;
[pre]· shell&amp;gt; mysql -ptest[/pre][pre]· shell&amp;gt; mysql -p test[/pre]The first command tells mysql to use the password 'test' but does not specify a default database. The second command tells mysql to prompt for the password and use 'test' as the default database.&lt;/p&gt;

&lt;p&gt;I. Introduction&lt;/p&gt;

&lt;p&gt;I have wanted to use Linux for a long time, but without a specific task, I never systematically learned it. Recently, due to work requirements, I had to use MySQL on Linux. I initially thought that with my experience using SQL Server on Windows, installing MySQL on Linux would be a breeze. However, I encountered many detours and problems during the actual installation and use of MySQL, as Linux and Windows are fundamentally very different. To help beginners like me avoid detours and get started quickly, I wrote this article, hoping it will be helpful to you.&lt;/p&gt;

&lt;p&gt;II. Installing MySQL&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Download MySQL Installation Files&lt;br&gt;
To install MySQL, you need the following two files:&lt;br&gt;
MySQL-server-5.0.9-0.i386.rpm&lt;br&gt;
MySQL-client-5.0.9-0.i386.rpm&lt;br&gt;
Download them from: &lt;a href="http://dev.mysql.com/downloads/mysql/5.0.html" rel="noopener noreferrer"&gt;http://dev.mysql.com/downloads/mysql/5.0.html&lt;/a&gt;. Open this page, scroll down to "Linux x86 RPM downloads," find "Server" and "Client programs," and download the two required RPM files.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Install MySQL&lt;br&gt;
RPM files are software packages developed by Red Hat. RPM allows Linux to install software packages without many complex procedures. Commonly used parameters for the &lt;code&gt;rpm&lt;/code&gt; command during installation are –ivh, where &lt;code&gt;i&lt;/code&gt; indicates installing the specified RPM package, &lt;code&gt;v&lt;/code&gt; indicates verbose information during installation, and &lt;code&gt;h&lt;/code&gt; indicates displaying '#' symbols during installation to show the current installation progress. This symbol will continue until the installation is complete.&lt;br&gt;
1) Install Server&lt;br&gt;
Run the following command in the directory containing the two RPM files:&lt;br&gt;
&lt;code&gt;[root@test1 local]# rpm -ivh MySQL-server-5.0.9-0.i386.rpm&lt;/code&gt;&lt;br&gt;
The following information will be displayed:&lt;br&gt;
&lt;code&gt;warning: MySQL-server-5.0.9-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Preparing... ########################################### [100%]&lt;/code&gt;&lt;br&gt;
&lt;code&gt;1:MySQL-server ########################################### [100%]&lt;/code&gt;&lt;br&gt;
&lt;code&gt;...... (display omitted)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;/usr/bin/mysqladmin -uroot password 'new-password'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;/usr/bin/mysqladmin -uroot -h test1 password 'new-password'&lt;/code&gt;&lt;br&gt;
&lt;code&gt;...... (display omitted)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Starting mysqld daemon with databases from /var/lib/mysql&lt;/code&gt;&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fwww.badguy.name%2Fattachments%2Fmonth_0704%2Fy2007418214924.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fwww.badguy.name%2Fattachments%2Fmonth_0704%2Fy2007418214924.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;br&gt;
If the above information appears, the server installation is complete. To test if it was successful, you can run &lt;code&gt;netstat&lt;/code&gt; to see if the MySQL port is open. If it is open, the service has started, and the installation is successful. The default MySQL port is 3306.&lt;br&gt;
&lt;code&gt;[root@test1 local]# netstat -nat&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Active Internet connections (servers and established)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Proto Recv-Q Send-Q Local Address Foreign Address State&lt;/code&gt;&lt;br&gt;
&lt;code&gt;tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN&lt;/code&gt;&lt;br&gt;
The above display shows that the MySQL service has started.&lt;br&gt;
2) Install Client&lt;br&gt;
Run the following command:&lt;br&gt;
&lt;code&gt;[root@test1 local]# rpm -ivh MySQL-client-5.0.9-0.i386.rpm&lt;/code&gt;&lt;br&gt;
&lt;code&gt;warning: MySQL-client-5.0.9-0.i386.rpm: V3 DSA signature: NOKEY, key ID 5072e1f5&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Preparing... ########################################### [100%]&lt;/code&gt;&lt;br&gt;
&lt;code&gt;1:MySQL-client ########################################### [100%]&lt;/code&gt;&lt;br&gt;
The display indicates that the installation is complete.&lt;br&gt;
Use the following command to connect to MySQL and test for success.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;III. Logging into MySQL&lt;/p&gt;

&lt;p&gt;The command to log into MySQL is &lt;code&gt;mysql&lt;/code&gt;. The syntax for &lt;code&gt;mysql&lt;/code&gt; is as follows:&lt;br&gt;
&lt;code&gt;mysql [-u username] [-h host] [-p[password]] [dbname]&lt;/code&gt;&lt;br&gt;
&lt;code&gt;username&lt;/code&gt; and &lt;code&gt;password&lt;/code&gt; are the MySQL username and password, respectively. The initial MySQL administrative account is &lt;code&gt;root&lt;/code&gt; with no password. Note: This &lt;code&gt;root&lt;/code&gt; user is not the Linux system user. The default MySQL user is &lt;code&gt;root&lt;/code&gt;. Since there is no initial password, you only need to type &lt;code&gt;mysql&lt;/code&gt; for the first login.&lt;br&gt;
&lt;code&gt;[root@test1 local]# mysql&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Welcome to the MySQL monitor. Commands end with ; or \g.&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Your MySQL connection id is 1 to server version: 4.0.16-standard&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Type 'help;' or '\h' for help. Type '\c' to clear the buffer.&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mysql&amp;gt;&lt;/code&gt;&lt;br&gt;
If the "mysql&amp;gt;" prompt appears, congratulations, the installation was successful!&lt;br&gt;
The login format after adding a password is as follows:&lt;br&gt;
&lt;code&gt;mysql -u root -p&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Enter password: (enter password)&lt;/code&gt;&lt;br&gt;
Here, &lt;code&gt;-u&lt;/code&gt; is followed by the username, and &lt;code&gt;-p&lt;/code&gt; prompts for the password. Press Enter and then enter the password at the prompt.&lt;/p&gt;

&lt;p&gt;Note: This &lt;code&gt;mysql&lt;/code&gt; file is in the &lt;code&gt;/usr/bin&lt;/code&gt; directory and is not the same file as the startup file &lt;code&gt;/etc/init.d/mysql&lt;/code&gt; which will be discussed later.&lt;/p&gt;

&lt;p&gt;IV. Several Important MySQL Directories&lt;/p&gt;

&lt;p&gt;After MySQL is installed, unlike SQL Server, it is not installed in a single directory. Its database files, configuration files, and command files are in different directories. Understanding these directories is very important, especially for Linux beginners, because the Linux directory structure itself is quite complex. If you don't understand the MySQL installation directories, you cannot talk about in-depth learning.&lt;/p&gt;

&lt;p&gt;Below are descriptions of these directories.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Database Directory&lt;br&gt;
&lt;code&gt;/var/lib/mysql/&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Configuration Files&lt;br&gt;
&lt;code&gt;/usr/share/mysql&lt;/code&gt; (mysql.server command and configuration files)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Related Commands&lt;br&gt;
&lt;code&gt;/usr/bin&lt;/code&gt; (mysqladmin, mysqldump, and other commands)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Startup Scripts&lt;br&gt;
&lt;code&gt;/etc/rc.d/init.d/&lt;/code&gt; (directory for the MySQL startup script file)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;V. Changing the Login Password&lt;/p&gt;

&lt;p&gt;MySQL has no default password. The importance of adding a password after installation is self-evident.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Command&lt;br&gt;
&lt;code&gt;usr/bin/mysqladmin -u root password 'new-password'&lt;/code&gt;&lt;br&gt;
Format: &lt;code&gt;mysqladmin -u username -p old_password password new_password&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Example&lt;br&gt;
Example 1: Add a password '123456' for root.&lt;br&gt;
Type the following command:&lt;br&gt;
&lt;code&gt;[root@test1 local]# /usr/bin/mysqladmin -u root password 123456&lt;/code&gt;&lt;br&gt;
Note: Since root initially has no password, the &lt;code&gt;-p old_password&lt;/code&gt; part can be omitted.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Test if the modification was successful&lt;br&gt;
1) Log in without a password&lt;br&gt;
&lt;code&gt;[root@test1 local]# mysql&lt;/code&gt;&lt;br&gt;
&lt;code&gt;ERROR 1045: Access denied for user: 'root@localhost' (Using password: NO)&lt;/code&gt;&lt;br&gt;
An error is displayed, indicating that the password has been changed.&lt;br&gt;
2) Log in with the modified password&lt;br&gt;
&lt;code&gt;[root@test1 local]# mysql -u root -p&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Enter password: (enter the modified password 123456)&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Welcome to the MySQL monitor. Commands end with ; or \g.&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Your MySQL connection id is 4 to server version: 4.0.16-standard&lt;/code&gt;&lt;br&gt;
&lt;code&gt;Type 'help;' or '\h' for help. Type '\c' to clear the buffer.&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mysql&amp;gt;&lt;/code&gt;&lt;br&gt;
Success!&lt;br&gt;
This changes the password using the &lt;code&gt;mysqladmin&lt;/code&gt; command. You can also change the password by modifying the database.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fwww.badguy.name%2Fattachments%2Fmonth_0704%2Ff200741821503.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/http%3A%2F%2Fwww.badguy.name%2Fattachments%2Fmonth_0704%2Ff200741821503.gif" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;VI. Starting and Stopping&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Start&lt;br&gt;
After MySQL is installed, the startup file &lt;code&gt;mysql&lt;/code&gt; is in the &lt;code&gt;/etc/init.d&lt;/code&gt; directory. To start it, run the following command:&lt;br&gt;
&lt;code&gt;[root@test1 init.d]# /etc/init.d/mysql start&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stop&lt;br&gt;
&lt;code&gt;/usr/bin/mysqladmin -u root -p shutdown&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automatic Startup&lt;br&gt;
1) Check if MySQL is in the automatic startup list&lt;br&gt;
&lt;code&gt;[root@test1 local]# /sbin/chkconfig --list&lt;/code&gt;&lt;br&gt;
2) Add MySQL to your system's startup service group&lt;br&gt;
&lt;code&gt;[root@test1 local]# /sbin/chkconfig – add mysql&lt;/code&gt;&lt;br&gt;
3) Remove MySQL from the startup service group.&lt;br&gt;
&lt;code&gt;[root@test1 local]# /sbin/chkconfig – del mysql&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The command to restart the MySQL service is &lt;code&gt;service mysql restart&lt;/code&gt; or &lt;code&gt;/etc/init.d/mysql restart&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;

&lt;/ol&gt;

&lt;p&gt;VII. Changing MySQL Directory&lt;/p&gt;

&lt;p&gt;The default data file storage directory for MySQL is &lt;code&gt;/var/lib/mysql&lt;/code&gt;. If you want to move the directory to &lt;code&gt;/home/data&lt;/code&gt;, you need to perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Create the &lt;code&gt;data&lt;/code&gt; directory in &lt;code&gt;/home&lt;/code&gt;&lt;br&gt;
&lt;code&gt;cd /home&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mkdir data&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Stop the MySQL service process:&lt;br&gt;
&lt;code&gt;mysqladmin -u root -p shutdown&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Move the entire &lt;code&gt;/var/lib/mysql&lt;/code&gt; directory to &lt;code&gt;/home/data&lt;/code&gt;&lt;br&gt;
&lt;code&gt;mv /var/lib/mysql /home/data/&lt;/code&gt;&lt;br&gt;
This moves the MySQL data files to &lt;code&gt;/home/data/mysql&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Find the &lt;code&gt;my.cnf&lt;/code&gt; configuration file&lt;br&gt;
If there is no &lt;code&gt;my.cnf&lt;/code&gt; configuration file in the &lt;code&gt;/etc/&lt;/code&gt; directory, find a &lt;code&gt;*.cnf&lt;/code&gt; file in &lt;code&gt;/usr/share/mysql/&lt;/code&gt;, copy one to &lt;code&gt;/etc/&lt;/code&gt;, and rename it to &lt;code&gt;my.cnf&lt;/code&gt;. The command is as follows:&lt;br&gt;
&lt;code&gt;[root@test1 mysql]# cp /usr/share/mysql/my-medium.cnf /etc/my.cnf&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Edit MySQL's configuration file &lt;code&gt;/etc/my.cnf&lt;/code&gt;&lt;br&gt;
To ensure MySQL works correctly, you need to specify the location where the &lt;code&gt;mysql.sock&lt;/code&gt; file is generated. Modify the &lt;code&gt;socket=/var/lib/mysql/mysql.sock&lt;/code&gt; line by changing the value to the right of the equals sign to: &lt;code&gt;/home/mysql/mysql.sock&lt;/code&gt;. Perform the following operation:&lt;br&gt;
&lt;code&gt;vi my.cnf&lt;/code&gt; (Use the &lt;code&gt;vi&lt;/code&gt; tool to edit the &lt;code&gt;my.cnf&lt;/code&gt; file, find the following data, and modify it)&lt;br&gt;
&lt;code&gt;# The MySQL server&lt;/code&gt;&lt;br&gt;
&lt;code&gt;[mysqld]&lt;/code&gt;&lt;br&gt;
&lt;code&gt;port = 3306&lt;/code&gt;&lt;br&gt;
&lt;code&gt;#socket = /var/lib/mysql/mysql.sock&lt;/code&gt; (Original content, commented out with "#" for safety)&lt;br&gt;
&lt;code&gt;socket = /home/data/mysql/mysql.sock&lt;/code&gt; (Add this line)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modify the MySQL startup script &lt;code&gt;/etc/rc.d/init.d/mysql&lt;/code&gt;&lt;br&gt;
Finally, you need to modify the MySQL startup script &lt;code&gt;/etc/rc.d/init.d/mysql&lt;/code&gt;, changing the &lt;code&gt;datadir=/var/lib/mysql&lt;/code&gt; line by replacing the path to the right of the equals sign with your current actual storage path: &lt;code&gt;home/data/mysql&lt;/code&gt;.&lt;br&gt;
&lt;code&gt;[root@test1 etc]# vi /etc/rc.d/init.d/mysql&lt;/code&gt;&lt;br&gt;
&lt;code&gt;#datadir=/var/lib/mysql&lt;/code&gt; (Comment out this line)&lt;br&gt;
&lt;code&gt;datadir=/home/data/mysql&lt;/code&gt; (Add this line)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Restart the MySQL service&lt;br&gt;
&lt;code&gt;/etc/rc.d/init.d/mysql start&lt;/code&gt;&lt;br&gt;
Or restart Linux with the &lt;code&gt;reboot&lt;/code&gt; command.&lt;br&gt;
If it works correctly, the move was successful. Otherwise, recheck the previous 7 steps.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;VIII. Common MySQL Operations&lt;/p&gt;

&lt;p&gt;Note: Every command in MySQL must end with a semicolon (;).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Show Databases&lt;br&gt;
&lt;code&gt;mysql&amp;gt; show databases;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;+----------+&lt;/code&gt;&lt;br&gt;
&lt;code&gt;| Database |&lt;/code&gt;&lt;br&gt;
&lt;code&gt;+----------+&lt;/code&gt;&lt;br&gt;
&lt;code&gt;| mysql |&lt;/code&gt;&lt;br&gt;
&lt;code&gt;| test |&lt;/code&gt;&lt;br&gt;
&lt;code&gt;+----------+&lt;/code&gt;&lt;br&gt;
&lt;code&gt;2 rows in set (0.04 sec)&lt;/code&gt;&lt;br&gt;
After MySQL is installed, there are two databases: &lt;code&gt;mysql&lt;/code&gt; and &lt;code&gt;test&lt;/code&gt;. The &lt;code&gt;mysql&lt;/code&gt; database is very important; it contains MySQL's system information. When we change passwords and add new users, we are actually operating on the relevant tables in this database.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Show Tables in a Database&lt;br&gt;
&lt;code&gt;mysql&amp;gt; use mysql;&lt;/code&gt; (Open the database; to operate on a database, you must open it, similar to FoxPro)&lt;br&gt;
&lt;code&gt;Database changed&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;code&gt;mysql&amp;gt; show tables;&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;+-----------------+&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| Tables_in_mysql |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;+-----------------+&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| columns_priv |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| db |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| func |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| host |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| tables_priv |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;| user |&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;+-----------------+&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;6 rows in set (0.01 sec)&lt;/code&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Show Table Structure:&lt;br&gt;
&lt;code&gt;describe table_name;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Show Records in a Table:&lt;br&gt;
&lt;code&gt;select * from table_name;&lt;/code&gt;&lt;br&gt;
For example: Show records in the &lt;code&gt;user&lt;/code&gt; table in the &lt;code&gt;mysql&lt;/code&gt; database. All users who can operate on MySQL users are in this table.&lt;br&gt;
&lt;code&gt;Select * from user;&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create Database:&lt;/p&gt;
&lt;h2&gt;
  
  
  `
&lt;/h2&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6834148" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6834148" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>mysql</category>
      <category>linux</category>
      <category>database</category>
      <category>debian</category>
    </item>
    <item>
      <title>FPGA Applications in Healthcare, Illustrated by 4K Medical Endoscopy</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Wed, 27 May 2026 07:23:06 +0000</pubDate>
      <link>https://dev.to/sienovoleo/fpga-applications-in-healthcare-illustrated-by-4k-medical-endoscopy-pmg</link>
      <guid>https://dev.to/sienovoleo/fpga-applications-in-healthcare-illustrated-by-4k-medical-endoscopy-pmg</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;With technological advancements, medical imaging—one of the major achievements of modern science—has found diverse applications in non-invasive diagnosis and treatment. One such application is endoscopy, which became more widespread in the 1990s when charge-coupled devices made it possible to transmit images to displays. To assist doctors in better identifying and locating lesions, manufacturers have continuously improved endoscope resolution, progressing from 1080P to today’s 4K for human medical endoscopes. In addition, innovative technologies such as fluorescence and 3D imaging have been integrated to further aid physicians in accurate diagnosis and surgical procedures. Recently, China's Ministry of Industry and Information Technology released the &lt;em&gt;Medical Equipment Industry Development Plan (2021–2025)&lt;/em&gt;, which outlines detailed strategic directions for key areas of medical equipment development, including the &lt;strong&gt;strategic goal of breaking through in key technologies for medical endoscopes and other diagnostic imaging devices&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdonpaoyj7vijmd34h1m.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffdonpaoyj7vijmd34h1m.jpeg" width="799" height="522"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Technical Challenges&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In clinical settings, the maximum allowable image latency for endoscopic applications ranges between 50 and 150 milliseconds. However, during surgery, endoscopes must respond in real time or near real time while simultaneously performing image correction, color noise reduction, edge enhancement, zooming, and other functions. Additionally, the end device should be as compact as possible, support 4K resolution, 3D imaging, fluorescence, and be compatible with SDI/HDMI interfaces. While 4K requires only one high-definition camera, fluorescence and 3D each require an additional HD camera, posing significant challenges to core board resources, data transmission speed, processing throughput, and algorithmic efficiency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8rdx42lo2zz5ji4zgq0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp8rdx42lo2zz5ji4zgq0.jpeg" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;An endoscopic system built around FPGA SoC technology can deliver real-time 4K video streaming. A 4K image sensor captures visual data, while image signal processing is handled by the &lt;strong&gt;Mercury+ XU8 FPGA (SoC)&lt;/strong&gt; module. The captured video stream is fed into the Mercury+ XU8 FPGA (SoC) module for preprocessing, then passed through an image management and storage unit before being displayed on a high-resolution monitor via a display interface for the surgeon’s use. The Mercury+ XU8 core module—long featured on Xilinx’s homepage—comes in three models: XCZU4CG, XCZU5EV, and XCZU7EV. Users can easily upgrade to higher-end models when more resources are needed, enabling simple and seamless system evolution.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zuc4vc3wzhmvy4kfzm6.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4zuc4vc3wzhmvy4kfzm6.jpeg" width="799" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mercury+ XU8 Core Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fue6zz0q43h80gag7m1o1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fue6zz0q43h80gag7m1o1.png" width="800" height="594"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Block Diagram&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Besides the Mercury+ XU8 FPGA (SoC), other SoCs such as Mercury+ XU5 and Mercury+ XU9 can also be considered for this application. Using the Mercury+ XU8 FPGA (SoC) module enables &lt;strong&gt;high integration of the hardware system, significantly shortening development time.&lt;/strong&gt; Additionally, support for various peripheral interfaces allows faster and more convenient future functionality updates and expansions. Thanks to Ruishu Yingke’s extensive product lineup, users can choose from multiple core module options across Xilinx Kintex-7, Zynq-7000, and Zynq Ultrascale+ MPSoC families. These core modules are pin-compatible within their series (Mars, Mercury, Andromeda), meaning users can plan clear upgrade paths, greatly reducing engineering effort during upgrades—even allowing last-minute core module changes during project development. FPGA core modules have a minimum expected lifecycle of over 10 years, with hardware designs emphasizing long-term availability and performance, ensuring all products remain deliverable for extended periods.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhhgdib4hoo6njbhtksi.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxhhgdib4hoo6njbhtksi.jpeg" width="800" height="542"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Module Series&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FPGA (Field-Programmable Gate Array), a key innovation by Xilinx, is renowned for its programmability and flexibility. Initially, FPGAs were used primarily to simulate ASICs before mask processing and mass production. However, ASICs require high customization and become cost-prohibitive at low volumes, so FPGAs and ASICs have coexisted without conflict, each serving distinct roles. Later, with the emergence of accelerators and increased computational demands, FPGAs evolved into parallel computing devices rivaling GPUs in prominence.&lt;/p&gt;

&lt;p&gt;Today, FPGAs have entered data center applications, where they offer reduced component count and superior power efficiency compared to CPUs and GPUs. Backed by Xilinx’s three strategic pillars—“Data Center First,” “Accelerating Core Markets,” and “Driving Adaptive Computing”—its ACAP platform and Alveo accelerator cards have become highly competitive in the data center market.&lt;/p&gt;

&lt;p&gt;Beyond that, Xilinx has demonstrated its “integrated SmartNIC platform” for cloud service providers, “FPGA TCON” solutions for consumer electronics, and Zynq SoC series solutions for industrial applications.&lt;/p&gt;

&lt;p&gt;In fact, according to Xilinx, the healthcare sector now represents a significant portion of its revenue and has been growing steadily at 11–15% annually. What FPGA products enable Xilinx to capture this market, and what role do FPGA devices play in medical equipment?&lt;/p&gt;

&lt;p&gt;Recently, Xilinx presented its latest achievements in medical science and medical devices to journalists; reporters from 21ic China Electronics Network attended the briefing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Where Can FPGA Devices Be Used?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Data shows that global per capita healthcare spending continues to rise. With an aging population, consumers have high expectations regarding both medical quality and cost. Meanwhile, the pandemic has heightened demand for early disease detection and rapid diagnostic analysis, necessitating lower medical device costs and higher computational power.&lt;/p&gt;

&lt;p&gt;FPGA devices offer inherent programmability, allowing developers to avoid the high non-recurring engineering (NRE) costs associated with ASICs, eliminate minimum order quantities, and reduce risks and losses from multi-chip iterations. The medical industry is one of the most closely linked to technological advancement, and as FPGA technology continuously evolves, new devices emerge, driving changes in treatment methods, pathways, and philosophies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g3b4ofpxuf9laeeecwr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g3b4ofpxuf9laeeecwr.png" width="286" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Subh Bhattacharya, Global Business Marketing Lead for Medical Sciences at Xilinx&lt;/p&gt;

&lt;p&gt;According to Subh Bhattacharya, Xilinx FPGA applications in healthcare fall into three main categories: clinical applications, medical imaging, and diagnostic analytics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhk24yue3yzab5uqnoc8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnhk24yue3yzab5uqnoc8.png" width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;01&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clinical Environments&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Clinical equipment varies widely in type and quantity, requiring highly flexible solutions—making FPGAs ideal. Notably, some devices directly impact patient safety and thus demand extremely fast boot times, high reliability, and low latency; others prioritize portability, requiring low power consumption and small form factors.&lt;/p&gt;

&lt;p&gt;As explained by Subh, Xilinx’s Zynq UltraScale+ MPSoC (hereafter referred to as “ZU+ MPSoC”) is a highly integrated platform combining multiple processors with programmable logic, as well as integrated information security and functional safety features. Subh emphasized that this platform’s powerful capabilities and performance make it well-suited for clinical applications ranging from cloud to edge.&lt;/p&gt;

&lt;p&gt;Subh presented several examples of how this platform addresses clinical needs:&lt;/p&gt;

&lt;p&gt;First, a medical AI solution developed in collaboration with Spline.AI and AWS (Amazon Web Services), using the ZU+ MPSoC ZCU104 platform as an edge device to implement a high-accuracy, low-latency deep learning model and reference design for medical X-ray classification. This solution can autonomously predict diseases from chest X-rays, including COVID-19 and pneumonia, and supports custom model development for clinical use. Additionally, the ZCU104 supports development using the open-source PYNQ framework and can be extended and deployed via AWS IoT Greengrass. This solution leverages the ZU+ MPSoC’s high performance and scalability to deliver precise diagnostics at low cost.&lt;/p&gt;

&lt;p&gt;Second, Xilinx supports Olympus in its core endoscope technology, leveraging the ZU+ MPSoC’s fast startup, low power, and low-latency characteristics.&lt;/p&gt;

&lt;p&gt;Third, Xilinx powers Clarius’s ultra-portable, high-performance ultrasound system, utilizing the ZU+ MPSoC’s dual on-chip ARM processors and FPGA in a compact package to achieve extreme portability.&lt;/p&gt;

&lt;p&gt;Historically, Zynq SoC was Xilinx’s first product integrating ARM cores, launched in 2011. At the time, it was called an “extensible processing platform,” aimed at expanding into embedded applications. Previously, FPGAs were mostly used as auxiliary chips; after integrating more functionalities into a single SoC platform, components such as ARM GPUs, data security processors, and functional safety processors were consolidated onto one chip. Subh noted that this transformation boosted Xilinx’s annual revenue growth from 5–6% to 14–15%, a 2.5x increase attributed entirely to this technological platform.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xwieoqp0t3ym8hkdwrv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xwieoqp0t3ym8hkdwrv.png" width="799" height="454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Additionally, Subh demonstrated ZU+ MPSoC’s medical security solutions. “Globally, over 100 million medical IoT devices are currently deployed, projected to grow to 161 million by 2020. Healthcare executives identify 59% privacy concerns, 55% legacy system integration, and 54% security issues as the top three barriers to IoT adoption in healthcare.”&lt;/p&gt;

&lt;p&gt;Subh explained that Xilinx leverages its programmable platform to continuously adapt to new security measures—both software and hardware updates. These capabilities are implemented in the SoC as certified and encrypted boot, secure boot, measured boot, secure application communication, and cloud-based monitoring.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclyalp823jujg8w3llht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fclyalp823jujg8w3llht.png" width="800" height="347"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;02&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Medical Imaging&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The use of FPGA devices in large-scale medical imaging equipment is now standard practice. As Subh explained, major imaging modalities include CT, ultrasound, X-ray, PET, and MRI scanners.&lt;/p&gt;

&lt;p&gt;For medical imaging, Zynq UltraScale+ MPSoC remains applicable. Beyond that, Subh highlighted the Versal ACAP series—considered the next-generation MPSoC—which holds significant advantages in imaging applications.&lt;/p&gt;

&lt;p&gt;Versal ACAP integrates ARM multi-core processors, programmable logic, and DSP blocks, and adds AI Engines—units based on SIMD and VLIW architectures—capable of parallel processing for similar operations.&lt;/p&gt;

&lt;p&gt;Subh showcased a solution for ultrasound image reconstruction and computer-aided diagnosis. With Xilinx’s hardware and software support, this solution reduces power consumption and thermal footprint, lowers overall system cost, extends equipment lifespan, and enables low-latency edge inference. Despite market complexity, Xilinx’s technology significantly enhances productivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkzkeqazaaut1lnz6viu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbkzkeqazaaut1lnz6viu.png" width="799" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;03&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Diagnostic Analytics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Subh noted that beyond SoCs and FPGAs, Xilinx offers plug-and-play Alveo accelerator cards. As PCIe-based solutions, these cards greatly reduce development time. Alveo cards work with any standard PC, accelerating both general CPU tasks and GPU workloads, delivering high throughput and ultra-low latency. Their unique computational power and adaptability significantly speed up various medical applications.&lt;/p&gt;

&lt;p&gt;United Imaging, a Chinese company, found that replacing traditional GPUs with Alveo U200 accelerator cards resulted in lower technology costs and power consumption, without sacrificing performance or development timelines.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6u1eql7zbv47womf075k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6u1eql7zbv47womf075k.png" width="800" height="395"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FPGA vs. CPU &amp;amp; GPU&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Solutions using CPUs or GPUs in medical devices are common. Why do FPGAs perform so exceptionally well—possessing an almost “magical” ability to replace CPUs and GPUs? In reality, both CPUs and GPUs follow the von Neumann architecture, whereas FPGAs break through architectural limitations, achieving superior energy efficiency.&lt;/p&gt;

&lt;p&gt;Specifically, CPUs and GPUs rely on SIMD (Single Instruction, Multiple Data) to execute operations involving memory, decoders, arithmetic units, and branch logic. In contrast, FPGAs define the function of each logic unit during programming, eliminating the need for instruction decoding. Moreover, CPUs and GPUs share memory, requiring arbitration and maintaining cache coherency across execution units. FPGAs, however, define communication requirements during configuration and do not require shared memory for inter-unit communication.&lt;/p&gt;

&lt;p&gt;As a result, FPGAs deliver exceptional floating-point multiplication performance with lower latency than GPUs—even in floating-point operations—because FPGAs support both pipelined and data-level parallelism, while GPUs only support data parallelism.&lt;/p&gt;

&lt;p&gt;In terms of computational power, Xilinx has evolved FPGA devices into SoCs for acceleration and adaptability. Scalar engines—including ARM, application processors, and real-time processors—handle acceleration, while the adaptive engine is based on programmable logic (FPGA), supplemented by intelligent engines such as DSPs. On the Versal ACAP platform, AI Engines further enhance acceleration and adaptability.&lt;/p&gt;

&lt;p&gt;“In medical applications like endoscopy, patients undergoing surgery share a critical requirement: extremely low latency, often requiring real-time processing. From image capture by the camera, through the processing pipeline, to display output, the entire process may take less than 20 microseconds. CPUs and GPUs cannot achieve such low latency—this is FPGA’s greatest advantage over CPUs and GPUs,” Subh continued. “Additionally, in terms of power, cost, and integration, Xilinx SoC-based FPGAs offer superior benefits.”&lt;/p&gt;

&lt;p&gt;“In many fields like visualization, GPUs have been used for years. FPGAs are certainly capable, but we focus on our strengths—efficient data movement within closed systems rather than intermittent memory uploads,” Subh admitted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Analyzing FPGA Applications in Healthcare Across Layers&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Xilinx stands alone in the medical field by simultaneously delivering industry-leading AI latency and performance, extended lifecycle, high quality, reliability, security, and real-time deterministic control and interfacing.&lt;/p&gt;

&lt;p&gt;Beyond providing FPGA and SoC hardware platforms, Xilinx has developed the Vitis AI unified software platform specifically to lower FPGA development barriers and meet broad market application needs. This software platform has been previously covered extensively; it enables algorithm engineers without hardware design experience to directly implement their algorithms.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvk6590itwr5u2h62el1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvk6590itwr5u2h62el1.png" width="799" height="407"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Xilinx’s medical solutions have helped Illumina perform genomic analysis on critically ill newborns, accelerated ICU and critical care patient communication via Eyetech’s eye-tracking tablet, and partnered with Mindray to combat the pandemic. In subtle yet profound ways, FPGAs add a layer of reverence for life.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xkybwu43a766admej50.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1xkybwu43a766admej50.png" width="799" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my view, Xilinx’s FPGA devices derive their market competitiveness from two key strengths: high-performance acceleration and adaptability. On one hand, FPGAs, ARM processors, application processors, real-time processors, DSPs, and AI engines are highly integrated via SoC and software, enhancing both computational power and application scalability. On the other hand, the inherent low latency of FPGAs makes them a natural fit for medical applications with stringent timing requirements.&lt;/p&gt;

&lt;p&gt;From a market perspective, the pandemic has driven sustained growth in demand for medical devices, particularly those requiring large-scale data analysis and high portability—both aligning perfectly with FPGA SoC capabilities. Meanwhile, rising medical standards and market consolidation (Matthew effect) have increased demand for energy-efficient, low-power FPGA solutions.&lt;/p&gt;

&lt;p&gt;From a software standpoint, Xilinx’s Vitis platform serves diverse user groups: hardware engineers fluent in HDL, software engineers skilled in mainstream programming languages, and algorithm engineers experienced with TensorFlow, Caffe, and PyTorch. This flexibility empowers innovative startups to bring creative ideas to life.&lt;/p&gt;

&lt;p&gt;As illustrated by Xilinx’s presentation, FPGAs have a place in both large-scale and portable medical devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  How will Xilinx’s path of medical innovation evolve in the future? Subh stated that Xilinx will continue to increase integration and reduce package size in medical products, while advancing heterogeneous computing to improve efficiency and performance.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/137629162" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/137629162" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fpgadev</category>
    </item>
    <item>
      <title>Demystifying C Language Pointers</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Tue, 26 May 2026 07:09:05 +0000</pubDate>
      <link>https://dev.to/sienovoleo/demystifying-c-language-pointers-2fio</link>
      <guid>https://dev.to/sienovoleo/demystifying-c-language-pointers-2fio</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A pointer is a special variable whose stored value is interpreted as an address in memory. To fully understand a pointer, you need to clarify four aspects: the pointer's type, the type it points to, its value (or the memory region it points to), and the memory space occupied by the pointer itself. Let's go through each in detail.&lt;/p&gt;

&lt;p&gt;First, declare a few pointers as examples:&lt;/p&gt;

&lt;p&gt;Example One:&lt;br&gt;
(1) int* ptr;&lt;br&gt;&lt;br&gt;
(2) char* ptr;&lt;br&gt;&lt;br&gt;
(3) int** ptr;&lt;br&gt;&lt;br&gt;
(4) int(*ptr)[3];&lt;br&gt;&lt;br&gt;
(5) int*(*ptr)[4];&lt;/p&gt;

&lt;p&gt;Pointer Type&lt;br&gt;&lt;br&gt;
From a syntactic perspective, if you remove the pointer name from its declaration, what remains is the pointer's type — the inherent type of the pointer itself. Let's examine the pointer types in Example One:&lt;br&gt;
(1) int* ptr; // pointer type is int*&lt;br&gt;&lt;br&gt;
(2) char* ptr; // pointer type is char*&lt;br&gt;&lt;br&gt;
(3) int** ptr; // pointer type is int**&lt;br&gt;&lt;br&gt;
(4) int(*ptr)[3]; // pointer type is int(*)[3]&lt;br&gt;&lt;br&gt;
(5) int*(*ptr)[4]; // pointer type is int*(*)[4]  &lt;/p&gt;

&lt;p&gt;Pretty straightforward, right? The method for identifying a pointer's type is quite simple.&lt;/p&gt;

&lt;p&gt;Type Pointed To by the Pointer&lt;br&gt;&lt;br&gt;
When accessing the memory region via a pointer, the type pointed to by the pointer determines how the compiler interprets the contents of that memory region.&lt;/p&gt;

&lt;p&gt;Syntactically, remove the pointer name and the * operator to its left from the declaration — what remains is the type the pointer points to. For example:&lt;br&gt;
(1) int* ptr; // type pointed to is int&lt;br&gt;&lt;br&gt;
(2) char* ptr; // type pointed to is char&lt;br&gt;&lt;br&gt;
(3) int** ptr; // type pointed to is int*&lt;br&gt;&lt;br&gt;
(4) int(*ptr)[3]; // type pointed to is int()[3]&lt;br&gt;&lt;br&gt;
(5) int*(*ptr)[4]; // type pointed to is int*()[4]  &lt;/p&gt;

&lt;p&gt;The type pointed to plays a critical role in pointer arithmetic.&lt;/p&gt;

&lt;p&gt;The pointer's type (i.e., the type of the pointer itself) and the type it points to are two distinct concepts. As you become more familiar with C, you'll realize that distinguishing between these two types is key to mastering pointers. I've read many books, and some poorly written ones conflate these two concepts, leading to contradictions and confusion.&lt;/p&gt;

&lt;p&gt;Pointer Value, or the Memory Region (Address) It Points To&lt;br&gt;&lt;br&gt;
The pointer's value is the numerical value it stores, which the compiler interprets as a memory address rather than a regular integer. In a 32-bit program, all pointer values are 32-bit integers because all memory addresses are 32 bits long. The memory region pointed to by the pointer starts at the address represented by the pointer's value and spans a length of sizeof(the type pointed to by the pointer). Hence, saying "a pointer's value is XX" is equivalent to saying "the pointer points to a memory region starting at address XX"; similarly, saying "a pointer points to a certain memory region" means "the pointer's value is the starting address of that region."&lt;/p&gt;

&lt;p&gt;The memory region pointed to and the type pointed to are entirely different concepts. In Example One, the type pointed to is defined, but since the pointer hasn't been initialized, the memory region it points to is either nonexistent or meaningless.&lt;/p&gt;

&lt;p&gt;Whenever you encounter a pointer, always ask: What is its type? What type does it point to? Where does it point?&lt;/p&gt;

&lt;p&gt;Memory Space Occupied by the Pointer Itself&lt;br&gt;&lt;br&gt;
How much memory does a pointer occupy? You can determine this using sizeof(pointer type). On a 32-bit platform, a pointer occupies 4 bytes.&lt;/p&gt;

&lt;p&gt;This concept is particularly useful when determining whether a pointer expression is an lvalue.&lt;/p&gt;

&lt;p&gt;Pointer Arithmetic&lt;br&gt;&lt;br&gt;
A pointer can be incremented or decremented by an integer. This arithmetic differs significantly from regular integer arithmetic. For example:&lt;/p&gt;

&lt;p&gt;Example Two:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;char a[20];
&lt;/li&gt;
&lt;li&gt;int* ptr = a;
...
...
&lt;/li&gt;
&lt;li&gt;ptr++;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this example, ptr is of type int*, pointing to int, and is initialized to point to array a. In line 3, ptr is incremented by 1. The compiler handles this by adding sizeof(int) — which is 4 in a 32-bit program — to the pointer's value. Since addresses are byte-addressed, ptr now points to an address 4 bytes higher than before.&lt;/p&gt;

&lt;p&gt;Since a char is 1 byte, ptr initially pointed to the first 4 bytes starting at a[0], and now points to the 4 bytes starting at a[4].&lt;/p&gt;

&lt;p&gt;We can use a pointer and a loop to traverse an array. For example:&lt;/p&gt;

&lt;p&gt;Example Three:&lt;br&gt;
int array[20];&lt;br&gt;&lt;br&gt;
int* ptr = array;&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
// Code to initialize array values omitted&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
for (i = 0; i &amp;lt; 20; i++)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
　(*ptr)++;&lt;br&gt;&lt;br&gt;
　ptr++;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;This example increments each element of the integer array by 1. Since ptr is incremented in each iteration, it accesses the next array element each time.&lt;/p&gt;

&lt;p&gt;Another example:&lt;/p&gt;

&lt;p&gt;Example Four:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;char a[20];
&lt;/li&gt;
&lt;li&gt;int* ptr = a;
...
...
&lt;/li&gt;
&lt;li&gt;ptr += 5;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here, ptr is increased by 5. The compiler computes this as ptr's value plus 5 * sizeof(int) — 5 * 4 = 20 in a 32-bit program. Since addresses are in bytes, ptr now points 20 bytes higher. Before the addition, ptr pointed to the first 4 bytes of a; afterward, it points outside the valid range of array a. While this may cause issues in practice, it is syntactically valid — demonstrating pointer flexibility.&lt;/p&gt;

&lt;p&gt;If ptr were instead decreased by 5, the process would be similar, but ptr's value would be reduced by 5 * sizeof(int), moving it 20 bytes lower in memory.&lt;/p&gt;

&lt;p&gt;In summary:&lt;br&gt;&lt;br&gt;
When a pointer &lt;code&gt;ptrold&lt;/code&gt; is incremented by an integer &lt;code&gt;n&lt;/code&gt;, the result is a new pointer &lt;code&gt;ptrnew&lt;/code&gt;. &lt;code&gt;ptrnew&lt;/code&gt; has the same type and points to the same type as &lt;code&gt;ptrold&lt;/code&gt;. The value of &lt;code&gt;ptrnew&lt;/code&gt; is &lt;code&gt;ptrold&lt;/code&gt;'s value plus &lt;code&gt;n * sizeof(type pointed to by ptrold)&lt;/code&gt; bytes. Thus, &lt;code&gt;ptrnew&lt;/code&gt; points to a memory region &lt;code&gt;n * sizeof(type)&lt;/code&gt; bytes higher than &lt;code&gt;ptrold&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly, when &lt;code&gt;ptrold&lt;/code&gt; is decremented by &lt;code&gt;n&lt;/code&gt;, &lt;code&gt;ptrnew&lt;/code&gt; has the same type and points to the same type, but its value is reduced by &lt;code&gt;n * sizeof(type)&lt;/code&gt;, pointing &lt;code&gt;n * sizeof(type)&lt;/code&gt; bytes lower.&lt;/p&gt;

&lt;p&gt;Operators &amp;amp; and *&lt;br&gt;&lt;br&gt;
Here, &amp;amp; is the address-of operator, and * is the "indirection operator" as referred to in textbooks.&lt;/p&gt;

&lt;p&gt;The result of &amp;amp;a is a pointer. Its type is the type of a with an added *, the type it points to is the type of a, and the address it points to is the address of a.&lt;/p&gt;

&lt;p&gt;The result of *p varies. In general, *p evaluates to the object pointed to by p — its type is the type pointed to by p, and its address is the address p points to.&lt;/p&gt;

&lt;p&gt;Example Five:&lt;br&gt;
int a = 12;&lt;br&gt;&lt;br&gt;
int b;&lt;br&gt;&lt;br&gt;
int* p;&lt;br&gt;&lt;br&gt;
int** ptr;&lt;br&gt;&lt;br&gt;
p = &amp;amp;a;&lt;br&gt;&lt;br&gt;
// &amp;amp;a results in a pointer of type int*, pointing to type int, at address of a.&lt;br&gt;&lt;br&gt;
*p = 24;&lt;br&gt;&lt;br&gt;
// *p here has type int and refers to the address p points to — clearly, *p is variable a.&lt;br&gt;&lt;br&gt;
ptr = &amp;amp;p;&lt;br&gt;&lt;br&gt;
// &amp;amp;p results in a pointer of type int** (p's type with an added *), pointing to type int*, at p's own address.&lt;br&gt;&lt;br&gt;
*ptr = &amp;amp;b;&lt;br&gt;&lt;br&gt;
// *ptr is a pointer, and &amp;amp;b is also a pointer — both have the same type and pointed-to type, so assigning &amp;amp;b to *ptr is valid.&lt;br&gt;&lt;br&gt;
**ptr = 34;&lt;br&gt;&lt;br&gt;
// *ptr refers to what ptr points to — here, a pointer. Applying * again yields an int variable.&lt;/p&gt;

&lt;p&gt;Pointer Expressions&lt;br&gt;&lt;br&gt;
An expression whose final result is a pointer is called a pointer expression.&lt;/p&gt;

&lt;p&gt;Examples:&lt;br&gt;
Example Six:&lt;br&gt;
int a, b;&lt;br&gt;&lt;br&gt;
int array[10];&lt;br&gt;&lt;br&gt;
int* pa;&lt;br&gt;&lt;br&gt;
pa = &amp;amp;a; // &amp;amp;a is a pointer expression.&lt;br&gt;&lt;br&gt;
int** ptr = &amp;amp;pa; // &amp;amp;pa is also a pointer expression.&lt;br&gt;&lt;br&gt;
*ptr = &amp;amp;b; // both *ptr and &amp;amp;b are pointer expressions.&lt;br&gt;&lt;br&gt;
pa = array;&lt;br&gt;&lt;br&gt;
pa++; // this is also a pointer expression.&lt;/p&gt;

&lt;p&gt;Example Seven:&lt;br&gt;
char* arr[20];&lt;br&gt;&lt;br&gt;
char** parr = arr; // if arr is treated as a pointer, it's a pointer expression&lt;br&gt;&lt;br&gt;
char* str;&lt;br&gt;&lt;br&gt;
str = *parr; // *parr is a pointer expression&lt;br&gt;&lt;br&gt;
str = *(parr + 1); // *(parr + 1) is a pointer expression&lt;br&gt;&lt;br&gt;
str = *(parr + 2); // *(parr + 2) is a pointer expression&lt;/p&gt;

&lt;p&gt;Since a pointer expression results in a pointer, it possesses the same four attributes: pointer type, type pointed to, memory region pointed to, and memory space occupied.&lt;/p&gt;

&lt;p&gt;When the resulting pointer of a pointer expression clearly occupies its own memory, the expression is an lvalue; otherwise, it is not.&lt;/p&gt;

&lt;p&gt;In Example Seven, &amp;amp;a is not an lvalue because it doesn't occupy definite memory. *ptr is an lvalue because it already occupies memory — *ptr is effectively pointer pa, and since pa has a defined location in memory, *ptr does too.&lt;/p&gt;

&lt;p&gt;Relationship Between Arrays and Pointers&lt;br&gt;&lt;br&gt;
An array name can essentially be viewed as a pointer. For example:&lt;/p&gt;

&lt;p&gt;Example Eight:&lt;br&gt;
int array[10] = {0,1,2,3,4,5,6,7,8,9}, value;&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
value = array[0]; // equivalent to: value = *array;&lt;br&gt;&lt;br&gt;
value = array[3]; // equivalent to: value = *(array + 3);&lt;br&gt;&lt;br&gt;
value = array[4]; // equivalent to: value = *(array + 4);&lt;/p&gt;

&lt;p&gt;Typically, the array name array represents the entire array, with type int[10]. But if treated as a pointer, it points to the 0th element, has type int*, and points to type int. Thus, *array equals 0 is unsurprising. Similarly, array + 3 is a pointer to the 3rd element, so *(array + 3) equals 3, and so on.&lt;/p&gt;

&lt;p&gt;Example Nine:&lt;br&gt;
char* str[3] = {&lt;br&gt;&lt;br&gt;
　"Hello, this is a sample! ",&lt;br&gt;&lt;br&gt;
　"Hi, good morning. ",&lt;br&gt;&lt;br&gt;
　"Hello world "&lt;br&gt;&lt;br&gt;
};&lt;br&gt;&lt;br&gt;
char s[80];&lt;br&gt;&lt;br&gt;
strcpy(s, str[0]); // equivalent to: strcpy(s, *str);&lt;br&gt;&lt;br&gt;
strcpy(s, str[1]); // equivalent to: strcpy(s, *(str + 1));&lt;br&gt;&lt;br&gt;
strcpy(s, str[2]); // equivalent to: strcpy(s, *(str + 2));&lt;/p&gt;

&lt;p&gt;Here, str is a 3-element array, each element being a pointer to a string. Treating str as a pointer, it points to the 0th element, has type char**, and points to type char*.&lt;/p&gt;

&lt;p&gt;*str is a pointer of type char*, pointing to char, and pointing to the first character 'H' of "Hello, this is a sample! ".&lt;/p&gt;

&lt;p&gt;str + 1 is also a pointer, of type char**, pointing to the 1st element.&lt;/p&gt;

&lt;p&gt;*(str + 1) is a pointer of type char*, pointing to the first character 'H' of "Hi, good morning.", and so on.&lt;/p&gt;

&lt;p&gt;To summarize array names: declaring TYPE array[n] gives array two meanings:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It represents the entire array, with type TYPE[n].
&lt;/li&gt;
&lt;li&gt;It is a pointer of type TYPE*, pointing to type TYPE (the array element type), pointing to the 0th element, and occupying its own memory space — distinct from the memory of the 0th element. Its value cannot be modified; expressions like array++ are invalid.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In different expressions, array can play different roles.&lt;/p&gt;

&lt;p&gt;In sizeof(array), array represents the entire array, so sizeof returns the total size.&lt;/p&gt;

&lt;p&gt;In *array, array acts as a pointer, so the result is the value of the 0th element. sizeof(*array) returns the size of one element.&lt;/p&gt;

&lt;p&gt;In array + n (n = 0,1,2,...), array acts as a pointer, so array + n is a pointer of type TYPE*, pointing to the nth element. Thus, sizeof(array + n) returns the size of a pointer.&lt;/p&gt;

&lt;p&gt;Example Ten:&lt;br&gt;
int array[10];&lt;br&gt;&lt;br&gt;
int(*ptr)[10];&lt;br&gt;&lt;br&gt;
ptr = &amp;amp;array;&lt;/p&gt;

&lt;p&gt;Here, ptr is a pointer of type int(*)[10], pointing to type int[10], initialized with the array's base address. In ptr = &amp;amp;array, array represents the entire array.&lt;/p&gt;

&lt;p&gt;This section mentioned sizeof(). So, what does sizeof(pointer_name) measure — the size of the pointer type itself or the size of the type it points to? The answer is the former. For example:&lt;br&gt;
int(*ptr)[10];&lt;br&gt;&lt;br&gt;
Then in a 32-bit program:&lt;br&gt;
sizeof(int(*)[10]) == 4&lt;br&gt;&lt;br&gt;
sizeof(int[10]) == 40&lt;br&gt;&lt;br&gt;
sizeof(ptr) == 4&lt;/p&gt;

&lt;p&gt;In fact, sizeof(object) always returns the size of the object's own type, not any other type.&lt;/p&gt;

&lt;p&gt;Relationship Between Pointers and Structure Types&lt;br&gt;&lt;br&gt;
You can declare a pointer to a structure type.&lt;/p&gt;

&lt;p&gt;Example Eleven:&lt;br&gt;
struct MyStruct&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
　int a;&lt;br&gt;&lt;br&gt;
　int b;&lt;br&gt;&lt;br&gt;
　int c;&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
MyStruct ss = {20, 30, 40};&lt;br&gt;&lt;br&gt;
// Declares structure object ss, initialized with 20, 30, 40.&lt;br&gt;&lt;br&gt;
MyStruct* ptr = &amp;amp;ss;&lt;br&gt;&lt;br&gt;
// Declares a pointer to ss, of type MyStruct*, pointing to MyStruct.&lt;br&gt;&lt;br&gt;
int* pstr = (int*)&amp;amp;ss;&lt;br&gt;&lt;br&gt;
// Declares another pointer to ss, but with different type and pointed-to type than ptr.&lt;/p&gt;

&lt;p&gt;How to access the three members of ss via ptr?&lt;br&gt;&lt;br&gt;
Answer:&lt;br&gt;&lt;br&gt;
ptr-&amp;gt;a;&lt;br&gt;&lt;br&gt;
ptr-&amp;gt;b;&lt;br&gt;&lt;br&gt;
ptr-&amp;gt;c;&lt;/p&gt;

&lt;p&gt;How to access them via pstr?&lt;br&gt;&lt;br&gt;
Answer:&lt;br&gt;&lt;br&gt;
*pstr;        // accesses member a&lt;br&gt;&lt;br&gt;
*(pstr + 1);  // accesses member b&lt;br&gt;&lt;br&gt;
*(pstr + 2);  // accesses member c&lt;/p&gt;

&lt;p&gt;Although I've tested this code in MSVC++ 6.0, using pstr this way is non-standard. To understand why, consider how pointers access array elements:&lt;/p&gt;

&lt;p&gt;Example Twelve:&lt;br&gt;
int array[3] = {35, 56, 37};&lt;br&gt;&lt;br&gt;
int* pa = array;&lt;/p&gt;

&lt;p&gt;Accessing array elements via pa:&lt;br&gt;
*pa;         // accesses element 0&lt;br&gt;&lt;br&gt;
*(pa + 1);   // accesses element 1&lt;br&gt;&lt;br&gt;
*(pa + 2);   // accesses element 2&lt;/p&gt;

&lt;p&gt;The syntax resembles the non-standard way of accessing structure members via pointers.&lt;/p&gt;

&lt;p&gt;All C/C++ compilers store array elements in contiguous memory with no gaps. However, when storing structure members, some compilers may require alignment (e.g., word or double-word), inserting "padding bytes" between members, creating gaps.&lt;/p&gt;

&lt;p&gt;Thus, even if *pstr accesses member a of ss, *(pstr + 1) may not access member b — it might access padding bytes between a and b. This demonstrates pointer flexibility. If your goal is to detect padding bytes, this is a decent method.&lt;/p&gt;

&lt;p&gt;The correct way to access structure members via pointers is as shown with ptr in Example Twelve.&lt;/p&gt;

&lt;p&gt;Relationship Between Pointers and Functions&lt;br&gt;&lt;br&gt;
You can declare a pointer to a function:&lt;br&gt;
int fun1(char*, int);&lt;br&gt;&lt;br&gt;
int(*pfun1)(char*, int);&lt;br&gt;&lt;br&gt;
pfun1 = fun1;&lt;br&gt;&lt;br&gt;
....&lt;br&gt;&lt;br&gt;
....&lt;br&gt;&lt;br&gt;
int a = (*pfun1)("abcdefg", 7); // call function via function pointer.&lt;/p&gt;

&lt;p&gt;You can also use pointers as function parameters and use pointer expressions as arguments.&lt;/p&gt;

&lt;p&gt;Example Thirteen:&lt;br&gt;
int fun(char*);&lt;br&gt;&lt;br&gt;
int a;&lt;br&gt;&lt;br&gt;
char str[] = "abcdefghijklmn ";&lt;br&gt;&lt;br&gt;
a = fun(str);&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
int fun(char* s)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
int num = 0;&lt;br&gt;&lt;br&gt;
for(int i = 0; i &amp;lt; strlen(s); i++)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
num += *s; s++;&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
return num;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;This function fun calculates the sum of ASCII values of all characters in a string. As mentioned earlier, an array name is also a pointer. When str is passed to s, the value of str (its address) is copied to s. s and str point to the same location but occupy separate storage. Incrementing s inside the function does not affect str.&lt;/p&gt;

&lt;p&gt;Pointer Type Casting&lt;br&gt;&lt;br&gt;
When initializing or assigning a pointer, the left side is a pointer, and the right side is a pointer expression. In most earlier examples, the pointer type and the expression type match, as do the types they point to.&lt;/p&gt;

&lt;p&gt;Example Fourteen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;float f = 12.3;
&lt;/li&gt;
&lt;li&gt;float* fptr = &amp;amp;f;
&lt;/li&gt;
&lt;li&gt;int* p;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Suppose we want p to point to float f. Can we write:&lt;br&gt;
p = &amp;amp;f;&lt;/p&gt;

&lt;p&gt;No. p has type int*, pointing to int. &amp;amp;f has type float*, pointing to float. The types don't match. At least in MSVC++ 6.0, pointer assignments require matching types and pointed-to types. (Other compilers may vary.) To achieve this, we need a "cast":&lt;br&gt;
p = (int*)&amp;amp;f;&lt;/p&gt;

&lt;p&gt;To convert a pointer p to type TYPE* pointing to TYPE, use:&lt;br&gt;
(TYPE*)p;&lt;/p&gt;

&lt;p&gt;This cast creates a new pointer of type TYPE*, pointing to TYPE, at the same address. The original pointer p remains unchanged.&lt;/p&gt;

&lt;p&gt;When a function uses a pointer parameter, type conversion also occurs during argument passing.&lt;/p&gt;

&lt;p&gt;Example Fifteen:&lt;br&gt;
void fun(char*);&lt;br&gt;&lt;br&gt;
int a = 125, b;&lt;br&gt;&lt;br&gt;
fun((char*)&amp;amp;a);&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
void fun(char* s)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
char c;&lt;br&gt;&lt;br&gt;
c = *(s + 3); *(s + 3) = *(s + 0); *(s + 0) = c;&lt;br&gt;&lt;br&gt;
c = *(s + 2); *(s + 2) = *(s + 1); *(s + 1) = c;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Note: This is a 32-bit program — int is 4 bytes, char is 1 byte. The function fun reverses the byte order of an integer. Notice that in the function call, &amp;amp;a has type int*, pointing to int, while the parameter s has type char*, pointing to char. Thus, a conversion from int* to char* occurs. Imagine the compiler creates a temporary char* temp, assigns temp = (char*)&amp;amp;a, then passes temp to s. The result: s is of type char*, points to char, and points to the address of a.&lt;/p&gt;

&lt;p&gt;We know a pointer's value is the address it points to — a 32-bit integer in 32-bit programs. Can we assign an integer directly as a pointer value?&lt;br&gt;
unsigned int a;&lt;br&gt;&lt;br&gt;
TYPE* ptr; // TYPE could be int, char, struct, etc.&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
a = 20345686;&lt;br&gt;&lt;br&gt;
ptr = 20345686; // want ptr to point to address 20345686 (decimal)&lt;br&gt;&lt;br&gt;
ptr = a; // same goal&lt;/p&gt;

&lt;p&gt;Compiling this shows both lines are invalid. Is there no way? Yes, there is:&lt;br&gt;
unsigned int a;&lt;br&gt;&lt;br&gt;
TYPE* ptr;&lt;br&gt;&lt;br&gt;
...&lt;br&gt;&lt;br&gt;
a = some_value; // must represent a valid address&lt;br&gt;&lt;br&gt;
ptr = (TYPE*)a; // this works.&lt;/p&gt;

&lt;p&gt;Strictly speaking, this (TYPE*) differs slightly from casting in pointer conversions. Here, (TYPE*) treats the unsigned integer a as a memory address. a must represent a valid address; otherwise, using ptr may cause illegal access.&lt;/p&gt;

&lt;p&gt;Can we reverse this — extract a pointer's value as an integer, then assign that integer as an address to another pointer? Yes. Example:&lt;/p&gt;

&lt;p&gt;Example Sixteen:&lt;br&gt;
int a = 123, b;&lt;br&gt;&lt;br&gt;
int* ptr = &amp;amp;a;&lt;br&gt;&lt;br&gt;
char* str;&lt;br&gt;&lt;br&gt;
b = (int)ptr; // extract ptr's value as integer&lt;br&gt;&lt;br&gt;
str = (char*)b; // assign integer as address to str&lt;/p&gt;

&lt;p&gt;Now we know: a pointer's value can be extracted as an integer, and an integer can be assigned as a pointer address.&lt;/p&gt;

&lt;p&gt;Pointer Safety Issues&lt;br&gt;&lt;br&gt;
Consider this example:&lt;/p&gt;

&lt;p&gt;Example Seventeen:&lt;br&gt;
char s = 'a';&lt;br&gt;&lt;br&gt;
int* ptr;&lt;br&gt;&lt;br&gt;
ptr = (int*)&amp;amp;s;&lt;br&gt;&lt;br&gt;
*ptr = 1298;&lt;/p&gt;

&lt;p&gt;ptr is an int* pointing to int, at the address of s. In a 32-bit program, s occupies 1 byte, int occupies 4. The last statement modifies not only s's byte but also the next 3 higher bytes. What are those bytes? Only the compiler knows — they might hold critical data or even executable code. Your careless pointer use could corrupt them, causing a crash.&lt;/p&gt;

&lt;p&gt;Another example:&lt;/p&gt;

&lt;p&gt;Example Eighteen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;char a;
&lt;/li&gt;
&lt;li&gt;int* ptr = &amp;amp;a;
...
...
&lt;/li&gt;
&lt;li&gt;ptr++;
&lt;/li&gt;
&lt;li&gt;*ptr = 115;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This compiles and runs. But after incrementing ptr in line 3, it points to memory adjacent to a. What's there? Unknown — possibly critical data or code. Line 4 writes to that region — a serious error. Always know exactly where your pointer points. When using pointers with arrays, ensure you don't exceed array bounds, or similar errors occur.&lt;/p&gt;

&lt;p&gt;In pointer casting: ptr1 = (TYPE*)ptr2, if sizeof(ptr2's type) &amp;gt; sizeof(ptr1's type), accessing ptr2's memory via ptr1 is safe. If sizeof(ptr2's type) &amp;lt; sizeof(ptr1's type), it's unsafe. Think about Example Seventeen to understand why.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="http://embedfans.com/C/2007181016375897.htm" rel="noopener noreferrer"&gt;http://embedfans.com/C/2007181016375897.htm&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6782297" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6782297" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>c</category>
      <category>language</category>
      <category>compiler</category>
      <category>storage</category>
    </item>
    <item>
      <title>Summary of Chinese Character Encoding and Programming: How ASCII, Internal Code, Zone-Position Code, GB Code, and Unicode Are Converted</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Mon, 25 May 2026 07:30:20 +0000</pubDate>
      <link>https://dev.to/sienovoleo/summary-of-chinese-character-encoding-and-programming-how-ascii-internal-code-zone-position-3a20</link>
      <guid>https://dev.to/sienovoleo/summary-of-chinese-character-encoding-and-programming-how-ascii-internal-code-zone-position-3a20</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;I. How do ASCII, internal code, zone-position code, GB code, and Unicode convert among each other? What are the conversion formulas?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The process in Chinese character systems involves zone-position code, national standard code (GB code), and internal machine code. The conversion relationships are as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Convert zone-position code (decimal) to zone-position code (hexadecimal)&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
Convert the zone number and position number separately into hexadecimal.&lt;br&gt;&lt;br&gt;
For example, if a character's zone-position code is 5448, convert 54 to hexadecimal 36, and 48 to hexadecimal 30. The resulting hexadecimal code is 3630.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GB Code = Zone-Position Code (hex) + 2020H&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: 3630H + 2020H = 5050H → This yields the GB2312 national standard code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Internal Machine Code = GB Code + 8080H&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Example: 5050H + 8080H = D0D0H.&lt;br&gt;&lt;br&gt;
ASCII uses a single byte with the highest bit set to 0, which distinguishes it from Chinese character encoding.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Unicode is a character encoding standard proposed in Europe. If a large data packet contains double-byte values greater than A0A0H, it can preliminarily be identified as Chinese character encoding. Note: In data packets, you can only obtain the internal machine code. Zone-position code is an input code and does not exist inside computers.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;II. What are the differences and relationships between GBK internal code, Unicode, and zone-position code? How to convert among them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ANSI&lt;/strong&gt; is an encoding format established by the &lt;a href="http://wenwen.soso.com/z/Search.e?sp=S%E7%BE%8E%E5%9B%BD%E5%9B%BD%E5%AE%B6%E6%A0%87%E5%87%86%E5%8D%8F%E4%BC%9A&amp;amp;ch=w.search.yjjlink&amp;amp;cid=w.search.yjjlink" rel="noopener noreferrer"&gt;American National Standards Institute&lt;/a&gt;. For example, the string "A汉" in ANSI encoding has the byte values &lt;code&gt;41 BA BA&lt;/code&gt; in memory: 'A' occupies one &lt;a href="http://wenwen.soso.com/z/Search.e?sp=S%E5%AD%97%E8%8A%82&amp;amp;ch=w.search.yjjlink&amp;amp;cid=w.search.yjjlink" rel="noopener noreferrer"&gt;byte&lt;/a&gt;, while "汉" uses two bytes.&lt;br&gt;&lt;br&gt;
Here, &lt;code&gt;BA BA&lt;/code&gt; is exactly the GBK internal code value. Let's first understand GBK encoding.&lt;/p&gt;

&lt;p&gt;GB2312, GBK, and GB18030 are all Chinese-developed encoding standards (not used outside China), introduced in chronological order: GB2312 → GBK → GB18030. They are backward compatible. "GB" likely stands for "Guo Biao" (National Standard), and "K" may mean "Kuo Zhan" (Extended). These are formal specifications. To represent GB2312 in computer memory, each byte of the zone-position code must have 0x80 added to form the &lt;a href="http://wenwen.soso.com/z/Search.e?sp=S%E6%9C%BA%E5%86%85%E7%A0%81&amp;amp;ch=w.search.yjjlink&amp;amp;cid=w.search.yjjlink" rel="noopener noreferrer"&gt;internal code&lt;/a&gt;. Adding 0x80 ensures the highest bit of each byte is 1, allowing memory to distinguish Chinese characters from ASCII (whose highest bit is always 0).  &lt;/p&gt;

&lt;p&gt;However, when extending GB2312 to GBK and GB18030, more encoding space was needed. Thus, GBK and GB18030 do not require the second byte’s highest bit to be 1. Instead, the first byte determines whether it's a single-byte ASCII or a double-byte GBK character. Note: GB2312, GBK, and GB18030 are backward compatible. For example, the character "汉" is encoded as &lt;code&gt;BA BA&lt;/code&gt; in all three standards.&lt;/p&gt;

&lt;p&gt;Moreover, GB2312 and GBK have not disappeared due to GB18030; they are still widely used in &lt;a href="http://wenwen.soso.com/z/Search.e?sp=S%E5%B5%8C%E5%85%A5%E5%BC%8F%E8%AE%BE%E5%A4%87&amp;amp;ch=w.search.yjjlink&amp;amp;cid=w.search.yjjlink" rel="noopener noreferrer"&gt;embedded devices&lt;/a&gt; because reducing font library size significantly cuts costs.&lt;/p&gt;

&lt;p&gt;Back to ANSI: We now understand GBK (though it's unclear why GBK is preferred over GB18030—perhaps because "GBK" is shorter and easier to write). So what is ANSI? ANSI acts like a pointer with no inherent content. If it points to "Chinese encoding," it means GBK; if to "Indian encoding," it means something else. Thus, in China, ANSI means GBK; in Japan, it means XXX; in India, ???—but in Windows Notepad, they all appear as "ANSI." However, ANSI makes a small adjustment: as shown earlier, 'A' occupies only one byte in memory. So ANSI = ASCII + local encoding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unicode&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
But how can we write Japanese characters in a Chinese document? This is where Unicode comes in. Whoever invented it, Unicode includes all written characters worldwide, solving the above issue. Programs written in Unicode by &lt;a href="http://wenwen.soso.com/z/Search.e?sp=S%E7%A8%8B%E5%BA%8F%E5%91%98&amp;amp;ch=w.search.yjjlink&amp;amp;cid=w.search.yjjlink" rel="noopener noreferrer"&gt;programmers&lt;/a&gt; can run on computers globally. In C, Unicode is represented using &lt;code&gt;wchar_t&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UCS&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
UCS is reportedly a parallel project to Unicode. Eventually, both projects reached consensus and are fully compatible. Thus, UCS can be treated as equivalent to Unicode.&lt;br&gt;&lt;br&gt;
UCS-2 (commonly referred to as UCS) uses two bytes per character, while UCS-4 uses four.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UTF-8&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
(UCS Transformation Format) Why was UTF-8 created? One reason: In C and operating systems, &lt;code&gt;0x00&lt;/code&gt; has special meaning (e.g., string termination). However, in raw Unicode encoding, a character might have a non-zero high byte and a zero low byte, causing C to mistakenly treat it as a string end. UTF-8 ensures that &lt;code&gt;0x00&lt;/code&gt; does not appear in the encoded byte stream (except for the actual null character).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UTF-8 Encoding Rules&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UCS-2 (Hex)     UTF-8 Byte Stream (Binary)
0000 - 007F     0xxxxxxx
0080 - 07FF     110xxxxx 10xxxxxx  (Number of 1s after the first 1 indicates following bytes: 1 here)
0800 - FFFF     1110xxxx 10xxxxxx 10xxxxxx  (2 following bytes)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Due to this encoding scheme, UTF-8 does not require endianness detection, making it suitable for network transmission (reason not explained here).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BOM (Byte Order Mark)&lt;/strong&gt;: &lt;code&gt;EF BB BF&lt;/code&gt;. We can use BOM to detect if a text file is UTF-8 encoded.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to detect a text file's encoding when opening it?&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Prompt the user to select the encoding type.
&lt;/li&gt;
&lt;li&gt;Guess the encoding based on certain rules.
&lt;/li&gt;
&lt;li&gt;Detect file header signatures:

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;EF BB BF&lt;/code&gt; → UTF-8
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FE FF&lt;/code&gt; → UTF-16/UCS-2 (Unicode), little endian (e.g., a file with only 'A' contains &lt;code&gt;FE FF 00 41&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FF FE&lt;/code&gt; → UTF-16/UCS-2 (Unicode), big endian (e.g., &lt;code&gt;FF FE 41 00&lt;/code&gt;)
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FF FE 00 00&lt;/code&gt; → UTF-32/UCS-4, little endian
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;00 00 FE FF&lt;/code&gt; → UTF-32/UCS-4, big-endian&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Zone-Position Code, GB (GBK) Code, Internal Code&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Character&lt;/th&gt;
&lt;th&gt;Zone-Position&lt;/th&gt;
&lt;th&gt;GB Code&lt;/th&gt;
&lt;th&gt;Internal Code&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;汉&lt;/td&gt;
&lt;td&gt;1A1A&lt;/td&gt;
&lt;td&gt;3A3A&lt;/td&gt;
&lt;td&gt;BABA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GB Code = Zone-Position Code + 0x20 (per byte)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal Code = GB Code + 0x80 (per byte)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;strong&gt;III. Summary of Chinese Character Encoding and Programming Issues&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;There are many Chinese character encodings. Common ones include UNICODE, GB (internal code), and GB2312-80 (zone-position code). UNICODE is the international character set standard, compatible only with ASCII.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The difference between GB (internal code) and GB2312-80 (zone-position code) is that GB (internal code) is represented as a 4-digit hexadecimal number, while GB2312-80 (zone-position code) uses a 4-digit decimal number. The conversion is as follows:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GB (internal code) = ((GB2312-80(zone-position)/100 + 160) &amp;lt;&amp;lt; 8) | ((GB2312-80(zone-position) % 100) + 160)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. How to convert or query Chinese character encoding?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, the character "汉": write it in Notepad and open the file with WinHex. The displayed code &lt;code&gt;BABA&lt;/code&gt; is its GB (internal code). You can also calculate its zone-position code using the reverse method:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(High byte - 0xA0, Low byte - 0xA0) → Convert to decimal → GB2312-80 (zone-position code)&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Note: 0xA0 = 160 (hex vs. decimal representation)&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;&lt;br&gt;
&lt;code&gt;(0xBA - 0xA0) * 100 + (0xBA - 0xA0) = 26 * 100 + 26 = 2626&lt;/code&gt; → This is the GB2312-80 zone-position code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. When programming with many Chinese characters, use WinHex's conversion feature to generate C code directly instead of typing manually.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For example, drag a document or image file into WinHex, right-click the data → Edit → Copy All → As C Source. The data in C format is copied to the clipboard and can be pasted into any document.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. How to obtain the Unicode code of a Chinese character from text?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;Notepad++&lt;/strong&gt;, a free open-source editor (excellent for coding, with built-in syntax highlighting). Open a document in Notepad++, then:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Format → Convert to UCS-2 Big/Little Endian&lt;/strong&gt;, then save. The file is now saved in Unicode encoding.&lt;/p&gt;

&lt;p&gt;Open it in WinHex to view the Unicode code. Choosing big or little endian only affects byte order (big endian places high byte first, at lower memory address).&lt;/p&gt;

&lt;p&gt;Below is an additional translated article and the standard Chinese zone-position code table to help understand various encoding formats:&lt;/p&gt;

&lt;p&gt;////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"On Unicode Encoding" by fmddlmyy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Unicode is a character encoding method capable of accommodating all written languages. The encoding methods from ASCII, GB2312, GBK to GB18030 are backward compatible. Unicode, however, is only compatible with ASCII (more precisely, ISO-8859-1), not with GB codes. For example, the Unicode code for "汉" is &lt;code&gt;6C49&lt;/code&gt;, while its GB code is &lt;code&gt;BABA&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is a fun read for programmers—fun in the sense of easily understanding previously unclear concepts, gaining knowledge, like leveling up in an RPG game. The motivation for writing this article came from two questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 1:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Using Windows Notepad's "Save As," you can convert between GBK, Unicode, Unicode big endian, and UTF-8. For the same &lt;code&gt;.txt&lt;/code&gt; file, how does Windows identify the encoding?&lt;/p&gt;

&lt;p&gt;I long noticed that Unicode, Unicode big endian, and UTF-8 files have extra bytes at the beginning: &lt;code&gt;FF FE&lt;/code&gt; (Unicode), &lt;code&gt;FE FF&lt;/code&gt; (Unicode big endian), &lt;code&gt;EF BB BF&lt;/code&gt; (UTF-8). But what standard defines these markers?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 2:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Recently, I found a &lt;code&gt;ConvertUTF.c&lt;/code&gt; that converts among UTF-32, UTF-16, and UTF-8. I already knew about Unicode (UCS2), GBK, and UTF-8. But this program confused me—what's the relationship between UTF-16 and UCS2?&lt;/p&gt;

&lt;p&gt;After researching, I finally clarified these issues and learned some Unicode details. I wrote this article for others with similar questions. I tried to make it easy to understand, assuming readers know what bytes and hexadecimal are.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;0. Big Endian and Little Endian&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Big and little endian are CPU methods for handling multi-byte numbers. For example, the Unicode code for "汉" is &lt;code&gt;6C49&lt;/code&gt;. When writing to a file, should &lt;code&gt;6C&lt;/code&gt; come first or &lt;code&gt;49&lt;/code&gt;? If &lt;code&gt;6C&lt;/code&gt; comes first, it's big endian; if &lt;code&gt;49&lt;/code&gt; comes first, it's little endian.&lt;/p&gt;

&lt;p&gt;The term "endian" comes from &lt;em&gt;Gulliver's Travels&lt;/em&gt;, where a civil war erupted over whether to crack an egg from the big end (Big-Endian) or the small end (Little-Endian), causing six rebellions, one emperor's death, and another's dethronement.&lt;/p&gt;

&lt;p&gt;We usually translate "endian" as "byte order," with "big endian" and "little endian" as "big-end" and "little-end."&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Character Encoding, Internal Code, and Chinese Encoding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Characters must be encoded to be processed by computers. The default encoding used by a computer is its internal code. Early computers used 7-bit ASCII. To handle Chinese, programmers designed GB2312 for simplified Chinese and Big5 for traditional Chinese.&lt;/p&gt;

&lt;p&gt;GB2312 (1980) includes 7,445 characters: 6,763 Chinese characters and 682 other symbols. The Chinese character area ranges from B0-F7 (high byte) and A1-FE (low byte), covering 72×94 = 6,768 code points, with 5 unused positions (D7FA-D7FE).&lt;/p&gt;

&lt;p&gt;GB2312 supports too few characters. GBK1.0 (1995) expanded to 21,886 symbols, divided into Chinese and graphic symbol areas, with 21,003 Chinese characters. GB18030 (2000) replaced GBK1.0 as the official national standard, including 27,484 Chinese characters and major minority scripts like Tibetan, Mongolian, and Uyghur. Current PC platforms must support GB18030, but embedded products are exempt. Thus, phones and MP3s usually support only GB2312.&lt;/p&gt;

&lt;p&gt;From ASCII, GB2312, GBK to GB18030, these encodings are backward compatible: the same character has the same code across standards, and later standards support more characters. English and Chinese can be uniformly processed. Chinese characters are identified by a high byte with the highest bit set to 1. Programmers refer to GB2312, GBK, and GB18030 as Double-Byte Character Sets (DBCS).&lt;/p&gt;

&lt;p&gt;Some Chinese Windows systems still use GBK as the default internal code. GB18030 upgrade packs are available. However, the additional characters in GB18030 are rarely used, so "GBK" often refers to Chinese Windows internal code.&lt;/p&gt;

&lt;p&gt;Some details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GB2312 originally uses zone-position code. To convert to internal code, add A0 to both high and low bytes.&lt;/li&gt;
&lt;li&gt;In DBCS, GB internal code is always stored in big-endian (high byte first).&lt;/li&gt;
&lt;li&gt;Both bytes in GB2312 have their highest bit set to 1. But only 128×128 = 16,384 code points meet this. Thus, GBK and GB18030 low bytes may not have the highest bit set. However, this doesn't affect DBCS parsing: when reading a DBCS stream, encountering a byte with the highest bit set indicates the next two bytes form a double-byte character, regardless of the low byte's high bit.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;2. Unicode, UCS, and UTF&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As mentioned, ASCII → GB2312 → GBK → GB18030 are backward compatible. Unicode is only compatible with ASCII (ISO-8859-1), not GB codes. For example, "汉" is &lt;code&gt;6C49&lt;/code&gt; in Unicode, &lt;code&gt;BABA&lt;/code&gt; in GB.&lt;/p&gt;

&lt;p&gt;Unicode is a character encoding method designed internationally to include all written languages. Its full name is "Universal Multiple-Octet Coded Character Set" (UCS), which can be seen as "Unicode Character Set."&lt;/p&gt;

&lt;p&gt;According to Wikipedia (&lt;a href="http://zh.wikipedia.org/wiki/" rel="noopener noreferrer"&gt;http://zh.wikipedia.org/wiki/&lt;/a&gt;), two independent groups developed Unicode: ISO (International Organization for Standardization) and Unicode Consortium (a software vendors' association). ISO developed ISO 10646; Unicode Consortium developed Unicode.&lt;/p&gt;

&lt;p&gt;Around 1991, both realized the world didn't need two incompatible standards. They merged their work and collaborated on a single encoding table. Starting with Unicode 2.0, Unicode adopted the same character set and codes as ISO 10646-1.&lt;/p&gt;

&lt;p&gt;Both projects still exist and publish standards independently. Unicode Consortium's latest version is Unicode 4.1.0 (2005). ISO's latest is 10646-3:2003.&lt;/p&gt;

&lt;p&gt;UCS defines how to represent various scripts using multiple bytes. UTF (UCS Transformation Format) defines how to transmit these encodings. Common UTF formats include UTF-8, UTF-7, UTF-16.&lt;/p&gt;

&lt;p&gt;IETF's RFC2781 and RFC3629 clearly and rigorously describe UTF-16 and UTF-8 encoding methods. IETF (Internet Engineering Task Force) maintains RFCs, the foundation of all Internet standards.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. UCS-2, UCS-4, BMP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UCS has two formats: UCS-2 (2 bytes) and UCS-4 (4 bytes, using only 31 bits; highest bit must be 0). Some simple math:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;UCS-2: 2^16 = 65,536 code points
&lt;/li&gt;
&lt;li&gt;UCS-4: 2^31 = 2,147,483,648 code points&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;UCS-4 divides the highest byte (with MSB=0) into 128 groups. Each group divides the second byte into 256 planes. Each plane divides the third byte into 256 rows, each with 256 cells (only the last byte differs).&lt;/p&gt;

&lt;p&gt;Group 0, Plane 0 is called the Basic Multilingual Plane (BMP). Alternatively, UCS-4 code points with the top two bytes zero are BMP.&lt;/p&gt;

&lt;p&gt;Removing the two leading zero bytes from UCS-4 BMP yields UCS-2. Adding two zero bytes to UCS-2 yields UCS-4 BMP. Currently, no UCS-4 characters are assigned outside BMP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. UTF Encoding&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UTF-8 encodes UCS in 8-bit units. UCS-2 to UTF-8 conversion:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;UCS-2 (Hex)     UTF-8 Byte Stream (Binary)
0000 - 007F     0xxxxxxx
0080 - 07FF     110xxxxx 10xxxxxx
0800 - FFFF     1110xxxx 10xxxxxx 10xxxxxx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example: "汉" has Unicode code &lt;code&gt;6C49&lt;/code&gt;. Since &lt;code&gt;6C49&lt;/code&gt; is in 0800–FFFF, it uses the 3-byte template: &lt;code&gt;1110xxxx 10xxxxxx 10xxxxxx&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
&lt;code&gt;6C49&lt;/code&gt; in binary is &lt;code&gt;0110110001001001&lt;/code&gt;. Filling the template:&lt;br&gt;&lt;br&gt;
&lt;code&gt;11100110 10110001 10001001&lt;/code&gt; → &lt;code&gt;E6 B1 89&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can test this encoding in Notepad.&lt;/p&gt;

&lt;p&gt;UTF-16 encodes UCS in 16-bit units. For UCS codes &amp;lt; 0x10000, UTF-16 equals the 16-bit unsigned integer. For ≥ 0x10000, a specific algorithm is used. However, since UCS-2 and UCS-4 BMP are always &amp;lt; 0x10000, UTF-16 and UCS-2 are currently nearly identical. But UCS-2 is just a scheme, while UTF-16 is for actual transmission, requiring byte order consideration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. UTF Byte Order and BOM&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;UTF-8 uses bytes as units, so no byte order issue. UTF-16 uses 16-bit units; before interpreting a UTF-16 text, you must know the byte order of each unit. For example, receiving byte stream &lt;code&gt;594E&lt;/code&gt;: is it "奎" (Unicode 594E) or "乙" (4E59)?&lt;/p&gt;

&lt;p&gt;Unicode recommends using BOM (Byte Order Mark) to indicate byte order. BOM is a clever idea:&lt;/p&gt;

&lt;p&gt;UCS defines a character "ZERO WIDTH NO-BREAK SPACE" with code &lt;code&gt;FEFF&lt;/code&gt;. &lt;code&gt;FFFE&lt;/code&gt; does not exist in UCS and should never appear in transmission. UCS suggests transmitting &lt;code&gt;FEFF&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;If the receiver gets &lt;code&gt;FEFF&lt;/code&gt;, the stream is big-endian; if &lt;code&gt;FFFE&lt;/code&gt;, it's little-endian. Thus, "ZERO WIDTH NO-BREAK SPACE" is called BOM.&lt;/p&gt;

&lt;p&gt;UTF-8 doesn't need BOM for byte order, but can use it to indicate encoding. The UTF-8 encoding of &lt;code&gt;FEFF&lt;/code&gt; is &lt;code&gt;EF BB BF&lt;/code&gt;. So, if a stream starts with &lt;code&gt;EF BB BF&lt;/code&gt;, it's UTF-8.&lt;/p&gt;

&lt;p&gt;Windows uses BOM to mark text file encodings.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Further References&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Main reference: "Short overview of ISO-IEC 10646 and Unicode" (&lt;a href="http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html" rel="noopener noreferrer"&gt;http://www.nada.kth.se/i18n/ucs/unicode-iso10646-oview.html&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Two other good resources (not read, as my questions were answered):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"Understanding Unicode A general introduction to the Unicode Standard" (&lt;a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;amp;item_id=IWS-Chapter04a" rel="noopener noreferrer"&gt;http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;amp;item_id=IWS-Chapter04a&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;"Character set encoding basics Understanding character set encodings and legacy encodings" (&lt;a href="http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;amp;item_id=IWS-Chapter03" rel="noopener noreferrer"&gt;http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;amp;item_id=IWS-Chapter03&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I've written software packages for converting between UTF-8, UCS-2, and GBK, including versions with and without Windows API. I may publish them on my homepage (&lt;a href="http://fmddlmyy.home4u.china.com" rel="noopener noreferrer"&gt;http://fmddlmyy.home4u.china.com&lt;/a&gt;) later.&lt;/p&gt;

&lt;p&gt;I wrote this article only after fully understanding everything, expecting it to take minutes. But wording and detail-checking took hours—from 1:30 PM to 9:00 PM. I hope readers benefit.&lt;/p&gt;

&lt;p&gt;//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GB = (Hex)(GB2312(H) + 160) + (Hex)(GB2312(L) + 160)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;People's Republic of China National Standard&lt;br&gt;&lt;br&gt;
   Chinese Character Coded Character Set for Information Interchange&lt;br&gt;&lt;br&gt;
   Basic Set&lt;br&gt;&lt;br&gt;
   GB 2312-80&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;(Zone-position code table follows, unchanged)&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6722193" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6722193" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>transformation</category>
      <category>character</category>
      <category>windows</category>
    </item>
    <item>
      <title>Design and Implementation of AM5728 DSP+ARM-Based Logistics Robots for Automated Sorting and Delivery, AGV</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Sun, 24 May 2026 07:03:46 +0000</pubDate>
      <link>https://dev.to/sienovoleo/design-and-implementation-of-am5728-dsparm-based-logistics-robots-for-automated-sorting-and-39fg</link>
      <guid>https://dev.to/sienovoleo/design-and-implementation-of-am5728-dsparm-based-logistics-robots-for-automated-sorting-and-39fg</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;AM5728 DSP+ARM-based logistics robot enabling automated sorting and delivery&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgconvert.csdnimg.cn%2FaHR0cHM6Ly90aW1nc2EuYmFpZHUuY29tL3RpbWc_aW1hZ2UmcXVhbGl0eT04MCZzaXplPWI5OTk5XzEwMDAwJnNlYz0xNTkwNTkzNTg4MzgwJmRpPWU1NjE4NjA5MDVkNTI2NTM1YmEyOGE3MTg3YTQ0ZDRhJmltZ3R5cGU9MCZzcmM9aHR0cCUzQSUyRiUyRnprcmVzMS5teXpha2VyLmNvbSUyRjIwMTkwNiUyRjVjZmU0YzE2OGU5ZjA5Njk3NzBmMWNlYl8xMDI0LmpwZw%3Fx-oss-process%3Dimage%2Fformat%2Cpng" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgconvert.csdnimg.cn%2FaHR0cHM6Ly90aW1nc2EuYmFpZHUuY29tL3RpbWc_aW1hZ2UmcXVhbGl0eT04MCZzaXplPWI5OTk5XzEwMDAwJnNlYz0xNTkwNTkzNTg4MzgwJmRpPWU1NjE4NjA5MDVkNTI2NTM1YmEyOGE3MTg3YTQ0ZDRhJmltZ3R5cGU9MCZzcmM9aHR0cCUzQSUyRiUyRnprcmVzMS5teXpha2VyLmNvbSUyRjIwMTkwNiUyRjVjZmU0YzE2OGU5ZjA5Njk3NzBmMWNlYl8xMDI0LmpwZw%3Fx-oss-process%3Dimage%2Fformat%2Cpng" width="800" height="400"&gt;&lt;/a&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrnso8i1xwse09v9r7wx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmrnso8i1xwse09v9r7wx.png" width="634" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Physical view of Amazon logistics robots:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g5tw7cbkuza9wrcq9oe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5g5tw7cbkuza9wrcq9oe.png" width="800" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tsnxbuclcrecrp2wkd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4tsnxbuclcrecrp2wkd3.png" width="800" height="1067"&gt;&lt;/a&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwv0r75ji6jqv1d4tecp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frwv0r75ji6jqv1d4tecp.png" width="800" height="1067"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Function Overview and Application Areas&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;China's logistics industry started relatively late and lags behind in development level, especially in the application of information technology, where it significantly trails developed countries. Many advanced technologies and equipment widely adopted abroad are rarely used domestically. This gap results in hundreds of billions of yuan in economic losses annually due to inefficiencies in logistics. Achieving logistics informatization has thus become an inevitable trend for the modern development of China's logistics sector.&lt;/p&gt;

&lt;p&gt;The implementation of barcode identification systems in express logistics has enhanced the informatization level of logistics enterprises, significantly improving operational efficiency, reducing costs, and minimizing errors.&lt;/p&gt;

&lt;p&gt;At the front end of the logistics workflow—immediately after unloading—industrial machine vision technology is employed to automatically scan parcel label barcodes.&lt;/p&gt;

&lt;p&gt;This solution uses smart cameras to capture images of shipping labels. The captured images are transferred to an image processing board for algorithmic analysis to extract barcode data. This barcode data is then combined with existing weight and volume information from volumetric weighing machines. Finally, the integrated data is transmitted to a central server via 2G/3G/4G networks, enabling automated sorting at distribution centers.&lt;/p&gt;

&lt;p&gt;Applications include automated sorting and delivery systems for major Chinese courier companies such as Yunda, SF Express, YTO Express, and STO Express.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Overall Design and Key Modules&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;▼ Image Acquisition and Processing Hardware System Based on Core Module&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygkje4s76uo2yoo5ovje.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fygkje4s76uo2yoo5ovje.png" width="482" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0j0jo7g1oqtaop7zy9t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl0j0jo7g1oqtaop7zy9t.png" width="773" height="302"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As shown above, the XM5728-DIK-V3 is compact and features a no-edge-design, with all functional interfaces brought out via pin headers. However, the baseboard's built-in functions alone do not fully meet customer requirements. Therefore, customers designed a custom carrier board, extending required functionalities through MIOe expansion interfaces and direct pin connections from the main module. By using PCB traces instead of cables, the design efficiently integrates all desired functions into the carrier board, quickly and effectively meeting interface, thermal dissipation, mechanical structure, and shock resistance requirements. Sienovo provides comprehensive technical support, including schematic review and debugging assistance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felrivzetsr7wrlh7upex.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Felrivzetsr7wrlh7upex.png" width="644" height="406"&gt;&lt;/a&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm1kpuy87wrulbgytf23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgm1kpuy87wrulbgytf23.png" width="642" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Visual Inspection Principle of Sorting System&lt;/p&gt;

&lt;p&gt;Visual inspection consists of two parts: detecting the color and shape of packages, and recognizing barcodes on shipping labels.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Package Color and Shape Detection&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
A color camera is used to identify packages. When a package reaches directly beneath the camera, the camera is triggered to capture an image. The AM5728 processor acquires and analyzes the image using algorithms.&lt;/p&gt;

&lt;p&gt;The recognition algorithm includes the following steps:&lt;/p&gt;

&lt;p&gt;❶ Noise reduction on the captured image;&lt;/p&gt;

&lt;p&gt;❷ Image segmentation based on color features to separate the package region from the background. The shape characteristics of the package are calculated from the edge features of the segmented region;&lt;/p&gt;

&lt;p&gt;❸ Within the package area in the image, connected component analysis combined with the label's color and rectangular shape features is used to locate the shipping label. After excluding the label region, the remaining package area is analyzed to determine the package's color characteristics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Barcode Recognition&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Four cameras simultaneously capture images of the package across its horizontal surface. The number of camera captures is determined based on the previously obtained shape characteristics, ensuring that every longitudinal section of the package surface is imaged.&lt;/p&gt;

&lt;p&gt;The barcode recognition algorithm includes:&lt;/p&gt;

&lt;p&gt;❶ Noise reduction on the captured images;&lt;/p&gt;

&lt;p&gt;❷ Detection of barcode presence in the processed image;&lt;/p&gt;

&lt;p&gt;❸ Precise localization and decoding of barcode regions, with results sent to the host computer interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Technologies of Fixed-Mount Imaging Smart Cameras – Key Features:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Core Module Based on TI AM5728 Multi-Core Heterogeneous Processor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Dual ARM Cortex-A15 + Dual C66x VLIW Floating-Point DSP C66X Heterogeneous Hybrid Processor&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;➢ Features 2x Cortex-A15 @ 1.5GHz, 2x C66x DSP @ 750MHz, 2x Cortex-M4, and 2x PRU&lt;/p&gt;

&lt;p&gt;➢ Uses industrial-grade precision BTB connectors to ensure signal integrity, enabling stable, reliable, and easy installation/removal&lt;/p&gt;

&lt;p&gt;➢ Supports up to 6 video inputs and 3 video outputs&lt;/p&gt;

&lt;p&gt;➢ Supports up to 8 McASP interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 2 CAN interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 10 UARTs&lt;/p&gt;

&lt;p&gt;➢ Supports up to 3 LCD interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 4 SPI interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 3 MMC interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 5 I2C interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports up to 2 Gigabit Ethernet ports&lt;/p&gt;

&lt;p&gt;➢ Supports 1 SATA-2 interface&lt;/p&gt;

&lt;p&gt;➢ Supports 1 USB 3.0 interface&lt;/p&gt;

&lt;p&gt;➢ Supports 2 USB 2.0 interfaces&lt;/p&gt;

&lt;p&gt;➢ Supports 1 HDMI interface&lt;/p&gt;

&lt;p&gt;➢ Supports 1 PCIe 3.0 interface, configurable in 1×2-lane or 2×1-lane mode&lt;/p&gt;

&lt;p&gt;➢ Supports Linux 4.14.67, DSP RTOS, and real-time RT-Linux systems&lt;/p&gt;

&lt;p&gt;➢ Operating temperature range: -40°C to +85°C (industrial grade)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Multi-Core Heterogeneous Development Platform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Provides command-line and Qt-based development examples, along with OpenCV, OpenCL, and OpenGL development guides. Also includes environment setup and development tutorials for DSP and PRU.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. High-Performance DSP&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Sienovo AM5728 development board integrates a real-time C66x digital signal processor (DSP) running at 750MHz, widely used in audio processing, video processing, and complex data algorithm applications. Sienovo provides an OpenCV vision library that includes reference demos combining OpenCV with DSP for edge detection, face recognition, and integration with OpenCL and OpenGL, enabling rapid customer development.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. PRU Programmable Real-Time Unit&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Equipped with two dual-core PRU-ICSS modules supporting industrial protocols such as EtherCAT, EtherNet/IP, POWERLINK, PROFIBUS, PROFINET RT/IRT, and SERCOS III. These enable real-time fieldbus communication and provide developers with ultra-low latency and real-time control capabilities essential for industrial applications, with timing precision down to the nanosecond level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Rich Multimedia Capabilities&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Integrated SGX5443-D and GC320 2D graphics accelerators support advanced graphical user interfaces. The Cortex-M4 IPU2 graphics processing unit is dedicated to IVA hardware video encoding/decoding, supporting hardware decoding of multiple formats including H.264 and MPEG-4. It enables simultaneous multi-channel video decoding at up to 1080p 60fps. Supports MJPEG hardware encoding/decoding. The VPE supports hardware-based image and video scaling and color space conversion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Extensive Communication Interfaces&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;■ Dual Gigabit Ethernet interfaces supporting Ethernet/IP and PROFINET protocols;&lt;/p&gt;

&lt;p&gt;■ RS232/RS485 bus support for connection to PLCs, computers, and other systems;&lt;/p&gt;

&lt;p&gt;■ Onboard WiFi &amp;amp; Bluetooth combo module and 4G communication support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Achieved Technical Performance Metrics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In logistics applications, barcodes on shipping documents must be scanned at multiple stages—from pickup to sorting centers, and from sorting centers to final delivery.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The barcode reader described in this article eliminates manual operation by being mounted as a fixed station on automated conveyor lines, enabling automatic barcode localization and decoding.&lt;/strong&gt; &lt;strong&gt;Based on fixed-mount imaging smart cameras, this system significantly improves both efficiency and accuracy throughout the entire logistics process.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reference solution: Sienovo's XM5728-IDK-V3 development board.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ix0np9gmr34gid7hfb2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ix0np9gmr34gid7hfb2.png" width="800" height="535"&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jqi5m7s5avrac69ar72.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0jqi5m7s5avrac69ar72.jpeg" alt="[Sharing] Disassembly and Analysis of Amazon AGV Kiva Robot" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;System Architecture and Mechanical Structure&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From the outside, each side of the Kiva robot's housing features an &lt;strong&gt;&lt;em&gt;infrared sensor array and a pneumatic bumper for collision detection and cushioning.&lt;/em&gt;&lt;/strong&gt; The housing also includes a charging port and a series of status indicator lights.&lt;/p&gt;

&lt;p&gt;Each Kiva robot has three independent degrees of freedom: &lt;strong&gt;&lt;em&gt;two drive wheels and one rotating lift motor.&lt;/em&gt;&lt;/strong&gt; When the lift motor operates, the two drive wheels rotate in opposite directions, resulting in the platform rising along the ball screw without rotating relative to the ground. Compared to traditional high-load linear actuation methods such as hydraulic or scissor lifts, Kiva's wheel-based lifting mechanism is clearly simpler and more reliable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfmen7hahtoqtqcej2wm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frfmen7hahtoqtqcej2wm.jpeg" width="307" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The top of the lift platform consists of robust X-shaped aluminum castings made from 319-grade general-purpose aluminum. Each casting undergoes secondary precision machining to create reference surfaces and threaded holes. This manufacturing process is commonly used in equipment such as automotive engines and hydraulic pumps.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6fb9hosjpt1v1p22pvc.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx6fb9hosjpt1v1p22pvc.jpeg" width="309" height="148"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Left: Internal structure of Kiva with housing removed, showing the &lt;strong&gt;infrared array, wireless module, lifting mechanism, and lift motor&lt;/strong&gt;. Right: Top view of Kiva, showing the lifting mechanism and battery.&lt;/p&gt;

&lt;p&gt;Each infrared sensor has its own dedicated filtering chip and communicates via a serial bus. In the image, you can see the motor and large gear used in the lifting module. Near the bottom of the robot, &lt;strong&gt;&lt;em&gt;four lead-acid batteries&lt;/em&gt;&lt;/strong&gt; are installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Housing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The orange, streamlined &lt;strong&gt;&lt;em&gt;plastic housing is vacuum-formed from ABS material&lt;/em&gt;&lt;/strong&gt; and includes numerous secondary machined features. The vacuum-forming machine and CNC milling tools used to manufacture Kiva were likely large and expensive. This version of the Kiva housing is both complex and costly; future versions are expected to adopt fully injection-molded structures.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpqsxzbzt5hkzyxekrc5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqpqsxzbzt5hkzyxekrc5.jpeg" width="303" height="169"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Collision Sensors&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For a large, streamlined housing like Kiva's, implementing a traditional integrated collision sensor is extremely difficult. Kiva engineers devised a clever, low-cost solution: &lt;strong&gt;inflating ethylene/rubber tubes and using a simple pressure sensor. Any change in internal pressure immediately triggers the robot to stop all motion.&lt;/strong&gt; The black box on the right side of the image processes pressure signals and all infrared sensor data, simplifying communication protocols and wiring with the main controller.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qnudhmjprlyd7yrt6ak.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0qnudhmjprlyd7yrt6ak.jpeg" width="303" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lifting Mechanism&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Gearbox, lift motor, and large-diameter ball screw. The lifting mechanism uses a custom ball screw connected to the motor via a standard &lt;strong&gt;&lt;em&gt;nylon gear.&lt;/em&gt;&lt;/strong&gt; The same Pittman motor used for lifting is also used for the two drive wheels, capable of delivering approximately 3 N·m of torque and 1 kW of stall power. The motor output shaft connects to a 25:1 Japanese Brother gearbox, producing 46 N·m of torque at 72 rpm. This gearbox costs around $1,000 per unit, though bulk purchasing would likely reduce the price significantly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jt5kf47fn4qmghvbpai.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jt5kf47fn4qmghvbpai.jpeg" width="299" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Chassis and Drive Wheels&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;After removing the lifting mechanism, flipping the robot reveals the drive components on the underside. The two drive motors and gearboxes are identical to the lift motor setup. Two custom wheels form a differential drive system capable of in-place rotation.&lt;/p&gt;

&lt;p&gt;Three sand-cast aluminum components make up most of the robot's chassis. They are connected with simple U-shaped pin clamps, forming a passive dual suspension system. These aluminum parts are also made from 319 alloy and use a casting followed by precision machining process. Note the machined heat dissipation structures on the chassis, on the back of which are mounted the large MOSFETs of the motor drivers. This design naturally uses the chassis for maximum heat dissipation efficiency.&lt;/p&gt;

&lt;p&gt;U-shaped pin clamps connecting the suspension, and heat sinks on the chassis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnzj9yd6puwjy5x22odb.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxnzj9yd6puwjy5x22odb.jpeg" width="303" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Electronics&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Designing reliable electronics capable of powering Kiva's three high-power motors and numerous sensors over long periods is a critical challenge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jt5kf47fn4qmghvbpai.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7jt5kf47fn4qmghvbpai.jpeg" width="299" height="121"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Battery Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Battery wiring harness and charging port (top and side views). The entire system is powered by &lt;strong&gt;&lt;em&gt;four series-connected 12V, 28Ah lead-acid batteries.&lt;/em&gt;&lt;/strong&gt; Two of the four batteries are equipped with thermocouples to prevent overheating. When battery levels are low, the robot automatically disengages from central controller commands and returns to the charging station. The charging station is designed with ample clearance to ensure reliable charging.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64b3qnns3epqbel7tlbm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64b3qnns3epqbel7tlbm.jpeg" width="296" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cameras and Imaging Module&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Upward- and downward-facing cameras, both mounted inside the ball screw assembly. Located within the lifting mechanism is one of the key components of the Kiva system: a &lt;strong&gt;&lt;em&gt;custom dual-camera imaging module.&lt;/em&gt;&lt;/strong&gt; &lt;strong&gt;&lt;em&gt;One camera looks downward to identify 2D barcodes on the warehouse floor, while the other looks upward at the underside of shelves.&lt;/em&gt;&lt;/strong&gt; Each camera is equipped with six red LEDs for illumination. Sandwiched between the two cameras is the image processing module, centered around an ADI ADSP-BF548 Blackfin multimedia processor that acquires data via high-speed serial interface and performs data matrix detection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mainboard and Subboards&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faapoqtmphfyyop5uq27x.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faapoqtmphfyyop5uq27x.jpeg" width="301" height="112"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main logic module shown above orchestrates all operations. The motor driver board is powered by 48V DC from the battery; logic components are powered by a separate filtered power rail. The three-phase brushless DC (BLDC) motor drivers are fully custom, driven by a Lattice LFXP6C FPGA (hidden beneath the mainboard).&lt;/p&gt;

&lt;p&gt;All three motor drivers include current sensors (suggesting FOC control), encoders, and six full-bridge MOSFETs (cooled via the chassis). A subboard hosting the FPGA handles coordination of the wireless module, imaging unit, emergency braking, infrared/pressure sensors, power management, and motor drivers, significantly reducing the load on the mainboard. The MCU is a 32-bit, 400MHz Freescale MPC5123, likely running PowerPC Linux. Two Ethernet ports connect to the wireless module and firmware storage via a Microchip KSZ8993 switch. The only off-the-shelf electronic component in the entire robot is the communication module: a Soekris Engineering Net4526 dual-antenna router running a single Winstron NeWeb CM9 wireless module, connected to the mainboard via Ethernet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdz0f7l2s2eng6fi4do0.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdz0f7l2s2eng6fi4do0.jpeg" width="304" height="101"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The remarkable lifting module&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3q2ncggr1k6atik3tg1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3q2ncggr1k6atik3tg1.jpeg" width="293" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This generation of Kiva robots features many clever design elements, but the standout is undoubtedly the lifting module. It must raise and lower loads up to 1,000 pounds (about half a ton) while maintaining perfect parallelism with the ground—ideally suited for a ball screw mechanism. Typically, commercial ball screws are solid and rarely exceed five centimeters in diameter. Kiva's custom version, however, has an outer diameter of 28 centimeters and is hollow with internal threading. The two housing bearings are aluminum, cast and then precision-machined like the chassis components. Both parts are surface-oxidized, providing excellent lubrication and corrosion resistance. The inner housing is fixed, acting as a ball nut, with an overmolded ring structure to constrain the balls. The outer housing rotates, with its inner surface contacting the balls and its outer surface connected to the lift motor via gears.&lt;/p&gt;

&lt;p&gt;Considering manufacturing complexity, the entire lifting mechanism is estimated to cost around $1,000.&lt;/p&gt;

&lt;h2&gt;
  
  
  Kiva Systems is one of the few companies capable of seamlessly integrating sophisticated hardware and software into a unified solution, having built a system that profoundly transforms how we buy, sell, and live. Clearly, Kiva employs a team of exceptionally skilled hardware engineers—likely a major reason why Amazon acquired the company in 2012 for a staggering $775 million. This article only discusses the robot itself, but it's important to note that this is just a small (albeit impressive) part of the entire Kiva solution.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/106390114" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/106390114" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>am5728</category>
      <category>logisticsrobot</category>
      <category>dsparm</category>
      <category>imagerecognition</category>
    </item>
    <item>
      <title>Domestic Virtual Instruments: Zynq-based Radar 10Gbps High-Speed PCIe Data Acquisition Card Solution (Part 2) Hardware Design</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Sat, 23 May 2026 06:52:33 +0000</pubDate>
      <link>https://dev.to/sienovoleo/domestic-virtual-instruments-zynq-based-radar-10gbps-high-speed-pcie-data-acquisition-card-44be</link>
      <guid>https://dev.to/sienovoleo/domestic-virtual-instruments-zynq-based-radar-10gbps-high-speed-pcie-data-acquisition-card-44be</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;This article details the hardware design of a Zynq-based 10 Gbps PCIe radar data acquisition card, covering chip selection, power architecture, clock distribution, high-speed interfaces, DDR3 memory, and the design of both the ADC daughter card and fiber-optic daughter card. Engineers working on FPGA-based data acquisition systems will find a practical reference for how to partition carrier-board and daughter-card responsibilities, select appropriate power management ICs, and configure the Xilinx Zynq-7100 SoC for high-throughput signal capture.&lt;/p&gt;

&lt;h2&gt;
  
  
  3.1 Introduction
&lt;/h2&gt;

&lt;p&gt;The hardware design of the acquisition card is the foundation for realizing its capture functions. A well-conceived hardware design makes the acquisition feature easier to implement and streamlines subsequent software development. This chapter builds on the hardware architecture described in Chapter 2 and provides a detailed walkthrough of chip selection, configuration, and specific circuit design for both the carrier board and the daughter cards. The overall block diagram for the carrier board and daughter cards is shown in Figure 3.1.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgixla012dnp6filhga10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgixla012dnp6filhga10.png" alt="Overall hardware design block diagram" width="718" height="621"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  3.2 Carrier Board Hardware Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.2.1 Main Control Chip Selection and Configuration Circuit
&lt;/h3&gt;

&lt;h4&gt;
  
  
  (1) Chip Selection and Analysis
&lt;/h4&gt;

&lt;p&gt;Based on the hardware design analysis from Chapter 2, the main control chip must satisfy the following requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;At least 12 pairs of high-speed GTX transceivers — 4 pairs for fiber optic links and 8 pairs for PCIe.&lt;/li&gt;
&lt;li&gt;Sufficient on-chip BRAM resources to implement FIFO buffering at the data interfaces.&lt;/li&gt;
&lt;li&gt;Native support for the Aurora serial protocol and PCIe 2.0.&lt;/li&gt;
&lt;li&gt;General-purpose peripheral interfaces (Ethernet, SPI, UART, CAN) for ease of debugging and porting.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Considering all of these constraints, the design selects a chip from the &lt;strong&gt;Xilinx Zynq-7000 SoC&lt;/strong&gt; family. The Zynq-7000 series integrates a dual-core ARM Cortex-A9 processing system (PS) with a Xilinx Kintex-7 FPGA programmable logic (PL) fabric on the same die, giving both hard-processor control and high-speed programmable I/O in one package. After comparing the resource tables for the product family (Table 3.1), any device at the Zynq-7135 or below can meet the design's requirements. The final selection is &lt;strong&gt;XC7Z100FFG900-2&lt;/strong&gt; from the Zynq-7100 sub-family.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewr33u5k7i9l0vxab8ck.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fewr33u5k7i9l0vxab8ck.png" alt="Zynq-7000 product family and PL resources" width="800" height="304"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The XC7Z100FFG900-2 IOBANK layout (Figure 3.2) is organized as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bank 9–13, 33–35&lt;/strong&gt; — PL-side general I/O pins.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bank 109–112&lt;/strong&gt; — PL-side high-speed GTX transceivers; each bank provides four pairs of high-speed differential transceivers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bank 500–502&lt;/strong&gt; — PS-side pins, providing standard interfaces such as Gigabit Ethernet, SPI, CAN, and UART.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;White squares in the diagram represent power, ground, or configuration pins.&lt;/p&gt;

&lt;h4&gt;
  
  
  (2) Power Supply Configuration Circuit
&lt;/h4&gt;

&lt;p&gt;The Zynq-7100FFG900 PL and PS sections each require different I/O supply voltages depending on bank type and performance class. PL banks are divided into &lt;strong&gt;HR (High Range)&lt;/strong&gt; and &lt;strong&gt;HP (High Performance)&lt;/strong&gt; categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;HR banks (9–13):&lt;/strong&gt; support I/O voltages from 1.2 V to 3.3 V.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HP banks (33–35):&lt;/strong&gt; support I/O voltages from 1.2 V to 1.8 V only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Beyond I/O voltages, the PL fabric also needs a core supply, an auxiliary supply, a GTX transceiver core supply, and a GTX termination supply. The PS side requires its own internal voltage, auxiliary voltage, and MIO voltage rails. The full supply voltage breakdown is summarized in Table 3.2.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej9z9dnxed2x9lx7vgnt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fej9z9dnxed2x9lx7vgnt.png" alt="Power supply voltage table" width="710" height="583"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  (3) Clock Configuration Circuit
&lt;/h4&gt;

&lt;p&gt;The clock distribution circuit is another critical configuration element in the Zynq-7000 design. All timing and control signals are derived from external clock references; excessive clock jitter or drift degrades overall system performance and can cause the system to stop functioning entirely. Active crystal oscillators are used as clock sources throughout.&lt;/p&gt;

&lt;p&gt;The Zynq-7000 family has three distinct clock domains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;PS clock:&lt;/strong&gt; provided by a 33.333333 MHz active oscillator with a single-ended output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;PL clock:&lt;/strong&gt; provided by a 100 MHz active oscillator with a differential output.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;High-speed GTX clock:&lt;/strong&gt; frequency is protocol- and data-rate-dependent and is generated by a programmable clock chip.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PS and PL clock circuits are shown in Figure 3.3(a) and 3.3(b) respectively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogahggc1u6ksw5qgs2gx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fogahggc1u6ksw5qgs2gx.png" alt="PS and PL clock circuits" width="800" height="294"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because high-speed protocols operate at a variety of line rates, the GTX reference clock frequency must be configurable. This design uses the &lt;strong&gt;TI CDCM61002&lt;/strong&gt; programmable clock IC, which accepts a single-ended input in the range of 21.875–28.57 MHz, locks an internal high-performance VCO running at 1.75–2.05 GHz, and outputs the VCO divided by 1, 2, 3, 4, 6, or 8. It provides two pairs of differential output clocks and supports both LVCMOS and LVDS output levels.&lt;/p&gt;

&lt;p&gt;In this design a 25 MHz reference is fed to the CDCM61002, and DIP switches are used to set the divider ratio by driving the chip's configuration pins to different logic levels. This yields output frequencies spanning &lt;strong&gt;62.5 MHz to 625 MHz&lt;/strong&gt;, which covers the reference clock requirements of most high-speed serial protocols encountered in radar data acquisition.&lt;/p&gt;

&lt;p&gt;The high-speed clock configuration block diagram is shown in Figure 3.4, and the DIP-switch configuration versus output-frequency mapping is listed in Table 3.3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbklhm6enzocn79nimks.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkbklhm6enzocn79nimks.png" alt="High-speed clock configuration block diagram" width="800" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  (4) High-Speed Interface Circuit
&lt;/h4&gt;

&lt;p&gt;The XC7Z100FFG900 provides 16 GTX transceiver pairs in total. This design uses 12 of them: 4 pairs are routed to the FMC connector (bank 110) for the daughter-card optical link, and 8 pairs are routed to the PCIe edge connector (banks 111 and 112).&lt;/p&gt;

&lt;p&gt;The high-speed interface block diagram is shown in Figure 3.5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabf1y3774r2j9s9w8lcl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabf1y3774r2j9s9w8lcl.png" alt="High-speed interface block diagram" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  (5) Peripheral Configuration and Boot Circuit
&lt;/h4&gt;

&lt;p&gt;Like all Xilinx FPGAs and SoCs, the Zynq-7000 is volatile: the PL bitstream and PS software are lost when power is removed. The design therefore provides multiple non-volatile storage options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two QSPI Flash chips&lt;/strong&gt; — Cypress S25FL256S, 256 Mb each, connected to PS bank 500. Maximum read/write clock is 133 MHz.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One SD card interface&lt;/strong&gt; — connected to PS bank 501, used for storing the boot image or OS.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One eMMC device&lt;/strong&gt; — Micron MTFC8GAKAJCN-4M, 8 GB capacity, 50 MHz clock, connected to PL bank 35 and accessed via the EMIO feature.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The QSPI Flash connection block diagram is shown in Figure 3.6, and the eMMC / SD card connection diagram is shown in Figure 3.7.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6cvjfj64s9cl5rdfomi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa6cvjfj64s9cl5rdfomi.png" alt="QSPI Flash connection block diagram" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsio4vwmu54chzse76ryl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsio4vwmu54chzse76ryl.png" alt="eMMC and SD card connection diagram" width="800" height="352"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For remote control and firmware updates over the network, a standard RJ-45 Gigabit Ethernet port is provided. The PHY is the &lt;strong&gt;Marvell 88E1518&lt;/strong&gt;, a tri-speed (10/100/1000 Mbps) Ethernet transceiver connected to PS bank 501. The network port and PHY block diagram is shown in Figure 3.8.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdi6wy50rk2guu3l7f28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpdi6wy50rk2guu3l7f28.png" alt="Ethernet PHY circuit block diagram" width="715" height="441"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2.2 DDR3 SDRAM Selection and Configuration
&lt;/h3&gt;

&lt;p&gt;Both the PS and PL domains require external DDR3 SDRAM. The PS-side DRAM provides a working memory region during boot and OS operation, while the PL-side DRAM serves as the high-bandwidth data cache for buffering incoming high-speed acquisition data before it is transferred to the host over PCIe.&lt;/p&gt;

&lt;p&gt;The design uses &lt;strong&gt;Micron MT41K256M16TW-107&lt;/strong&gt; DDR3 SDRAM. Two chips are populated on each of the PS and PL sides, giving a 32-bit data bus width per domain (2 × 16-bit devices) and a total capacity of &lt;strong&gt;1 GB per domain&lt;/strong&gt;. Key performance figures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PS-side DDR3: up to &lt;strong&gt;1066 MHz&lt;/strong&gt; operating frequency.&lt;/li&gt;
&lt;li&gt;PL-side DDR3: up to &lt;strong&gt;1600 MHz&lt;/strong&gt; operating frequency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The PL-side DDR3 is connected to HP banks 33 and 34, which offer cleaner power rails and tighter I/O timing margins compared to HR banks — important for extracting maximum DDR3 performance. The PS-side DDR3 connects to the dedicated memory interface bank 502. The DDR3 block diagrams for both domains are shown in Figure 3.9.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujz3hbzbsmewnwu1ppzr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fujz3hbzbsmewnwu1ppzr.png" alt="DDR3 SDRAM block diagram" width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2.3 High-Speed Interface Circuit
&lt;/h3&gt;

&lt;p&gt;The carrier board provides two classes of high-speed interfaces: &lt;strong&gt;FMC&lt;/strong&gt; and &lt;strong&gt;PCIe&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;As a general PCB layout rule, 0.1 µF AC-coupling capacitors are placed at every high-speed differential signal pin to block DC offsets. Differential pairs within a single channel are routed as tightly coupled, parallel traces on the same layer to minimize impedance discontinuities, and vias between layers are kept to a minimum. Across multiple channels, all differential pairs are length-matched to ensure phase-aligned, synchronous data reception.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FMC (FPGA Mezzanine Card)&lt;/strong&gt; is the VITA 57.1 standard interconnect between a carrier board and a daughter card. The daughter card typically carries the male connector and the carrier board the female connector. FMC supports transfer rates up to 10 Gbps per lane, with a theoretical aggregate throughput approaching 40 Gbps. Two variants exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;LPC (Low Pin Count):&lt;/strong&gt; 160-pin connector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HPC (High Pin Count):&lt;/strong&gt; 400-pin connector, used here because it provides the required number of GTX transceiver lanes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition to the high-speed data lanes, the FMC connector also carries a JTAG chain, an I²C management bus, and dedicated power pins that allow the carrier board to supply the daughter card directly. This decouples the daughter-card logic design from the carrier board's general-purpose FPGA I/O pin constraints and makes the daughter-card design more portable.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;PCIe&lt;/strong&gt; interface (Figure 3.10) uses a gold-finger edge connector that plugs directly into a host PC motherboard slot. RXD pins receive data from the host; TXD pins transmit to the host. AC-coupling capacitors (0.1 µF) are required on the TXD differential lines. The PCIe lane width is selectable — X1, X2, or X8 — by connecting the appropriate &lt;code&gt;PRSNT_xx&lt;/code&gt; pin to &lt;code&gt;PCIE_PG&lt;/code&gt;. This design implements &lt;strong&gt;PCIe X8&lt;/strong&gt; mode, requiring &lt;code&gt;PRSNT_x8&lt;/code&gt; to be tied to &lt;code&gt;PRSNT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F755tp3m2se4s000kn0ne.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F755tp3m2se4s000kn0ne.png" alt="PCIe interface schematic" width="800" height="642"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3.2.4 Power Circuit
&lt;/h3&gt;

&lt;p&gt;A well-designed power delivery network is critical: excessive output ripple causes instability, performance degradation, and can permanently damage components. The PC motherboard supplies the PCIe slot at &lt;strong&gt;12 V&lt;/strong&gt;, so the acquisition card's primary input is 12 V DC, which is then down-converted by on-board power management ICs to supply each subsystem at its required voltage.&lt;/p&gt;

&lt;p&gt;Power management ICs must not be operated at or beyond their rated output current, since that leads to voltage droop and thermal runaway. The Zynq-7000 is a low-power SoC; its combined PS + PL current draw in this application is within a few amperes, which is well within the budget of the chosen regulators.&lt;/p&gt;

&lt;p&gt;The design uses a &lt;strong&gt;core board + baseboard&lt;/strong&gt; split. The main control chip sits on the core board. Performing all power conversion on the baseboard would complicate the baseboard layout and tightly couple the core board to a single baseboard design. Instead, the 12 V rail is brought onto the core board and converted there — making the core board self-contained and reusable with other baseboards.&lt;/p&gt;

&lt;p&gt;The baseboard still needs modest power conversion for its own peripherals (USB, Ethernet PHY, FMC power delivery). That conversion is handled by a &lt;strong&gt;TI DC/DC converter&lt;/strong&gt; with an input range of up to 18 V and a programmable output range up to 7 V, rated for up to 3 A output — sufficient for the baseboard's peripheral load. The baseboard power block diagram is shown in Figure 3.11.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dlez1vtte7knzxtkedy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9dlez1vtte7knzxtkedy.png" alt="Baseboard power block diagram" width="690" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The core board requires multiple supply voltages — 0.75 V, 1.0 V, 1.5 V, 1.8 V, 2.0 V, 3.3 V, and 5.0 V — for the Zynq SoC, DDR3 SDRAM termination and core, and other peripherals. The full core-board power conversion tree is shown in Figure 3.12.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizj0f71vvs6qhgjj09bo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fizj0f71vvs6qhgjj09bo.png" alt="Core board power conversion tree" width="674" height="549"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Key power IC choices on the core board:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;12 V → 1 V (Zynq PL core):&lt;/strong&gt; TI &lt;strong&gt;TPS53355&lt;/strong&gt;. Conversion input range 1.5–15 V; bias supply input range 4.5–25 V; adjustable output down to a fraction of a volt; maximum output current 30 A.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;12 V → intermediate rail:&lt;/strong&gt; TI DC/DC converter with 6 A output capability and output adjustable from 0.76 V upward.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;5 V → lower voltages (1.5 V, 1.8 V, etc.):&lt;/strong&gt; MPS &lt;strong&gt;MP2143&lt;/strong&gt;, input range 2.5–5.5 V, output range 0.6 V to Vin − 0.5 V, 3 A output capability.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All selected ICs were verified to meet the actual load current demands with margin, ensuring stable operation across the full operating range.&lt;/p&gt;




&lt;h2&gt;
  
  
  3.3 Daughter Card Circuit Design
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.3.1 AD Daughter Card Circuit Design
&lt;/h3&gt;

&lt;p&gt;The ADC daughter card performs analog-to-digital conversion of the incoming radar IF/baseband signal and delivers the digitized samples to the Zynq chip over the FMC interface.&lt;/p&gt;

&lt;p&gt;The ADC is the &lt;strong&gt;TI ADC12D800&lt;/strong&gt;, a dual-channel, 12-bit converter with a maximum sample rate of &lt;strong&gt;1.6 GSPS&lt;/strong&gt; (interleaved). Its output can be configured either as 12 differential output pairs or as parallel data lines. The two independent channels are designated &lt;strong&gt;I&lt;/strong&gt; and &lt;strong&gt;Q&lt;/strong&gt;, each with its own dedicated data bus, supporting both single-edge (SDR) and double-edge (DDR) clocking modes. The ADC's clock and control interface signals are summarized in Table 3.5.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf0t3t0lagyo5mznfum8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsf0t3t0lagyo5mznfum8.png" alt="ADC clock and control interface table" width="800" height="344"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The ADC12D800 also provides an SPI interface for extended control mode, enabling software configuration of offset trim, calibration, and other parameters. This design does not use the SPI configuration path, so that interface is not discussed further here.&lt;/p&gt;

&lt;p&gt;The analog input is AC-coupled — the incoming RF/IF signal enters through an &lt;strong&gt;SMB coaxial connector&lt;/strong&gt;, passes through the matching and balun network, and is converted to a differential signal pair before entering the ADC's differential input pins. The input circuit is shown in Figure 3.13.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxemtrxud3i444vg6s7d5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxemtrxud3i444vg6s7d5.png" alt="ADC analog input circuit" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The ADC12D800's maximum operating voltage is 2.2 V. This design powers it at &lt;strong&gt;1.9 V&lt;/strong&gt;, derived from the 3.3 V supply available on the FMC connector using a &lt;strong&gt;TI LP38503-ADJ&lt;/strong&gt; LDO regulator (input range 2.7 V to 6 V, output range adjustable up to 5.0 V, maximum output current sufficient for the ADC load).&lt;/p&gt;

&lt;p&gt;All ADC control lines and data lines are brought out to the FMC connector, with equal-length routing enforced on the data bus to satisfy timing closure for synchronous parallel capture. The complete AD daughter card block diagram is shown in Figure 3.14.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33k9kw362c50ehfi7dra.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F33k9kw362c50ehfi7dra.png" alt="AD daughter card block diagram" width="799" height="510"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  3.3.2 Fiber-Optic Daughter Card Circuit Design
&lt;/h3&gt;

&lt;p&gt;The fiber-optic daughter card provides the physical-layer bridge between the optical fiber link and the FMC connector on the carrier board. Its primary component is a &lt;strong&gt;QSFP (Quad Small Form-factor Pluggable)&lt;/strong&gt; connector (part number 1761987-9), which exposes 4 high-speed differential transceiver lanes in a compact, hot-pluggable package well-suited for multi-lane fiber-optic links.&lt;/p&gt;

&lt;p&gt;The optical transceiver module used is an &lt;strong&gt;SR4-40G&lt;/strong&gt; QSFP+ module, offering an aggregate line rate of &lt;strong&gt;40 Gbps&lt;/strong&gt; (4 × 10 Gbps) over multi-mode fiber with a reach of up to &lt;strong&gt;150 m&lt;/strong&gt;. The QSFP cage requires a 3.3 V supply, which is drawn directly from the FMC power pins provided by the carrier board. The four high-speed differential pairs from the QSFP connector are routed directly to the FMC HPC connector, where they connect to the GTX transceiver lanes in bank 110 of the Zynq-7100.&lt;/p&gt;

&lt;p&gt;This passthrough architecture keeps the fiber daughter card simple: it performs no signal conditioning beyond the optical-to-electrical conversion inside the QSFP module, and the Aurora protocol framing and 8b/10b encoding are handled entirely within the Zynq PL fabric. Equal-length routing and controlled-impedance traces are used on the high-speed differential lines between the QSFP cage and the FMC connector to preserve signal integrity at 10 Gbps per lane.&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The hardware design presented in this chapter covers every major subsystem of the Zynq-based 10 Gbps PCIe acquisition card:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Subsystem&lt;/th&gt;
&lt;th&gt;Key Choice&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Main control SoC&lt;/td&gt;
&lt;td&gt;XC7Z100FFG900-2 (Zynq-7100, dual Cortex-A9 + Kintex-7 PL)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GTX transceivers used&lt;/td&gt;
&lt;td&gt;12 of 16 pairs (4 FMC / 8 PCIe)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PS DDR3&lt;/td&gt;
&lt;td&gt;2 × Micron MT41K256M16TW-107, 32-bit / 1 GB, 1066 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PL DDR3&lt;/td&gt;
&lt;td&gt;2 × Micron MT41K256M16TW-107, 32-bit / 1 GB, 1600 MHz&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GTX reference clock&lt;/td&gt;
&lt;td&gt;TI CDCM61002, 62.5–625 MHz DIP-selectable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Non-volatile storage&lt;/td&gt;
&lt;td&gt;2 × Cypress S25FL256S QSPI Flash + SD card + 8 GB eMMC&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ethernet PHY&lt;/td&gt;
&lt;td&gt;Marvell 88E1518 (10/100/1000 Mbps)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ADC daughter card&lt;/td&gt;
&lt;td&gt;TI ADC12D800, 12-bit, 1.6 GSPS, dual I/Q channels&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fiber daughter card&lt;/td&gt;
&lt;td&gt;QSFP SR4-40G, 40 Gbps aggregate over 150 m MMF&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary power input&lt;/td&gt;
&lt;td&gt;12 V DC (from PCIe slot), down-converted on core board&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  The carrier-board / daughter-card split via the FMC HPC connector gives this platform its modularity: the same Zynq carrier can be paired with different signal-conditioning daughter cards (ADC, fiber, DA, etc.) simply by swapping the mezzanine module, while the Zynq PL firmware adapts to the new interface. This approach is characteristic of the VITA 57.1 ecosystem and substantially reduces the NRE cost of iterating on front-end hardware.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/130781818" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/130781818" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fpgadev</category>
      <category>domesticvirtualinstrument</category>
    </item>
    <item>
      <title>STM32 ARM+FPGA Servo Control System (Part Two) Software and FPGA Design</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Sat, 23 May 2026 06:52:31 +0000</pubDate>
      <link>https://dev.to/sienovoleo/stm32-armfpga-servo-control-system-part-two-software-and-fpga-design-55jk</link>
      <guid>https://dev.to/sienovoleo/stm32-armfpga-servo-control-system-part-two-software-and-fpga-design-55jk</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;A complete servo system involves numerous modules, making it impractical to detail each one. This article focuses on the more challenging FPGA implementation, providing a brief overview of the ARM-side workflow. The FPGA is central to the control system, handling critical functions like the Field-Oriented Control (FOC) algorithm, current sampling, and encoder sampling. The performance of these FPGA-based algorithms directly dictates the quality of motor control. Due to the inherent parallelism and real-time constraints of FPGA operation, careful consideration of design timing and the coordinated scheduling of various tasks is paramount, significantly increasing design complexity. Below, we will delve into the design specifics of key FPGA program parts, primarily covering the Space Vector Pulse Width Modulation (SVPWM) algorithm module, the BISS-C encoder feedback module, and the Tamagawa encoder feedback module.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.1 SVPWM Algorithm Program Design
&lt;/h2&gt;

&lt;p&gt;As established in prior discussions, the SVPWM algorithm's workflow is a sequential process designed to generate the precise voltage required for motor control. This process begins by decoding the stationary frame voltage components, U_alpha and U_beta, to accurately determine the current sector of the voltage vector. Following sector identification, the system calculates the active time required for the basic voltage vectors within that specific sector. The next step involves determining the precise time points for PWM comparison. Finally, pulse width modulation is performed, incorporating a crucial dead-time to generate complementary PWM waves. These waves then control the inverter switches, ultimately producing the desired sinusoidal voltage waveform for the motor.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1.1 Software Module Design
&lt;/h3&gt;

&lt;p&gt;The SVPWM module's functional structure is designed to manage the generation of these control signals. The module interacts with several key signals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;sys_clk&lt;/strong&gt;: The system clock, operating at a frequency of 50MHz, provides the timing backbone for all operations.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;sys_rst&lt;/strong&gt;: The system reset signal, which is active low, initializes the module to a known state.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;svpwm_en&lt;/strong&gt;: The module enable signal, which activates or deactivates the SVPWM generation process.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;ualpha, ubeta&lt;/strong&gt;: These are the output signals from the inverse Park transformation module, representing the voltage components in the stationary reference frame.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;Other&lt;/strong&gt;: This refers to the six complementary PWM waves (three pairs) that drive the inverter's power switches.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The underlying principles and computational formulas for this module are detailed in Chapter 2 and will not be reiterated here. However, a critical design consideration is the generation of complementary PWM waves with a precisely defined dead-time. This dead-time is essential to account for the mechanical switching delays inherent in the inverter's power devices (e.g., MOSFETs or IGBTs). Without adequate dead-time, there is a risk of simultaneously turning on both the upper and lower switches of an inverter leg, leading to a direct short circuit across the DC bus, which can damage the inverter and pose a safety hazard.&lt;/p&gt;

&lt;p&gt;The principle for generating complementary PWM waves with dead-time involves using the calculated PWM wave as a reference. A suitable dead-time is then configured based on the specific characteristics of the inverter hardware. Assuming the inverter input signal is active high:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  When the reference PWM signal transitions from low to high (indicating the upper switch should turn on), the lower switch is first commanded to turn off. After a delay equal to the defined dead-time, the upper switch is then commanded to turn on.&lt;/li&gt;
&lt;li&gt;  Conversely, when the reference PWM signal transitions from high to low (indicating the upper switch should turn off), the upper switch is first commanded to turn off. After a delay equal to the defined dead-time, the lower switch is then commanded to turn on.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This mechanism ensures that there is a brief period where both switches in a leg are off, preventing shoot-through. For example, considering the U-phase, if &lt;code&gt;u_pwm&lt;/code&gt; is the calculated reference PWM wave, &lt;code&gt;u_pwm1&lt;/code&gt; would be the PWM wave for the upper switch, and &lt;code&gt;u_pwm2&lt;/code&gt; for the lower switch. The dead-time would be visible as a short delay between &lt;code&gt;u_pwm1&lt;/code&gt; turning off and &lt;code&gt;u_pwm2&lt;/code&gt; turning on, and vice-versa.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.1.2 Simulation Test
&lt;/h3&gt;

&lt;p&gt;To validate the functionality of the SVPWM module, a simulation was conducted. The simulation results demonstrated that by assigning arbitrary values to &lt;code&gt;u_alpha&lt;/code&gt; and &lt;code&gt;u_beta&lt;/code&gt;, and then generating a single clock cycle &lt;code&gt;svpwm_en&lt;/code&gt; signal, the system correctly produced &lt;code&gt;u_pwm&lt;/code&gt; as the reference PWM wave. Crucially, based on this &lt;code&gt;u_pwm&lt;/code&gt; signal, the module successfully generated the complementary PWM waves, &lt;code&gt;u_pwm1&lt;/code&gt; and &lt;code&gt;u_pwm2&lt;/code&gt;, with the expected dead-time clearly visible between them. This simulation confirmed that the SVPWM module is capable of generating the required complementary PWM waves with dead-time, ensuring safe and effective inverter operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.2 BISS-C Protocol Program Design
&lt;/h2&gt;

&lt;p&gt;The BISS (Bi-directional Synchronous Serial) protocol, developed by iC-Haus, is a robust bi-directional serial interface specifically designed for sensors. It incorporates CRC (Cyclic Redundancy Check) functionality to ensure the integrity and correctness of transmitted data. Compared to other similar communication protocols, BISS offers significant advantages in terms of compatibility and network structure. It achieves high speeds and low latency, comparable to SSI (Synchronous Serial Interface), with communication rates reaching up to 10Mbps. Furthermore, the BISS protocol allows for flexible adjustment of data length according to specific application requirements, providing excellent scalability.&lt;/p&gt;

&lt;p&gt;BISS protocol supports two operating modes. The design discussed here utilizes the sensor mode, where the FPGA acts as the master, sending position request commands to the encoder, and the encoder (slave) responds with relevant information. In sensor mode, the BISS-C data format is structured as a series of bits transmitted over the SLO (Slave Output) data line, synchronized by the MA (Master) clock signal generated by the host.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2.1 BISS-C Protocol Data Structure
&lt;/h3&gt;

&lt;p&gt;A BISS-C data frame is composed of eight distinct parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Ack (Acknowledgement) Phase&lt;/strong&gt;: The encoder signals its readiness.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start Bit&lt;/strong&gt;: A single bit indicating the start of data transmission.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;One '0' Bit&lt;/strong&gt;: A fixed zero bit following the start bit.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Position Data&lt;/strong&gt;: A variable number of bits representing the encoder's absolute position.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Error Bit&lt;/strong&gt;: A single bit indicating an error condition in the encoder.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Warning Bit&lt;/strong&gt;: A single bit indicating a warning condition in the encoder.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;CRC Check Code&lt;/strong&gt;: A six-bit CRC checksum for data integrity verification.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Timeout Phase&lt;/strong&gt;: The concluding phase of the communication cycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The communication request cycle proceeds as follows:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Idle State&lt;/strong&gt;: When no position request is active, the MA clock signal is held high. The host monitors the encoder's SLO data line. If SLO is high, it indicates the encoder is ready for communication.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Start MA Clock&lt;/strong&gt;: Once the encoder is ready, the host begins transmitting a fixed-frequency MA clock signal to the encoder.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Encoder Acknowledgment&lt;/strong&gt;: Upon detecting the second rising edge of the MA clock signal from the host, the encoder responds by pulling its SLO line low.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Host Switches to Receive&lt;/strong&gt;: The encoder pulling the SLO line low signals to the host that the encoder is in the Acknowledge (Ack) state. The host should then switch to its receive state.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Data Reception&lt;/strong&gt;: The host synchronously receives data transmitted by the encoder over the SLO line, synchronized with the MA clock signal. The data frame format is Most Significant Bit (MSB) first.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Cycle Completion&lt;/strong&gt;: After receiving all data, the host pulls the MA clock line high. The encoder will then pull its SLO line high to indicate readiness for the next position request. If not ready, it will keep SLO low.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  4.2.2 Software Module Design
&lt;/h3&gt;

&lt;p&gt;The BISS module's functional structure comprises three main sub-modules: the MA module, the SLO module, and the CRC module. Key signals for the BISS module include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;strong&gt;biss_en&lt;/strong&gt;: The module enable signal, used to initiate the process of acquiring encoder position information.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;data_length&lt;/strong&gt;: A configurable parameter that sets the bit width of the encoder's position data.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;SLO&lt;/strong&gt;: The BISS protocol data line, carrying information from the encoder to the FPGA.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;MA&lt;/strong&gt;: The BISS protocol clock line, generated by the FPGA to synchronize communication with the encoder.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;abs_data&lt;/strong&gt;: The single-turn absolute value, used for multi-turn counting in rotary encoders and for electrical angle calculations.&lt;/li&gt;
&lt;li&gt;  &lt;strong&gt;abs_pos&lt;/strong&gt;: The total actual position data from the encoder.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The module operates by first configuring the &lt;code&gt;data_length&lt;/code&gt; register in the FPGA to match the position data bit width of the specific encoder model being used. This design supports position data widths up to 32 bits. When the main control module asserts the &lt;code&gt;biss_en&lt;/code&gt; signal, the MA clock module begins operation, sending a fixed-frequency MA clock signal to the encoder to request its current position value. Upon receiving the data returned by the encoder, the FPGA feeds this data into the CRC verification module for integrity checking. Finally, the validated position data is output to the next stage of the control system.&lt;/p&gt;

&lt;p&gt;To manage the data reception process from the SLO line, a state machine is implemented, dividing the reception into six distinct states based on the BISS protocol's timing diagram characteristics:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Idle State&lt;/strong&gt;: The functional module starts in an idle state.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Wait State&lt;/strong&gt;: It then transitions into a waiting state, monitoring the SLO line.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Ack State&lt;/strong&gt;: When the encoder pulls the SLO signal line low, the state machine enters the Acknowledge (Ack) state.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;STATE_ZERO&lt;/strong&gt;: Upon detecting SLO transitioning from low to high, the state machine moves to STATE_ZERO.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Work State&lt;/strong&gt;: When the SLO data line is detected as low again, the module enters the working state and begins receiving data.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;TIMEOUT State&lt;/strong&gt;: After receiving the configured data width, the module transitions to the "TIMEOUT" state, indicating the end of data reception for the current cycle.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In practical engineering applications, data signal levels can be susceptible to glitches or metastability, especially when sampling on the rising edge of a clock signal. Directly reading the SLO data line's level on the MA clock's rising edge can lead to unreliable data. A more robust approach, implemented here, is to sample the SLO data line multiple times during the stable middle portion of each MA clock cycle. The logic then determines which level (high or low) has a majority count among these samples and assigns that stable value to a register. This method leverages the fact that the MA clock frequency is typically much lower than the internal FPGA operating frequency (&lt;code&gt;sys_clk&lt;/code&gt;), allowing for multiple samples within a single MA clock period. Specifically, at each rising edge of the MA clock, a counter (&lt;code&gt;bps_cnt&lt;/code&gt;) starts from zero, accumulating samples. The system then compares the count of high samples versus low samples, and the majority value is latched into a register. This process repeats until all data bits are received.&lt;/p&gt;

&lt;p&gt;Once the SLO module completes data reception, it sends a "reception complete" signal to both the MA module and the CRC verification module. The MA module, upon receiving this signal, instructs the FPGA to pull the MA clock line high, preparing for the next communication cycle. Simultaneously, the CRC module receives the data frame transmitted by the SLO module and performs the CRC checksum calculation. The BISS-C protocol specifies a CRC polynomial of G(x) = x^6 + x + 1, which corresponds to the binary sequence 1000011. To maximize the parallel processing capabilities of the FPGA and enhance efficiency, a parallel CRC calculation algorithm is employed. This allows the CRC checksum to be computed within a single system clock cycle. The core logic for this parallel CRC operation involves an input &lt;code&gt;d[33:0]&lt;/code&gt; (the data to be checked) and an output &lt;code&gt;crc_out[5:0]&lt;/code&gt; (the calculated CRC result), with an initial &lt;code&gt;c[5:0]&lt;/code&gt; value of zero.&lt;/p&gt;

&lt;p&gt;After calculation, the &lt;code&gt;crc_out&lt;/code&gt; result is compared with the received CRC checksum from the encoder. A crucial detail is that the encoder internally inverts its CRC checksum before transmitting it to the host. Therefore, the FPGA's calculated CRC value must also be inverted before comparison. If the inverted calculated CRC matches the received CRC, it indicates that the SLO module correctly received the data, and the validated position data is then updated in the next-level module. If there is a mismatch, the system retains the previously valid position data and initiates a new position request to the encoder.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.2.3 Simulation Test
&lt;/h3&gt;

&lt;p&gt;A comprehensive test file was developed to verify the BISS module's functionality using ModelSim software, with a strong emphasis on stability for real-world industrial applications. The simulation was conducted at a communication rate of 5Mbps, which is a common high-speed setting. The module was tested against frequently used encoder models with both 26-bit and 32-bit position data widths.&lt;/p&gt;

&lt;p&gt;For the 26-bit data width, two sets of data were configured. The first set intentionally had a single bit difference in the last bit of the CRC checksum, while the second set was entirely correct. This deliberate manipulation allowed for testing whether the BISS module could correctly receive and differentiate between valid and corrupted data, and critically, to verify the proper operation of the CRC verification module. As noted previously, the BISS-C protocol specifies that the encoder inverts its CRC checksum before transmission. Consequently, the CRC values presented in the test data tables were pre-inverted. During the FPGA's verification process, the calculated CRC value must also be inverted before being compared with the received value. The overall simulation results for the 26-bit mode confirmed the module's correct operation.&lt;/p&gt;

&lt;p&gt;The simulation waveforms showed that upon receiving the &lt;code&gt;biss_en&lt;/code&gt; enable signal, the FPGA transmitted a 5MHz MA clock signal to the encoder. The encoder, detecting the MA clock, returned data via the SLO line. Once the FPGA completed data reception, it transferred the received CRC checksum (&lt;code&gt;crc_check&lt;/code&gt;) and the data to be verified (&lt;code&gt;check_data&lt;/code&gt;) to the CRC module, along with a &lt;code&gt;done&lt;/code&gt; signal to trigger the CRC module's operation. The CRC module then processed the data. After processing, it compared its calculated CRC (&lt;code&gt;crc_out&lt;/code&gt;) with the received &lt;code&gt;crc_check&lt;/code&gt;. If they matched (after accounting for the inversion), a high-level pulse on the &lt;code&gt;crc_done&lt;/code&gt; signal indicated successful verification; otherwise, &lt;code&gt;crc_done&lt;/code&gt; remained low.&lt;/p&gt;

&lt;p&gt;A closer examination of the CRC verification details revealed that if the received &lt;code&gt;crc_check&lt;/code&gt; was, for example, &lt;code&gt;001011&lt;/code&gt;, and the calculated &lt;code&gt;crc_out&lt;/code&gt; (before inversion) was &lt;code&gt;110100&lt;/code&gt;, then after inverting &lt;code&gt;crc_out&lt;/code&gt; to &lt;code&gt;001011&lt;/code&gt;, it matched the received value. This confirmed the CRC module's correct operation, and importantly, the CRC calculation was completed within a single system clock cycle, demonstrating the efficiency of the parallel CRC algorithm.&lt;/p&gt;

&lt;p&gt;From these simulation results, it was concluded that the BISS module could reliably send MA clock signals at 5Mbps, completely receive encoder data, and perform CRC verification within a single clock cycle. Thus, the designed BISS module successfully passed functional simulation tests for the 26-bit mode.&lt;/p&gt;

&lt;p&gt;Similarly, simulation tests were performed for the 32-bit data width, using a corresponding set of simulation data. The functional simulation and CRC verification details for the 32-bit mode also confirmed the successful operation of the designed BISS module.&lt;/p&gt;

&lt;p&gt;In conclusion, the designed BISS module is capable of reliably receiving data from encoders with data widths up to 32 bits at a communication rate of 5Mbps, simply by adjusting the &lt;code&gt;data_length&lt;/code&gt; register.&lt;/p&gt;

&lt;h2&gt;
  
  
  4.3 Tamagawa Protocol Program Design
&lt;/h2&gt;

&lt;p&gt;The Tamagawa protocol, developed by Tamagawa Seiki Co., Ltd. of Japan, employs a "request-response" communication model. In this scheme, the host (FPGA) sends various request commands to the encoder to obtain different types of data. The communication method is similar to standard serial communication, transmitting one byte of data at a fixed rate of 2.5Mbps, starting with the least significant bit (LSB). This section will primarily focus on the Tamagawa protocol's mode for reading encoder information.&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3.1 Tamagawa Protocol Data Structure
&lt;/h3&gt;

&lt;p&gt;The data frame format for reading encoder information consists of several components. The operational principle is that the host sends different control frame commands to the encoder to request specific information. In response, the encoder returns a data group comprising a control frame, a status frame, a variable number of data frames (depending on the encoder model and requested information), and a CRC frame for error checking.&lt;/p&gt;

&lt;p&gt;The control frame's data format is structured into three main parts: a synchronization code, a control command, and a control command checksum bit. The synchronization code is a fixed, unchanging pattern, while the control command and its associated checksum bit are specific instruction codes. These instruction codes, detailed in a command table, correspond to different functions and dictate the type of data the encoder will return. For instance, if a user wishes to obtain both the single-turn and multi-turn values from the encoder, consulting the command table would reveal that instruction code ID 3 (binary: 01011000) corresponds to this request. The host would then send this specific command code to the encoder. Upon receiving it, the encoder would respond with its current single-turn value, multi-turn value, and any additional relevant information.&lt;/p&gt;

&lt;p&gt;The status frame's data format provides critical diagnostic information and is composed of information bits, encoder error alarm bits, and communication alarm bits. The meaning of the information bits can vary depending on the specific encoder model and should be referenced in the corresponding encoder manual. The encoder error alarm bits include &lt;code&gt;ea0&lt;/code&gt; and &lt;code&gt;ea1&lt;/code&gt;. If &lt;code&gt;ea0&lt;/code&gt; is set to '1', it indicates an encoder encoding error or an external power supply issue, signifying that the current encoder information is incorrect. If &lt;code&gt;ea1&lt;/code&gt; is '1', it indicates an error in the encoder's multi-turn value data. The communication alarm bits, &lt;code&gt;ca0&lt;/code&gt; and &lt;code&gt;ca1&lt;/code&gt;, signal issues with the communication itself. If &lt;code&gt;ca0&lt;/code&gt; is '1', it means an error occurred in the control command checksum bit within the received control frame. If &lt;code&gt;ca1&lt;/code&gt; is '1', it indicates an error in the end bit of the received control frame.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tamagawa absolute encoders are capable of achieving high-resolution position encoding data, up to 39 bits in total, which typically includes 23 bits for the single-turn value and 16 bits for the multi-turn value. However, the Tamagawa protocol transmits data only 8 bits at a time. Therefore, sending complete high-resolution position information requires multiple communication exchanges.
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/131730593" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/131730593" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>fpgadev</category>
      <category>stm32</category>
      <category>armdev</category>
    </item>
    <item>
      <title>Difference Between .c and .h Files (The Relationship Between Header Files and Implementation Files)</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Thu, 21 May 2026 07:14:38 +0000</pubDate>
      <link>https://dev.to/sienovoleo/difference-between-c-and-h-files-the-relationship-between-header-files-and-implementation-files-37n3</link>
      <guid>https://dev.to/sienovoleo/difference-between-c-and-h-files-the-relationship-between-header-files-and-implementation-files-37n3</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;a href="http://blog.163.com/xiaotu_sh2008/blog/static/683125962009103045557443" rel="noopener noreferrer"&gt;&lt;strong&gt;Difference Between .c and .h Files&lt;/strong&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;A simple question: What is the difference between .c and .h files?&lt;br&gt;&lt;br&gt;
After studying C for several months, I feel more and more confused. Subroutines can be defined either in a .c file or in a .h file — so what exactly is the difference in usage between these two?&lt;/p&gt;

&lt;p&gt;Reply #2:&lt;br&gt;&lt;br&gt;
Do not define subroutines in .h files.&lt;br&gt;&lt;br&gt;
Function definitions should be placed in .c files, while .h files should only contain declarations. Otherwise, if included multiple times, it will lead to errors due to duplicate function definitions.&lt;/p&gt;

&lt;p&gt;Reply #3:&lt;br&gt;&lt;br&gt;
.h files are for declarations only and do not generate code after compilation.&lt;/p&gt;

&lt;p&gt;Reply #4:&lt;br&gt;&lt;br&gt;
The purpose is to achieve software modularity, making the software structure clear and also easier for others to use your code.&lt;/p&gt;

&lt;p&gt;From a pure C language syntax perspective, you can technically place anything in a .h file, because &lt;code&gt;#include&lt;/code&gt; is completely equivalent to copying and pasting the content of the .h file directly into the .c file.&lt;/p&gt;

&lt;p&gt;.h files should contain macros, variable and function declarations — they tell others "what your program can do and how to use it."&lt;br&gt;&lt;br&gt;
.c files contain the actual definitions of variables and functions — they tell the computer "how your program is implemented."&lt;/p&gt;

&lt;p&gt;Reply #5:&lt;br&gt;&lt;br&gt;
Of course, if a .h file is included by multiple .c files&lt;br&gt;&lt;br&gt;
and the .h file contains definitions of entities (variables or functions), duplicate definition errors will occur.&lt;br&gt;&lt;br&gt;
Declarations can appear any number of times, but definitions must be unique.&lt;/p&gt;

&lt;p&gt;Reply #6:&lt;br&gt;&lt;br&gt;
Generally speaking, a C file should represent a module.&lt;br&gt;&lt;br&gt;
If your program consists of only one module (a single C file), you may not need a header file at all.&lt;/p&gt;

&lt;p&gt;Otherwise, your module is clearly not independent and its implementation needs to be called by other modules. In this case, you should create a header file (H file) to declare which functions are public. Once other modules include your header file, they can use these public declarations.&lt;/p&gt;

&lt;p&gt;Reply #7:&lt;br&gt;&lt;br&gt;
One C file corresponds to one H file — this makes management easier.&lt;br&gt;&lt;br&gt;
For example, if you have a "feed_dog.c", you should also create a "feed_dog.h":&lt;/p&gt;

&lt;h1&gt;
  
  
  ifndef _feed_dog_h
&lt;/h1&gt;

&lt;h1&gt;
  
  
  define _feed_dog_h
&lt;/h1&gt;

&lt;p&gt;extern void feed_dog(void);&lt;/p&gt;

&lt;h1&gt;
  
  
  endif
&lt;/h1&gt;

&lt;p&gt;Actually, it doesn't matter if you write function bodies in H files — it's just not conventional. As long as you follow the above format, you can include the H file as many times as needed, hehe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reply #8:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
It's just a convention.&lt;br&gt;&lt;br&gt;
The compiler itself makes no distinction between .c and .h files. How you use .c and .h files is entirely up to the programmer. However, to ensure your code remains readable (to yourself and others) in the future, please follow common conventions — which have already been well explained by others above.&lt;br&gt;&lt;br&gt;
It's like driving on the right side of the road: it's a human-defined rule. The car (compiler) itself doesn't know whether it's driving on the left or right.&lt;br&gt;&lt;br&gt;
If you prefer, you could even use arbitrary extensions for source and header files, but doing so might cause your integrated development and debugging environment to fail, forcing you to write your own makefile.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reply #9:&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Thank you all very much, but I'm getting even more confused now:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a function is used frequently (e.g., by a dozen C files), I usually put it in the H file and prefix it with &lt;code&gt;__inline&lt;/code&gt;. For &lt;code&gt;__inline&lt;/code&gt; functions, many C files can include this H file, but it seems only one H file can include it — if two H files include it, compilation errors occur.
&lt;/li&gt;
&lt;li&gt;Some array variables can be as large as十几K (tens of kilobytes) and require initial values, so I don't put them in C files — otherwise, it becomes too confusing.
&lt;/li&gt;
&lt;li&gt; 
#ifndef _feed_dog_h
#define _feed_dog_h&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;extern void feed_dog(void);&lt;/p&gt;

&lt;h1&gt;
  
  
  endif
&lt;/h1&gt;

&lt;p&gt;Brother Mohanwei, does this mean that feed_dog.h can be included an unlimited number of times?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reply #11:&lt;/strong&gt;  &lt;/p&gt;

&lt;h1&gt;
  
  
  ifndef _feed_dog_h // If the macro "_feed_dog_h" has not been defined yet
&lt;/h1&gt;

&lt;h1&gt;
  
  
  define _feed_dog_h // Then define the macro "_feed_dog_h"
&lt;/h1&gt;

&lt;p&gt;extern void feed_dog(void); // Declare an external function&lt;/p&gt;

&lt;h1&gt;
  
  
  endif // End of "#ifndef"
&lt;/h1&gt;

&lt;p&gt;Therefore, no matter how many times you include it (even multiple times in the same C file), conflicts will not occur.&lt;/p&gt;

&lt;p&gt;An article found online about .H and .C files — quite helpful, sharing it with everyone.&lt;/p&gt;

&lt;p&gt;In simple terms:&lt;br&gt;&lt;br&gt;
To understand the difference between C files and header files, you first need to understand how a compiler works. Generally, the compiler performs the following steps:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Preprocessing phase
&lt;/li&gt;
&lt;li&gt;Lexical and syntactic analysis phase
&lt;/li&gt;
&lt;li&gt;Compilation phase: first convert to pure assembly code, then assemble into CPU-specific binary code, generating individual object files
&lt;/li&gt;
&lt;li&gt;Linking phase: perform absolute address relocation on code segments from various object files to generate a platform-specific executable file. Optionally, &lt;code&gt;objcopy&lt;/code&gt; can be used to generate pure binary code, stripping away file format information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The compiler works on a per-C-file basis. This means if your project contains no C files at all, it cannot be compiled. The linker works on object files, relocating functions and variables across one or more object files to generate the final executable. In PC-based software development, there is usually a &lt;code&gt;main&lt;/code&gt; function, which is a convention across compilers. Of course, if you write your own linker script, you don't have to use &lt;code&gt;main&lt;/code&gt; as the entry point!&lt;/p&gt;

&lt;p&gt;With this background, let's return to the topic. To generate a final executable, you need some object files — hence you need C files. Among these C files, one must contain the &lt;code&gt;main&lt;/code&gt; function as the program entry point. Let's start with a single C file. Suppose its content is:&lt;/p&gt;

&lt;h1&gt;
  
  
  include 
&lt;/h1&gt;

&lt;h1&gt;
  
  
  include "mytest.h"
&lt;/h1&gt;

&lt;p&gt;int main(int argc,char **argv)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
 test = 25;&lt;br&gt;&lt;br&gt;
 printf("test.................%d\n",test);&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;And the header file content is:&lt;br&gt;&lt;br&gt;
int test;&lt;/p&gt;

&lt;p&gt;Now, let's walk through how the compiler processes this example:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Preprocessing phase&lt;/strong&gt;: The compiler treats each C file as a unit. It reads the C file and finds the first two lines include header files. It searches all include paths for these files. Once found, it processes macros, variables, function declarations, and nested includes in the headers, checks dependencies, performs macro substitution, and detects duplicate definitions or declarations. Finally, it effectively merges all content from the included files into the current C file, forming an intermediate "C file."&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Compilation phase&lt;/strong&gt;: In the previous step, the &lt;code&gt;test&lt;/code&gt; variable from the header file is effectively merged into the intermediate C file, making &lt;code&gt;test&lt;/code&gt; a global variable in this file. The compiler then allocates memory for all variables and functions, compiles functions into binary code, and generates an object file in a specific format. This object file contains symbol descriptions for global variables and functions, and organizes the binary code according to the target file standard.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Linking phase&lt;/strong&gt;: The linker takes the object files generated in the previous step and, based on certain parameters, combines them into the final executable. Its main task is to relocate functions and variables across object files — essentially merging their binary code into a single file according to specific rules.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, returning to the question of what should go in C files versus header files:&lt;br&gt;&lt;br&gt;
Theoretically, anything supported by the C language can go in either .c or .h files. For example, you can write a function body in a header file. As long as some C file includes this header, the function will be compiled as part of that object file (since compilation is per C file, if no C file includes the header, the code is effectively dead). You can also place function declarations, variable declarations, or struct declarations in C files — no problem! So why do we separate code into header and C files? And why do we generally place function and variable declarations, macros, and struct declarations in headers, while definitions and implementations go in C files? The reasons are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;If a function body is implemented in a header file and that header is included by multiple C files, each C file that includes it will generate a copy of the function in its object file. If the function is not declared static (local), the linker will encounter multiple identical functions and report an error.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If a global variable is defined in a header file and initialized, then every C file that includes this header will have a copy of this variable. Since it has an initial value, the compiler places it in the DATA segment. During linking, multiple instances of the same variable will exist in the DATA segment, and the linker cannot merge them into a single variable (i.e., allocate only one storage space). However, if the variable is not initialized, the compiler places it in the BSS segment, and the linker will merge multiple instances of the same variable in BSS into a single storage location.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If macros, structs, or functions are declared in a C file, then to use them in another C file, you must repeat the declaration. If you modify a declaration in one C file but forget to update others, serious bugs can occur, making program logic unpredictable. By placing these common elements in a single header file, any C file that needs them can simply include the header — much more convenient. When you need to change a declaration, you only need to modify the header file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Declaring structs, functions, etc., in header files allows you to package your code into a library for others to use without revealing the source code. How can others use your library functions? One way is to publish the source code, but another is to provide only the header file. Users can see your function prototypes in the header and know how to call them — just like using &lt;code&gt;printf&lt;/code&gt;. How do you know its parameters? By looking at the declarations in its header file! Of course, these have become part of the C standard, so even without checking headers, you may already know how to use them.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;What is the difference between ".h" and ".c" files in source code?&lt;br&gt;&lt;br&gt;
In a source code project, I see both udp.h and udp.c files — what's the relationship between them? What's the difference? Any experts care to help? Thanks!&lt;/p&gt;

&lt;p&gt;Best answer: .c files are C source files, stored in text format, while .h files are header files — they contain function and global variable declarations in C. Since C functions are encapsulated, their implementation code is not visible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The Relationship Between Header Files and Implementation Files&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Today I came across an online article explaining .h and .c (.cpp) files. After reading it, I found some parts misleading, so I'd like to provide some guidance based on my understanding — especially for beginners.&lt;br&gt;&lt;br&gt;
Do you understand the basic meaning?&lt;br&gt;&lt;br&gt;
To understand the relationship between the two, we need to go back many years — long long ago, once upon a time...&lt;br&gt;&lt;br&gt;
It was a forgotten era when compilers only recognized .c (.cpp) files and had no idea what a .h file was.&lt;br&gt;&lt;br&gt;
People wrote many .c (.cpp) files and gradually noticed that the same declaration statements were repeated across many files. Yet they had to painstakingly retype them in every .c (.cpp) file. Worse, when a declaration changed, they had to manually search and update every file — a true apocalypse!&lt;br&gt;&lt;br&gt;
Finally, someone (or some people) could no longer endure this and extracted the repeated parts into a new file. Then, in any .c (.cpp) file that needed them, they added &lt;code&gt;#include XXXX&lt;/code&gt;. Now, when a declaration changed, they only needed to update one file — and peace was restored!&lt;br&gt;&lt;br&gt;
Because this new file was typically placed at the top of .c (.cpp) files, it was called a "header file," with the extension .h.&lt;br&gt;&lt;br&gt;
From then on, compilers (actually preprocessors) learned that besides .c (.cpp) files, there were also .h files and a &lt;code&gt;#include&lt;/code&gt; directive.&lt;/p&gt;

&lt;p&gt;Although many changes have occurred since, this practice continues to this day — though over time, people have largely forgotten its origins.&lt;/p&gt;

&lt;p&gt;Now that we've mentioned header files, let's discuss their roles.&lt;br&gt;&lt;br&gt;
I recall Lin Rui's concise description from &lt;em&gt;High-Quality C/C++ Programming&lt;/em&gt;:&lt;br&gt;&lt;br&gt;
(1) Use header files to access library functionality. In many cases, source code cannot or must not be disclosed to users. Providing only header files and binary libraries is sufficient. Users can call library functions based on the interface declarations in the header, without needing to know the implementation details. The compiler extracts the appropriate code from the library.&lt;br&gt;&lt;br&gt;
(2) Header files enhance type safety. If an interface is implemented or used in a way inconsistent with its declaration in the header, the compiler will flag an error. This simple rule greatly reduces debugging and error-fixing effort.&lt;/p&gt;

&lt;p&gt;Preprocessing is the compiler's precursor, responsible for combining program modules stored in different files into a complete source program.&lt;br&gt;&lt;br&gt;
&lt;code&gt;#include&lt;/code&gt; is merely a simple file inclusion preprocessor command — it inserts the content of the specified file at that location. Other than that, it has no other purpose (at least that's my understanding).&lt;/p&gt;

&lt;p&gt;I fully agree with Brother Qiankun Yixiao's view — foundational concepts must be clearly understood.&lt;br&gt;&lt;br&gt;
I'll now expand on his example to clarify some confusing points.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;&lt;br&gt;
//a.h&lt;br&gt;&lt;br&gt;
void foo();&lt;/p&gt;

&lt;p&gt;//a.c  &lt;/p&gt;

&lt;h1&gt;
  
  
  include "a.h"  // My question: Is this line necessary or not?
&lt;/h1&gt;

&lt;p&gt;void foo()&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    return;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;//main.c  &lt;/p&gt;

&lt;h1&gt;
  
  
  include "a.h"
&lt;/h1&gt;

&lt;p&gt;int main(int argc, char *argv[])&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
   foo();&lt;br&gt;&lt;br&gt;
 　return 0;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;For the above code, answer three questions:&lt;br&gt;&lt;br&gt;
Is the &lt;code&gt;#include "a.h"&lt;/code&gt; in a.c redundant?  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Why do we often see xx.c including its corresponding xx.h?
&lt;/li&gt;
&lt;li&gt;If a.c does not include it, will the compiler automatically bind the contents of the .h file with the同名 .c file?
&lt;/li&gt;
&lt;li&gt;I'll rephrase the third question: If a.c does not include the .h file, will the compiler automatically bind the contents of the .h file with the同名 .c file?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is Qiankun Yixiao's original explanation:&lt;/p&gt;

&lt;p&gt;From the C compiler's perspective, .h and .c files are irrelevant — you could rename them to .txt or .doc with little consequence. In other words, there is no inherent connection between .h and .c files. .h files typically contain declarations of variables, arrays, and functions defined in the同名 .c file — declarations that need to be accessible outside the .c file. What's the purpose of these declarations? Simply to make it convenient for other code to reference them. The &lt;code&gt;#include "xx.h"&lt;/code&gt; directive literally means "remove this line and insert the entire content of xx.h here." Since many places need these function declarations (every place that calls functions from xx.c must declare them beforehand), using &lt;code&gt;#include "xx.h"&lt;/code&gt; saves many lines of code — letting the preprocessor do the replacement. In short, xx.h exists only to save keystrokes for places that need to declare functions from xx.c. Whether the file that includes this .h is a .h, a .c, or the同名 .c file, there is no necessary relationship.&lt;br&gt;&lt;br&gt;
You might say: "Wait — if I only want to call one function from xx.c, but I include the entire xx.h, doesn't that bring in many useless declarations?" Yes, indeed, it introduces some "garbage." But it saves you effort and keeps the code cleaner. You can't have both fish and bear's paws — that's the trade-off. Anyway, extra declarations (since .h files usually contain only declarations, not definitions — see my article "Crossing the Road, Look Left and Right") do no harm and don't affect compilation — so why not?&lt;/p&gt;

&lt;p&gt;Now, revisiting the three questions above — are they easier to answer?&lt;/p&gt;

&lt;p&gt;His answers:&lt;br&gt;&lt;br&gt;
Answer: 1. Not necessarily. In this example, it's clearly redundant. But if functions in .c need to call other functions in the same .c file, including the同名 .h at the top avoids issues with declaration and call order (C requires declarations before use, and including the同名 .h at the beginning of the .c file solves this). Many projects even adopt this as a coding standard to ensure clean, readable code.  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Answered in 1.
&lt;/li&gt;
&lt;li&gt;No. Anyone asking this question lacks clear understanding — or is trying to confuse things. It's extremely annoying that many Chinese exams include such poor-quality questions, seemingly designed only to confuse students.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Over!&lt;/p&gt;

&lt;p&gt;One key point must be clarified: compilers work on compilation units. A compilation unit consists of a .c file and all .h files it includes. Intuitively, it's one file. A project can contain many files, one of which is the entry point — typically &lt;code&gt;main()&lt;/code&gt; (though it's possible to have no such function and still run the program — see my blog). Without an entry point, the compilation unit only generates an object file (.o on Unix, .obj on Windows).&lt;/p&gt;

&lt;p&gt;This example contains two compilation units: a.c and main.c. During the compilation phase, each generates its own .o file independently, without interaction with other files.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;#include&lt;/code&gt; preprocessor directive is handled during the preprocessing phase — which occurs before actual compilation and is handled by a preprocessor.&lt;/p&gt;

&lt;p&gt;.h and .c files aren't entirely "irrelevant" — discussing them without considering the compiler is meaningless. Going deeper — such as how the OS loads the file, PE format (ELF on Linux), etc. — the compiler must first recognize the file to compile it. That's the prerequisite. If you change the extension, will the compiler still recognize it? At a higher level, Brother XX's point is valid — he means that just because two files have the same name doesn't imply a technical relationship; names are arbitrary.&lt;br&gt;&lt;br&gt;
The connection between them, as I mentioned earlier, is historical and habitual. Who wants to remember dozens of different filenames? (Take me as an example — if a data table has more than 30 fields, my head spins. Now some tables have over a hundred fields. I really hope someone invents a better method to make our world a better place.)&lt;/p&gt;

&lt;p&gt;Qiankun Yixiao's third question is very representative — it appears frequently online. Modern compilers are absolutely not that intelligent, nor is there any need for them to be. Let's now discuss the compiler's processing flow (this is likely where beginners have doubts — lack of understanding of how .h and .c (.cpp) files change during compilation).&lt;/p&gt;

&lt;p&gt;Let me give a simple example:&lt;br&gt;&lt;br&gt;
//a.h&lt;br&gt;&lt;br&gt;
class   A&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
public:&lt;br&gt;&lt;br&gt;
      int   f(int   t);&lt;br&gt;&lt;br&gt;
};&lt;/p&gt;

&lt;p&gt;//a.cpp  &lt;/p&gt;

&lt;h1&gt;
  
  
  include   "a.h"
&lt;/h1&gt;

&lt;p&gt;int   A::f(int   t)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    return   t;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;//main.cpp  &lt;/p&gt;

&lt;h1&gt;
  
  
  include   "a.h"
&lt;/h1&gt;

&lt;p&gt;void   main()&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
      A   a;&lt;br&gt;&lt;br&gt;
      a.f(3);&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
During preprocessing, when the preprocessor sees &lt;code&gt;#include "filename"&lt;/code&gt;, it reads that file in. For example, when compiling main.cpp and encountering &lt;code&gt;#include "a.h"&lt;/code&gt;, it reads the content of a.h. It now knows there is a class A with a member function f that takes an int parameter and returns an int. Proceeding further, it understands &lt;code&gt;A a&lt;/code&gt; — creating an object of class A on the stack. Then it sees a call to A's member function f with parameter 3. Since it knows f expects an integer, and 3 matches, it places 3 on the stack and generates a call instruction (typically a &lt;code&gt;call&lt;/code&gt;). It doesn't know where f is implemented — it leaves that blank to be resolved at link time. It also knows f returns an int, so it may prepare for that (though in this example, we don't use the return value, so it may ignore it). Reaching the end, main.cpp is compiled, producing main.obj. Throughout this process, it never needs to know the content of a.cpp.&lt;br&gt;&lt;br&gt;
Similarly, the compiler compiles a.cpp, generating the f() function and producing a.obj.&lt;br&gt;&lt;br&gt;
Finally, the linker combines all .obj files generated from the project's .cpp files.&lt;br&gt;&lt;br&gt;
At this stage, it locates the actual address of the f(int) function and fills in the blank address in main.obj. The final executable, main.exe, is produced.&lt;/p&gt;

&lt;p&gt;Clear now? If not, let me explain further. When we study compiler principles, we know compilers work in phases, transforming the source program from one representation to another. Typically: source -&amp;gt; lexer -&amp;gt; parser -&amp;gt; semantic analyzer -&amp;gt; intermediate code generator -&amp;gt; optimizer -&amp;gt; code generator -&amp;gt; target program.&lt;br&gt;&lt;br&gt;
Among these, two key components involved in most phases are the symbol table and error handler.&lt;br&gt;&lt;br&gt;
Ultimately, it's the symbol table that causes confusion. The symbol table is a data structure. A fundamental task of the compiler is to record identifiers used in the source and collect attribute information for each — such as storage location, type, scope (where it's valid), etc. Simply put, when the compiler sees a symbol declaration (e.g., a function name), it registers it in the symbol table, storing information like entry address, number of parameters, return type, etc. The linking phase mainly resolves symbol references across files — what we commonly call "dereferencing."&lt;br&gt;&lt;br&gt;
After all this, is it clearer?&lt;/p&gt;

&lt;p&gt;Finally, quoting Brother XXX's concluding three points:&lt;br&gt;&lt;br&gt;
Understanding syntax and concepts can be easy or hard. Three tips:  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Don't work blindly — take time to think, reflect, and read.
&lt;/li&gt;
&lt;li&gt;Read good books and ask knowledgeable people. Bad books and weak programmers give you wrong concepts and mislead you.
&lt;/li&gt;
&lt;li&gt;Diligence compensates for lack of talent — hard work brings results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you think .c and .h files differ only in name, your understanding is too shallow. Looking at language evolution from procedural to object-oriented, header files resemble classes in some ways. Header files offer better encapsulation — this is easy to see. Just open any standard C library .h file — the pattern is obvious. So I agree with Brother XXX that Qiankun Yixiao's view is superficial.&lt;/p&gt;

&lt;p&gt;But from another perspective:&lt;/p&gt;

&lt;p&gt;(As for compiler implementation, I'm not fully informed. But I believe)&lt;br&gt;&lt;br&gt;
//a.cpp  &lt;/p&gt;

&lt;h1&gt;
  
  
  include "a.h"
&lt;/h1&gt;

&lt;p&gt;int A::f(int t)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
return t;&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
programs like this probably don't exist... hehe. So modern developers simplifying .h and .c usage is also influenced by history and era.&lt;/p&gt;

&lt;p&gt;I'm not very bright, but after reading several times, I finally got it.&lt;br&gt;&lt;br&gt;
Now summarizing (please correct me if wrong):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Header files can pre-inform the compiler of necessary declarations, allowing smooth compilation even before actual definitions appear.
The significance of header files lies in:
a. Making programs concise and clear.
b. Avoiding redundant declaration code.
&lt;/li&gt;
&lt;li&gt;There is no inherent connection between **.c and **.h files.
This article is from CSDN Blog. Please credit the source: &lt;a href="http://blog.csdn.net/bm1408/archive/2006/02/22/606382.aspx" rel="noopener noreferrer"&gt;http://blog.csdn.net/bm1408/archive/2006/02/22/606382.aspx&lt;/a&gt;
---&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6800672" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6800672" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>compiler</category>
      <category>include</category>
      <category>c</category>
      <category>language</category>
    </item>
    <item>
      <title>Linux Socket Network Programming (Theoretical Analysis + Comprehensive Examples)</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Thu, 21 May 2026 07:14:05 +0000</pubDate>
      <link>https://dev.to/sienovoleo/linux-socket-network-programming-theoretical-analysis-comprehensive-examples-4ldi</link>
      <guid>https://dev.to/sienovoleo/linux-socket-network-programming-theoretical-analysis-comprehensive-examples-4ldi</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;What is a Socket?&lt;br&gt;&lt;br&gt;
The Socket interface is the API for TCP/IP networks. It defines numerous functions or routines that developers can use to build applications over TCP/IP networks. To master Internet-based TCP/IP network programming, one must understand the Socket interface.&lt;br&gt;&lt;br&gt;
Socket interfaces were originally designed for Unix operating systems. If you are familiar with Unix I/O operations, understanding Sockets becomes much easier. Network socket data transmission is a special form of I/O, and a socket is essentially a file descriptor. Similar to opening a file, there is a function call &lt;code&gt;socket()&lt;/code&gt; that returns an integer socket descriptor. Subsequent operations such as connection establishment and data transfer are performed using this descriptor. There are two commonly used socket types: stream sockets (&lt;code&gt;SOCK_STREAM&lt;/code&gt;) and datagram sockets (&lt;code&gt;SOCK_DGRAM&lt;/code&gt;). Stream sockets are connection-oriented and used with TCP services; datagram sockets are connectionless and correspond to UDP services.&lt;/p&gt;

&lt;p&gt;Socket Creation&lt;br&gt;&lt;br&gt;
To create a socket, a program calls the &lt;code&gt;socket()&lt;/code&gt; function, which returns a handle similar to a file descriptor. The function prototype is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;protocol&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;domain&lt;/code&gt; parameter specifies the protocol family, usually &lt;code&gt;PF_INET&lt;/code&gt;, indicating the Internet protocol family (TCP/IP). The &lt;code&gt;type&lt;/code&gt; parameter defines the socket type: &lt;code&gt;SOCK_STREAM&lt;/code&gt; or &lt;code&gt;SOCK_DGRAM&lt;/code&gt;. The Socket interface also defines raw sockets (&lt;code&gt;SOCK_RAW&lt;/code&gt;), allowing programs to access lower-level protocols. The &lt;code&gt;protocol&lt;/code&gt; parameter is typically set to 0. The &lt;code&gt;socket()&lt;/code&gt; call returns an integer socket descriptor, which can be used in subsequent operations.&lt;br&gt;&lt;br&gt;
A socket descriptor is a pointer to an internal data structure, pointing to an entry in the descriptor table. When &lt;code&gt;socket()&lt;/code&gt; is called, the system allocates storage space for a socket data structure. The system manages the descriptor table on behalf of the application.&lt;br&gt;&lt;br&gt;
A network connection between two programs consists of five pieces of information: communication protocol, local protocol address, local host port, remote host address, and remote protocol port. This information is stored within the socket data structure.&lt;/p&gt;

&lt;p&gt;Socket Configuration&lt;br&gt;&lt;br&gt;
After obtaining a socket descriptor via &lt;code&gt;socket()&lt;/code&gt;, the socket must be configured before network transmission can occur. Connection-oriented socket clients use the &lt;code&gt;connect()&lt;/code&gt; function to store local and remote information in the socket structure. Unconnected socket clients and servers, as well as connection-oriented socket servers, use the &lt;code&gt;bind()&lt;/code&gt; function to configure local information.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;bind()&lt;/code&gt; function associates a socket with a port on the local machine, after which the application can listen for service requests on that port. The function prototype is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;addrlen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, &lt;code&gt;sockfd&lt;/code&gt; is the socket descriptor returned by &lt;code&gt;socket()&lt;/code&gt;, &lt;code&gt;my_addr&lt;/code&gt; is a pointer to a &lt;code&gt;sockaddr&lt;/code&gt; structure containing the local IP address and port number, and &lt;code&gt;addrlen&lt;/code&gt; is typically set to &lt;code&gt;sizeof(struct sockaddr)&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;struct sockaddr&lt;/code&gt; type is used to store socket information:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="n"&gt;sa_family&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Address family, AF_xxx */&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sa_data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;         &lt;span class="cm"&gt;/* 14-byte protocol address */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;sa_family&lt;/code&gt; field is usually &lt;code&gt;AF_INET&lt;/code&gt;, representing the Internet (TCP/IP) address family. The &lt;code&gt;sa_data&lt;/code&gt; field contains the socket's IP address and port number.&lt;br&gt;&lt;br&gt;
Another commonly used structure is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sin_family&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="cm"&gt;/* Address family */&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;short&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sin_port&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* Port number */&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in_addr&lt;/span&gt; &lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="cm"&gt;/* IP address */&lt;/span&gt;
    &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;sin_zero&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;      &lt;span class="cm"&gt;/* Padding to match struct sockaddr size */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This structure is more convenient. The &lt;code&gt;sin_zero&lt;/code&gt; field ensures &lt;code&gt;sockaddr_in&lt;/code&gt; is the same size as &lt;code&gt;sockaddr&lt;/code&gt; and can be zeroed using &lt;code&gt;bzero()&lt;/code&gt; or &lt;code&gt;memset()&lt;/code&gt;. Pointers to &lt;code&gt;sockaddr_in&lt;/code&gt; and &lt;code&gt;sockaddr&lt;/code&gt; can be cast interchangeably, meaning you can pass a &lt;code&gt;sockaddr_in*&lt;/code&gt; where a &lt;code&gt;sockaddr*&lt;/code&gt; is expected, and vice versa.&lt;br&gt;&lt;br&gt;
When using &lt;code&gt;bind()&lt;/code&gt;, you can use the following assignments to automatically obtain the local IP address and a randomly selected unused port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;                    &lt;span class="cm"&gt;/* System selects an unused port */&lt;/span&gt;
&lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INADDR_ANY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="cm"&gt;/* Use local IP address */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting &lt;code&gt;my_addr.sin_port&lt;/code&gt; to 0 lets the system automatically choose an available port. Setting &lt;code&gt;my_addr.sin_addr.s_addr&lt;/code&gt; to &lt;code&gt;INADDR_ANY&lt;/code&gt; tells the system to fill in the local IP address.&lt;br&gt;&lt;br&gt;
Note: When using &lt;code&gt;bind()&lt;/code&gt;, &lt;code&gt;sin_port&lt;/code&gt; and &lt;code&gt;sin_addr&lt;/code&gt; must be converted to network byte order; &lt;code&gt;sin_addr&lt;/code&gt; itself does not require conversion.&lt;br&gt;&lt;br&gt;
Computers use two byte orders: big-endian (most significant byte first) and little-endian (least significant byte first). Internet data is transmitted in big-endian order. Machines using little-endian internally must convert data before transmission to avoid inconsistencies.&lt;br&gt;&lt;br&gt;
The following functions perform byte order conversion:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;htonl()&lt;/code&gt;: Convert a 32-bit value from host to network byte order
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;htons()&lt;/code&gt;: Convert a 16-bit value from host to network byte order
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ntohl()&lt;/code&gt;: Convert a 32-bit value from network to host byte order
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ntohs()&lt;/code&gt;: Convert a 16-bit value from network to host byte order
&lt;code&gt;bind()&lt;/code&gt; returns 0 on success and -1 on error, setting &lt;code&gt;errno&lt;/code&gt; to the appropriate error code. Avoid using port numbers below 1024 when calling &lt;code&gt;bind()&lt;/code&gt;, as ports 1–1024 are reserved. Choose any unused port above 1024.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Connection Establishment&lt;br&gt;&lt;br&gt;
Connection-oriented client programs use the &lt;code&gt;connect()&lt;/code&gt; function to configure the socket and establish a TCP connection with a remote server. The function prototype is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;addrlen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the socket descriptor returned by &lt;code&gt;socket()&lt;/code&gt;; &lt;code&gt;serv_addr&lt;/code&gt; is a pointer to a structure containing the remote host's IP address and port; &lt;code&gt;addrlen&lt;/code&gt; is the size of the address structure. &lt;code&gt;connect()&lt;/code&gt; returns -1 on error and sets &lt;code&gt;errno&lt;/code&gt; accordingly. Client programs typically do not call &lt;code&gt;bind()&lt;/code&gt; because they only need to know the destination IP address. The system automatically selects an unused local port and notifies the program when data arrives.&lt;br&gt;&lt;br&gt;
&lt;code&gt;connect()&lt;/code&gt; initiates a direct connection to the remote host. Only connection-oriented clients need to connect their socket to a remote host. Connectionless protocols never establish direct connections. Connection-oriented servers do not initiate connections; they passively listen for client requests on a port.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;listen()&lt;/code&gt; function places the socket in passive listening mode and creates an incoming connection queue, storing service requests until the program processes them.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;backlog&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the socket descriptor returned by &lt;code&gt;socket()&lt;/code&gt;; &lt;code&gt;backlog&lt;/code&gt; specifies the maximum number of pending connections in the queue, which wait for &lt;code&gt;accept()&lt;/code&gt; (see below). Most systems default &lt;code&gt;backlog&lt;/code&gt; to 20. If a new request arrives when the queue is full, the socket rejects the connection, and the client receives an error.&lt;br&gt;&lt;br&gt;
&lt;code&gt;listen()&lt;/code&gt; returns -1 on error and sets &lt;code&gt;errno&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;accept()&lt;/code&gt; function allows a server to accept incoming client connection requests. After setting up the input queue, the server calls &lt;code&gt;accept()&lt;/code&gt;, then sleeps until a connection request arrives.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addrlen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the listening socket descriptor; &lt;code&gt;addr&lt;/code&gt; is typically a pointer to a &lt;code&gt;sockaddr_in&lt;/code&gt; variable that stores information about the requesting host (which host, which port); &lt;code&gt;addrlen&lt;/code&gt; is usually a pointer to an integer with value &lt;code&gt;sizeof(struct sockaddr_in)&lt;/code&gt;. On error, &lt;code&gt;accept()&lt;/code&gt; returns -1 and sets &lt;code&gt;errno&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
When &lt;code&gt;accept()&lt;/code&gt; detects a connection request on the monitored socket, the system creates a new socket, associates it with the requesting process's address, and returns its descriptor. The original socket continues listening, while data transmission occurs over the new socket.&lt;/p&gt;

&lt;p&gt;Data Transmission&lt;br&gt;&lt;br&gt;
The &lt;code&gt;send()&lt;/code&gt; and &lt;code&gt;recv()&lt;/code&gt; functions are used for data transfer over connection-oriented sockets.&lt;br&gt;&lt;br&gt;
&lt;code&gt;send()&lt;/code&gt; prototype:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the socket descriptor for data transmission; &lt;code&gt;msg&lt;/code&gt; is a pointer to the data to send; &lt;code&gt;len&lt;/code&gt; is the data length in bytes; &lt;code&gt;flags&lt;/code&gt; is usually 0 (refer to man pages for advanced usage).&lt;br&gt;&lt;br&gt;
&lt;code&gt;send()&lt;/code&gt; returns the number of bytes actually sent, which may be less than requested. Always compare the return value with &lt;code&gt;len&lt;/code&gt; and handle partial sends appropriately.&lt;br&gt;&lt;br&gt;
Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bytes_sent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;bytes_sent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;recv()&lt;/code&gt; prototype:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the receiving socket descriptor; &lt;code&gt;buf&lt;/code&gt; is the buffer to store received data; &lt;code&gt;len&lt;/code&gt; is buffer size; &lt;code&gt;flags&lt;/code&gt; is usually 0. &lt;code&gt;recv()&lt;/code&gt; returns the number of bytes actually received, or -1 on error with &lt;code&gt;errno&lt;/code&gt; set.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sendto()&lt;/code&gt; and &lt;code&gt;recvfrom()&lt;/code&gt; are used for connectionless datagram sockets. Since no connection is established, the destination address must be specified during data transmission.&lt;br&gt;&lt;br&gt;
&lt;code&gt;sendto()&lt;/code&gt; prototype:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;sendto&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tolen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This function adds two parameters: &lt;code&gt;to&lt;/code&gt;, which contains the destination IP and port, and &lt;code&gt;tolen&lt;/code&gt;, typically &lt;code&gt;sizeof(struct sockaddr)&lt;/code&gt;. &lt;code&gt;sendto()&lt;/code&gt; returns the number of bytes sent or -1 on error.&lt;br&gt;&lt;br&gt;
&lt;code&gt;recvfrom()&lt;/code&gt; prototype:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;recvfrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;unsigned&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fromlen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;from&lt;/code&gt; is a &lt;code&gt;sockaddr&lt;/code&gt; variable storing the source IP and port. &lt;code&gt;fromlen&lt;/code&gt; is usually &lt;code&gt;sizeof(struct sockaddr)&lt;/code&gt;. On return, &lt;code&gt;fromlen&lt;/code&gt; contains the actual size of data stored in &lt;code&gt;from&lt;/code&gt;. &lt;code&gt;recvfrom()&lt;/code&gt; returns the number of bytes received or -1 on error with &lt;code&gt;errno&lt;/code&gt; set.&lt;br&gt;&lt;br&gt;
If &lt;code&gt;connect()&lt;/code&gt; is called on a datagram socket, &lt;code&gt;send()&lt;/code&gt; and &lt;code&gt;recv()&lt;/code&gt; can be used for data transfer. The socket remains a datagram socket using UDP, but the kernel automatically adds source and destination address information during transmission.&lt;/p&gt;

&lt;p&gt;Ending Transmission&lt;br&gt;&lt;br&gt;
After all data operations are complete, call &lt;code&gt;close()&lt;/code&gt; to release the socket and stop all data operations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, use &lt;code&gt;shutdown()&lt;/code&gt; to close the socket partially. This function allows stopping data transmission in one direction while continuing in the other. For example, you can disable sending while still receiving data until all incoming data is read.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;shutdown&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;how&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;sockfd&lt;/code&gt; is the socket descriptor to close. The &lt;code&gt;how&lt;/code&gt; parameter specifies the shutdown mode:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;0 — Disallow further receives
&lt;/li&gt;
&lt;li&gt;1 — Disallow further sends
&lt;/li&gt;
&lt;li&gt;2 — Disallow both sends and receives
To fully close, call &lt;code&gt;close()&lt;/code&gt;.
&lt;code&gt;shutdown()&lt;/code&gt; returns 0 on success and -1 on error with &lt;code&gt;errno&lt;/code&gt; set.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Socket Programming Example&lt;br&gt;&lt;br&gt;
The server in this example sends the string "Hello, you are connected!" to the client via a socket connection. Running the server software on the server and the client software on the client will result in the client receiving the string.&lt;br&gt;&lt;br&gt;
Server code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/wait.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#define SERVPORT 3333 &lt;/span&gt;&lt;span class="cm"&gt;/* Server listening port */&lt;/span&gt;&lt;span class="cp"&gt;
#define BACKLOG 10     &lt;/span&gt;&lt;span class="cm"&gt;/* Max concurrent connection requests */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* sockfd: listening socket; client_fd: data transfer socket */&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* Local address info */&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="cm"&gt;/* Client address info */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sin_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"socket creation failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVPORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;INADDR_ANY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_zero&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;my_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"bind failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BACKLOG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"listen failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;sin_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;remote_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;sin_size&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accept failed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;continue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received a connection from %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;inet_ntoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;remote_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;fork&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* Child process code */&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Hello, you are connected!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;26&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"send failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The server workflow: First, &lt;code&gt;socket()&lt;/code&gt; creates a socket. Then &lt;code&gt;bind()&lt;/code&gt; associates it with the local address and port. &lt;code&gt;listen()&lt;/code&gt; starts listening on that socket. When &lt;code&gt;accept()&lt;/code&gt; receives a connection request, it creates a new socket. The server prints the client's IP address and sends the greeting via the new socket, then closes it.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;fork()&lt;/code&gt; function creates a child process to handle data transfer. &lt;code&gt;fork()&lt;/code&gt; returns 0 in the child process, so the &lt;code&gt;if&lt;/code&gt; block contains child process code, executed concurrently with the parent process code that follows.&lt;/p&gt;

&lt;p&gt;Client code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netdb.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#define SERVPORT 3333
#define MAXDATASIZE 100 &lt;/span&gt;&lt;span class="cm"&gt;/* Max data size per transfer */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[]){&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;recvbytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAXDATASIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hostent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Please enter the server's hostname!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gethostbyname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;herror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gethostbyname failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"socket creation failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SERVPORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in_addr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;h_addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_zero&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"connect failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;recvbytes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;MAXDATASIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"recv failed!"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;recvbytes&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Received: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client first resolves the server's hostname to an IP address using &lt;code&gt;gethostbyname()&lt;/code&gt;, then creates a socket and connects to the server. After a successful connection, it receives data and closes the socket.&lt;br&gt;&lt;br&gt;
&lt;code&gt;gethostbyname()&lt;/code&gt; performs domain name resolution. Since IP addresses are hard to remember, domain names are commonly used, requiring conversion. Function prototype:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hostent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;gethostbyname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns a pointer to a &lt;code&gt;hostent&lt;/code&gt; structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hostent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;h_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="cm"&gt;/* Official host name */&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;h_aliases&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;      &lt;span class="cm"&gt;/* NULL-terminated array of host aliases */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h_addrtype&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;        &lt;span class="cm"&gt;/* Address type, AF_INET in Internet */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;h_length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;          &lt;span class="cm"&gt;/* Length of address in bytes */&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;h_addr_list&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* NULL-terminated array of host addresses */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="cp"&gt;#define h_addr h_addr_list[0] &lt;/span&gt;&lt;span class="cm"&gt;/* First address in h_addr_list */&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On success, &lt;code&gt;gethostbyname()&lt;/code&gt; returns a pointer to &lt;code&gt;struct hostent&lt;/code&gt;; on failure, it returns NULL. Use &lt;code&gt;herror()&lt;/code&gt; instead of &lt;code&gt;perror()&lt;/code&gt; to print error messages.&lt;/p&gt;

&lt;p&gt;Connectionless client/server programs work similarly in principle to connection-oriented ones. The key difference is that connectionless clients typically do not establish a connection and must specify the remote address when sending or receiving data.&lt;/p&gt;

&lt;p&gt;Blocking and Non-blocking&lt;br&gt;&lt;br&gt;
A blocking function prevents the program from calling another function until its task is complete. For example, when a program executes a read operation, it waits until the read finishes before proceeding. When a server reaches the &lt;code&gt;accept()&lt;/code&gt; statement and no client connection request has arrived, it blocks, waiting for a request. This is called blocking. Non-blocking operations return immediately. For instance, if a server should only check for pending connections without waiting, the socket can be set to non-blocking mode. In non-blocking mode, &lt;code&gt;accept()&lt;/code&gt; returns immediately if no client is waiting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;fcntl.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;fcntl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;F_SETFL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;O_NONBLOCK&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Setting a socket to non-blocking enables polling of multiple sockets. Attempting to read from a non-blocking socket with no data returns immediately with -1 and sets &lt;code&gt;errno&lt;/code&gt; to &lt;code&gt;EWOULDBLOCK&lt;/code&gt;. However, polling wastes CPU cycles. The &lt;code&gt;select()&lt;/code&gt; system call solves this efficiently by suspending the process while the kernel monitors a set of file descriptors. When activity occurs on any monitored descriptor, &lt;code&gt;select()&lt;/code&gt; returns, indicating which descriptor is ready. This avoids wasteful CPU polling. The &lt;code&gt;select()&lt;/code&gt; prototype is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;numfds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd_set&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;readfds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;fd_set&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;writefds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="n"&gt;fd_set&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;exceptfds&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timeval&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;readfds&lt;/code&gt;, &lt;code&gt;writefds&lt;/code&gt;, and &lt;code&gt;exceptfds&lt;/code&gt; are sets of file descriptors monitored for read, write, and exception events. To check if data can be read from standard input and a socket, add file descriptor 0 and the socket descriptor to &lt;code&gt;readfds&lt;/code&gt;. &lt;code&gt;numfds&lt;/code&gt; is the highest-numbered file descriptor plus one—in this case, &lt;code&gt;sockfd + 1&lt;/code&gt;. After &lt;code&gt;select()&lt;/code&gt; returns, &lt;code&gt;readfds&lt;/code&gt; is modified to indicate ready descriptors. Use &lt;code&gt;FD_ISSET()&lt;/code&gt; to test. Macros for manipulating &lt;code&gt;fd_set&lt;/code&gt;:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;FD_ZERO(fd_set *set)&lt;/code&gt; — Clear the set
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FD_SET(int fd, fd_set *set)&lt;/code&gt; — Add a descriptor to the set
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FD_CLR(int fd, fd_set *set)&lt;/code&gt; — Remove a descriptor from the set
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FD_ISSET(int fd, fd_set *set)&lt;/code&gt; — Test if a descriptor is set
The &lt;code&gt;timeout&lt;/code&gt; parameter is a pointer to a &lt;code&gt;struct timeval&lt;/code&gt;, allowing &lt;code&gt;select()&lt;/code&gt; to return after the specified time if no descriptors are ready. The structure:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;timeval&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tv_sec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;    &lt;span class="cm"&gt;/* seconds */&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;tv_usec&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;   &lt;span class="cm"&gt;/* microseconds */&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;POP3 Client Example&lt;br&gt;&lt;br&gt;
This example implements a POP3 client that connects to a mail server and retrieves emails for a specified account. Commands are stored in the &lt;code&gt;POPMessage&lt;/code&gt; array and sent in a &lt;code&gt;do-while&lt;/code&gt; loop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt;&lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;errno.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netdb.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#define POP3SERVPORT 110
#define MAXDATASIZE 4096
&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[]){&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hostent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;POPMessage&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"USER userid&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"PASS password&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"STAT&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"LIST&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"RETR 1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"DELE 1&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="s"&gt;"QUIT&lt;/span&gt;&lt;span class="se"&gt;\r\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nb"&gt;NULL&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iEnd&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAXDATASIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gethostbyname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"your.server"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"gethostbyname error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"socket error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POP3SERVPORT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in_addr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;h_addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_zero&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;serv_addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;==-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"connect error"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;POPMessage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POPMessage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"have sent: %s"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;POPMessage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="n"&gt;iLength&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;recv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="n"&gt;iEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;iEnd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;iEnd&lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="n"&gt;iLength&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iEnd&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sc"&gt;'\0'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"received: %s,%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;POPMessage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;iMsg&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A robust Linux/Unix network file transfer example:&lt;/p&gt;

&lt;p&gt;I've been studying Unix network programming recently. Initially, when transferring image files, extra bytes would appear. After testing and reviewing online articles, I discovered the issue was improper handling of the final read/write operations. I've improved the program, and it now successfully transfers various file types. Next step: implement video file transfer.&lt;/p&gt;

&lt;p&gt;server.c&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="cp"&gt;#define MAXSIZE 100
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;server_sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;client_sockfd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;server_len&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;client_len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAXSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;client_address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"server:file name&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;server_sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_sockfd&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Creating socket error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;s_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htonl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;INADDR_ANY&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;server_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOL_SOCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SO_REUSEADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_sockfd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;server_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;server_len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Bind error."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"listen error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;client_len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;client_sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server_sockfd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;client_address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;client_len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_sockfd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accept error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s"&gt;"rb"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"file open error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;feof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fread&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAXSIZE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;write&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client_sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;client.c&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/socket.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;sys/types.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netinet/in.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;arpa/inet.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdlib.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;netdb.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#define MAXSIZE 100
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;argc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;recvs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;MAXSIZE&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr_in&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;hostent&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argc&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client ip filename&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;host&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;gethostbyname&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt; &lt;span class="n"&gt;sockfd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"socket create error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;bzero&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_family&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_addr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;in_addr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;host&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;h_addr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sin_port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htons&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;setsockopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SOL_SOCKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;SO_REUSEADDR&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="n"&gt;len&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,(&lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;sockaddr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;perror&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"client"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;FILE&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fopen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="s"&gt;"wb"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"create file error!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;recvs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;MAXSIZE&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="n"&gt;fwrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;recvs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sockfd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;fclose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6752089" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6752089" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>socket</category>
      <category>networking</category>
      <category>programming</category>
      <category>linux</category>
    </item>
    <item>
      <title>Socket, Ports, and Processes Q&amp;A (Collected and Organized)</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Thu, 21 May 2026 07:14:02 +0000</pubDate>
      <link>https://dev.to/sienovoleo/socket-ports-and-processes-qa-collected-and-organized-3mkh</link>
      <guid>https://dev.to/sienovoleo/socket-ports-and-processes-qa-collected-and-organized-3mkh</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://intl.sienovo.cn/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;1. How many ports does a computer have, what are they, and what are their purposes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ports are divided into three main categories:&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Well-known Ports (0–1023):&lt;/strong&gt; These are tightly bound to specific services. Communications on these ports typically indicate a specific protocol. For example, port 80 is always used for HTTP traffic.&lt;/p&gt;

&lt;p&gt;2) &lt;strong&gt;Registered Ports (1024–49151):&lt;/strong&gt; These are loosely associated with specific services. Many services use these ports, and they may also serve other purposes. For instance, systems often begin assigning dynamic ports around 1024.&lt;/p&gt;

&lt;p&gt;3) &lt;strong&gt;Dynamic and/or Private Ports (49152–65535):&lt;/strong&gt; These should theoretically not be assigned to services. In practice, most systems assign dynamic ports starting from 1024, though exceptions exist—such as SUN's RPC ports, which start from 32768.&lt;/p&gt;

&lt;p&gt;----------------------------------------------------------------------------------------------------------------------------------&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. A computer has only one IP address but multiple distinct ports&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;An IP address identifies a host; identical IP addresses usually indicate the same machine.&lt;br&gt;&lt;br&gt;
A port identifies a process. Two processes on the same machine cannot occupy the same port simultaneously, so if ports differ, they may belong to different processes on the same host.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ports used for direct internet access typically start from &lt;strong&gt;4000&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If two QQ instances are running on the same machine, their ports are usually 4000 and 4001, respectively.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;--------------------------------------------------------------------------&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Processes and Ports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;1) &lt;strong&gt;Port Definition&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F01_0_1316656161q8Up.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F01_0_1316656161q8Up.gif" width="443" height="290"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F02_0_1316656806x9P5.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F02_0_1316656806x9P5.gif" width="439" height="307"&gt;&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;2)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F03_0_1316656371114y.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fpub-048dcb96257f476697b113fcb5939cb9.r2.dev%2Fblog%2F6799417%2F03_0_1316656371114y.gif" width="514" height="336"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3) &lt;strong&gt;Ports&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A port is a named and addressable communication endpoint in a network, representing a resource that the operating system can allocate.&lt;/p&gt;

&lt;p&gt;According to the OSI seven-layer model, the key functional difference between the transport layer and the network layer is that the transport layer provides process-to-process communication. Thus, the final destination in network communication is not just a host address, but also includes an identifier for a specific process. To address this, the TCP/IP protocol suite introduces the concept of a &lt;em&gt;protocol port&lt;/em&gt; (commonly referred to as a "port") to identify communicating processes.&lt;/p&gt;

&lt;p&gt;A port is an abstract software structure (including data structures and I/O buffers). After an application (i.e., a process) establishes a connection (binding) to a port via a system call, all data delivered by the transport layer to that port is received by the corresponding process, and all data sent by the process to the transport layer is transmitted through that port. In TCP/IP implementations, port operations resemble standard I/O operations—acquiring a port is akin to obtaining a unique local I/O file, which can be accessed using standard read/write primitives.&lt;/p&gt;

&lt;p&gt;Similar to file descriptors, each port has an integer identifier called a &lt;em&gt;port number&lt;/em&gt; to distinguish it from others. Since the TCP and UDP protocols in the TCP/IP transport layer are independent modules, their port number spaces are separate. For example, TCP can have port 255, and UDP can simultaneously have port 255 without conflict.&lt;/p&gt;

&lt;p&gt;Port number allocation is critical and follows two basic methods:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Global allocation:&lt;/strong&gt; A centralized approach where a recognized central authority assigns ports based on user needs and publishes the assignments.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local allocation (dynamic allocation):&lt;/strong&gt; A process requests a port from the local operating system, which returns a locally unique port number. The process then binds itself to this port via a system call.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TCP/IP combines both methods. It divides port numbers into two ranges: a small set of &lt;em&gt;well-known ports&lt;/em&gt; assigned globally to standard services. Thus, every standard server has a universally recognized port number (e.g., port 80 for HTTP), consistent across machines. The remaining &lt;em&gt;ephemeral ports&lt;/em&gt; are allocated locally. Both TCP and UDP reserve port numbers below 256 for well-known services.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Addressing&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In network communication, the two communicating processes reside on different machines. In an interconnected network, machines may belong to different subnets, connected via network devices (gateways, bridges, routers, etc.). Hence, a three-level addressing scheme is required:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A host may connect to multiple networks, so a specific network address must be specified.&lt;/li&gt;
&lt;li&gt;Each host on the network must have a unique address.&lt;/li&gt;
&lt;li&gt;Each process on a host must have a unique identifier within that host.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Typically, a host address consists of a network ID and a host ID, represented as a 32-bit integer in TCP/IP. Both TCP and UDP use 16-bit port numbers to identify user processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Network Byte Order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Different computers store multi-byte values in different orders—some store the least significant byte at the lowest address (little-endian), others the most significant byte (big-endian). To ensure data integrity, network protocols define a standard byte order. TCP/IP uses big-endian (most significant byte first) for 16-bit and 32-bit integers, as defined in protocol header files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Connection&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The communication link between two processes is called a &lt;em&gt;connection&lt;/em&gt;. Internally, a connection consists of buffers and protocol mechanisms; externally, it provides higher reliability than connectionless communication.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Half-association&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As discussed, a process can be uniquely identified globally by a &lt;strong&gt;triple&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;(Protocol, Local Address, Local Port Number)&lt;/p&gt;

&lt;p&gt;This triple is known as a &lt;em&gt;half-association&lt;/em&gt;, specifying one half of a connection.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Association&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A complete inter-process communication requires two processes using the same high-level protocol—e.g., both ends must use TCP or both UDP. Therefore, a full communication is identified by a &lt;strong&gt;quintuple&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;(Protocol, Local Address, Local Port, Remote Address, Remote Port)&lt;/p&gt;

&lt;p&gt;This quintuple is called an &lt;em&gt;association&lt;/em&gt;. Only two half-associations using the same protocol can form a valid association, fully specifying a connection.&lt;/p&gt;

&lt;p&gt;------------------------------------------------------------------------------------------------&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Revisiting Process-to-Port Mapping&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Creation Date: 2002-02-05&lt;br&gt;&lt;br&gt;
Article Type: Original&lt;br&gt;&lt;br&gt;
Source: &lt;a href="http://www.whitecell.org/" rel="noopener noreferrer"&gt;www.whitecell.org&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Submitted by: &lt;a href="https://www.xfocus.net/bbs/index.php?lang=cn&amp;amp;act=Profile&amp;amp;do=03&amp;amp;MID=3079" rel="noopener noreferrer"&gt;ILSY&lt;/a&gt; (masteruser_at_263.net)  &lt;/p&gt;

&lt;p&gt;Author  : ilsy&lt;br&gt;&lt;br&gt;
Email   : &lt;a href="mailto:ilsy@whitecell.org"&gt;ilsy@whitecell.org&lt;/a&gt;&lt;br&gt;&lt;br&gt;
HomePage: &lt;a href="http://www.whitecell.org/" rel="noopener noreferrer"&gt;http://www.whitecell.org&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Date    : 2002-02-06&lt;br&gt;&lt;br&gt;
Category: Security&lt;br&gt;&lt;br&gt;
Keywords: process, PDE, PTE, paging, kernel object, linear address, physical address  &lt;/p&gt;

&lt;p&gt;There are many articles on process-to-port mapping. Here, I present my analysis of &lt;em&gt;fport&lt;/em&gt;, explaining how it works.&lt;br&gt;&lt;br&gt;
&lt;em&gt;fport.exe&lt;/em&gt; is a free tool developed by the Foundstone team that lists all open ports on a system and identifies which processes opened them.&lt;br&gt;&lt;br&gt;
The method described below is based on &lt;em&gt;fport v1.33&lt;/em&gt;. If your version differs, please verify the version.  &lt;/p&gt;

&lt;p&gt;First, the tool checks whether the current user has administrative privileges (by reading the current process token). If not, it displays a warning and exits. Then, it adjusts the current process token. Next, it uses the &lt;code&gt;ZwOpenSection&lt;/code&gt; function to open the kernel object &lt;code&gt;\\Device\\PhysicalMemory&lt;/code&gt;, which allows access to physical system memory. The function prototype is as follows:  &lt;/p&gt;

&lt;p&gt;NTSYSAPI&lt;br&gt;&lt;br&gt;
NTSTATUS&lt;br&gt;&lt;br&gt;
NTAPI&lt;br&gt;&lt;br&gt;
ZwOpenSection(&lt;br&gt;&lt;br&gt;
    OUT PHANDLE SectionHandle;&lt;br&gt;&lt;br&gt;
    IN ACCESS_MASK DesiredAccess;&lt;br&gt;&lt;br&gt;
    IN POBJECT_ATTRIBUTES ObjectAttributes&lt;br&gt;&lt;br&gt;
    );&lt;br&gt;&lt;br&gt;
(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;The first parameter receives the handle upon successful execution.&lt;br&gt;&lt;br&gt;
The second parameter, &lt;code&gt;DesiredAccess&lt;/code&gt;, can be one of the following constants:&lt;br&gt;&lt;br&gt;
    #define SECTION_QUERY       0x0001&lt;br&gt;&lt;br&gt;
    #define SECTION_MAP_WRITE   0x0002&lt;br&gt;&lt;br&gt;
    #define SECTION_MAP_READ    0x0004&lt;br&gt;&lt;br&gt;
    #define SECTION_MAP_EXECUTE 0x0008&lt;br&gt;&lt;br&gt;
    #define SECTION_EXTEND_SIZE 0x0010  &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#define SECTION_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SECTION_QUERY|\\  
                        SECTION_MAP_WRITE |      \\  
                        SECTION_MAP_READ |       \\  
                        SECTION_MAP_EXECUTE |    \\  
                        SECTION_EXTEND_SIZE)  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;The third parameter is a structure containing information such as the object type to open:&lt;br&gt;&lt;br&gt;
    typedef struct _OBJECT_ATTRIBUTES {&lt;br&gt;&lt;br&gt;
        ULONG Length;&lt;br&gt;&lt;br&gt;
        HANDLE RootDirectory;&lt;br&gt;&lt;br&gt;
        PUNICODE_STRING ObjectName;&lt;br&gt;&lt;br&gt;
        ULONG Attributes;&lt;br&gt;&lt;br&gt;
        PVOID SecurityDescriptor;        // Points to type SECURITY_DESCRIPTOR&lt;br&gt;&lt;br&gt;
        PVOID SecurityQualityOfService;  // Points to type SECURITY_QUALITY_OF_SERVICE&lt;br&gt;&lt;br&gt;
    } OBJECT_ATTRIBUTES;&lt;br&gt;&lt;br&gt;
    typedef OBJECT_ATTRIBUTES *POBJECT_ATTRIBUTES;&lt;br&gt;&lt;br&gt;
(See ntdef.h)  &lt;/p&gt;

&lt;p&gt;This structure is initialized using a macro:&lt;br&gt;&lt;br&gt;
    #define InitializeObjectAttributes( p, n, a, r, s ) { \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;Length = sizeof( OBJECT_ATTRIBUTES );          \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;RootDirectory = r;                             \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;Attributes = a;                                \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;ObjectName = n;                                \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;SecurityDescriptor = s;                        \&lt;br&gt;&lt;br&gt;
        (p)-&amp;gt;SecurityQualityOfService = NULL;               \&lt;br&gt;&lt;br&gt;
        }&lt;br&gt;&lt;br&gt;
(See ntdef.h)  &lt;/p&gt;

&lt;p&gt;To open the kernel object &lt;code&gt;\\Device\\PhysicalMemory&lt;/code&gt;, the code is:&lt;br&gt;&lt;br&gt;
WCHAR    PhysmemName[] =        L"\\Device\\PhysicalMemory";&lt;br&gt;&lt;br&gt;
void *   pMapPhysicalMemory;&lt;br&gt;&lt;br&gt;
HANDLE   pHandle;  &lt;/p&gt;

&lt;p&gt;bool    OpenPhysicalMemory()&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    NTSTATUS    status;&lt;br&gt;&lt;br&gt;
    UNICODE_STRING    physmemString;&lt;br&gt;&lt;br&gt;
    OBJECT_ATTRIBUTES attributes;&lt;br&gt;&lt;br&gt;
    RtlInitUnicodeString( &amp;amp;physmemString, PhysmemName ); // Initialize Unicode string, see ntddk.h&lt;br&gt;&lt;br&gt;
    InitializeObjectAttributes( &amp;amp;attributes, &amp;amp;physmemString,&lt;br&gt;&lt;br&gt;
                         OBJ_CASE_INSENSITIVE, NULL, NULL ); // Initialize OBJECT_ATTRIBUTES&lt;br&gt;&lt;br&gt;
    status = ZwOpenSection(pHandle, SECTION_MAP_READ, &amp;amp;attributes ); // Open \Device\PhysicalMemory, get handle&lt;br&gt;&lt;br&gt;
    if( !NT_SUCCESS( status ))&lt;br&gt;&lt;br&gt;
        return false;&lt;br&gt;&lt;br&gt;
    pMapPhysicalMemory = MapViewOfFile(pHandle, FILE_MAP_READ,&lt;br&gt;&lt;br&gt;
                               0, 0x30000, 0x1000);&lt;br&gt;&lt;br&gt;
    // Map 0x1000 bytes starting from physical address 0x30000&lt;br&gt;&lt;br&gt;
    if( GetLastError() != 0 )&lt;br&gt;&lt;br&gt;
        return false;&lt;br&gt;&lt;br&gt;
    return true;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;Why start mapping from 0x30000? In Windows NT/2000, the system is divided into kernel mode (Ring 0) and user mode (Ring 3). All visible processes run in Ring 3. The physical address of the System process's Page Directory Entry (PDE) is typically 0x30000—the smallest PDE address in the system. The PDE contains 1024 entries, each pointing to a Page Table Entry (PTE). Each PTE manages 1024 pages of 4KB each. Since 1024 × 4KB = 0x1000 bytes, mapping 0x1000 bytes from 0x30000 covers one full PDE. (See WebCrazy's article "On Windows NT/2000 Paging Mechanism" for details.)  &lt;/p&gt;

&lt;p&gt;After opening &lt;code&gt;\\Device\\PhysicalMemory&lt;/code&gt;, the program uses &lt;code&gt;ZwOpenFile&lt;/code&gt; to open the kernel objects &lt;code&gt;\\Device\\Tcp&lt;/code&gt; and &lt;code&gt;\\Device\\Udp&lt;/code&gt;. The function prototype is:&lt;br&gt;&lt;br&gt;
NTSYSAPI&lt;br&gt;&lt;br&gt;
NTSTATUS&lt;br&gt;&lt;br&gt;
NTAPI&lt;br&gt;&lt;br&gt;
ZwOpenFile(&lt;br&gt;&lt;br&gt;
    OUT PHANDLE FileHandle,&lt;br&gt;&lt;br&gt;
    IN ACCESS_MASK DesiredAccess,&lt;br&gt;&lt;br&gt;
    IN POBJECT_ATTRIBUTES ObjectAttributes,&lt;br&gt;&lt;br&gt;
    OUT PIO_STATUS_BLOCK IoStatusBlock,&lt;br&gt;&lt;br&gt;
    IN ULONG ShareAccess,&lt;br&gt;&lt;br&gt;
    IN ULONG OpenOptions&lt;br&gt;&lt;br&gt;
    );&lt;br&gt;&lt;br&gt;
(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;The first parameter returns the handle to the opened object.&lt;br&gt;&lt;br&gt;
The second parameter, &lt;code&gt;DesiredAccess&lt;/code&gt;, can be:&lt;br&gt;&lt;br&gt;
    #define FILE_READ_DATA            ( 0x0001 )    // file &amp;amp; pipe&lt;br&gt;&lt;br&gt;
    #define FILE_LIST_DIRECTORY       ( 0x0001 )    // directory&lt;br&gt;&lt;br&gt;
    #define FILE_WRITE_DATA           ( 0x0002 )    // file &amp;amp; pipe&lt;br&gt;&lt;br&gt;
    #define FILE_ADD_FILE             ( 0x0002 )    // directory&lt;br&gt;&lt;br&gt;
    #define FILE_APPEND_DATA          ( 0x0004 )    // file&lt;br&gt;&lt;br&gt;
    #define FILE_ADD_SUBDIRECTORY     ( 0x0004 )    // directory&lt;br&gt;&lt;br&gt;
    #define FILE_CREATE_PIPE_INSTANCE ( 0x0004 )    // named pipe&lt;br&gt;&lt;br&gt;
    #define FILE_READ_EA              ( 0x0008 )    // file &amp;amp; directory&lt;br&gt;&lt;br&gt;
    #define FILE_WRITE_EA             ( 0x0010 )    // file &amp;amp; directory&lt;br&gt;&lt;br&gt;
    #define FILE_EXECUTE              ( 0x0020 )    // file&lt;br&gt;&lt;br&gt;
    #define FILE_TRAVERSE             ( 0x0020 )    // directory&lt;br&gt;&lt;br&gt;
    #define FILE_DELETE_CHILD         ( 0x0040 )    // directory&lt;br&gt;&lt;br&gt;
    #define FILE_READ_ATTRIBUTES      ( 0x0080 )    // all&lt;br&gt;&lt;br&gt;
    #define FILE_WRITE_ATTRIBUTES     ( 0x0100 )    // all&lt;br&gt;&lt;br&gt;
    #define FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)&lt;br&gt;&lt;br&gt;
    #define FILE_GENERIC_READ         (STANDARD_RIGHTS_READ     |\&lt;br&gt;&lt;br&gt;
                                   FILE_READ_DATA           |\&lt;br&gt;&lt;br&gt;
                                   FILE_READ_ATTRIBUTES     |\&lt;br&gt;&lt;br&gt;
                                   FILE_READ_EA             |\&lt;br&gt;&lt;br&gt;
                                   SYNCHRONIZE)&lt;br&gt;&lt;br&gt;
    #define FILE_GENERIC_WRITE        (STANDARD_RIGHTS_WRITE    |\&lt;br&gt;&lt;br&gt;
                                   FILE_WRITE_DATA          |\&lt;br&gt;&lt;br&gt;
                                   FILE_WRITE_ATTRIBUTES    |\&lt;br&gt;&lt;br&gt;
                                   FILE_WRITE_EA            |\&lt;br&gt;&lt;br&gt;
                                   FILE_APPEND_DATA         |\&lt;br&gt;&lt;br&gt;
                                   SYNCHRONIZE)&lt;br&gt;&lt;br&gt;
    #define FILE_GENERIC_EXECUTE      (STANDARD_RIGHTS_EXECUTE  |\&lt;br&gt;&lt;br&gt;
                                   FILE_READ_ATTRIBUTES     |\&lt;br&gt;&lt;br&gt;
                                   FILE_EXECUTE             |\&lt;br&gt;&lt;br&gt;
                                   SYNCHRONIZE)&lt;br&gt;&lt;br&gt;
(See ntdef.h)  &lt;/p&gt;

&lt;p&gt;The third parameter is the same structure as above.&lt;br&gt;&lt;br&gt;
The fourth parameter returns object attributes in an &lt;code&gt;IO_STATUS_BLOCK&lt;/code&gt; structure:&lt;br&gt;&lt;br&gt;
    typedef struct _IO_STATUS_BLOCK {&lt;br&gt;&lt;br&gt;
        union {&lt;br&gt;&lt;br&gt;
            NTSTATUS Status;&lt;br&gt;&lt;br&gt;
            PVOID Pointer;&lt;br&gt;&lt;br&gt;
        };&lt;br&gt;&lt;br&gt;
        ULONG_PTR Information;&lt;br&gt;&lt;br&gt;
    } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;&lt;br&gt;&lt;br&gt;
    #if defined(_WIN64)&lt;br&gt;&lt;br&gt;
    typedef struct _IO_STATUS_BLOCK32 {&lt;br&gt;&lt;br&gt;
        NTSTATUS Status;&lt;br&gt;&lt;br&gt;
        ULONG Information;&lt;br&gt;&lt;br&gt;
    } IO_STATUS_BLOCK32, *PIO_STATUS_BLOCK32;&lt;br&gt;&lt;br&gt;
    #endif&lt;br&gt;&lt;br&gt;
(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;The fifth parameter, &lt;code&gt;ShareAccess&lt;/code&gt;, can be:&lt;br&gt;&lt;br&gt;
    #define FILE_SHARE_READ           0x00000001  // winnt&lt;br&gt;&lt;br&gt;
    #define FILE_SHARE_WRITE          0x00000002  // winnt&lt;br&gt;&lt;br&gt;
    #define FILE_SHARE_DELETE         0x00000004  // winnt&lt;br&gt;&lt;br&gt;
(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;The sixth parameter, &lt;code&gt;OpenOptions&lt;/code&gt;, can be:&lt;br&gt;&lt;br&gt;
    #define FILE_DIRECTORY_FILE                 0x00000001&lt;br&gt;&lt;br&gt;
    #define FILE_WRITE_THROUGH                  0x00000002&lt;br&gt;&lt;br&gt;
    #define FILE_SEQUENTIAL_ONLY                0x00000004&lt;br&gt;&lt;br&gt;
    #define FILE_NO_INTERMEDIATE_BUFFERING      0x00000008&lt;br&gt;&lt;br&gt;
    #define FILE_SYNCHRONOUS_IO_ALERT           0x00000010&lt;br&gt;&lt;br&gt;
    #define FILE_SYNCHRONOUS_IO_NONALERT        0x00000020&lt;br&gt;&lt;br&gt;
    #define FILE_NON_DIRECTORY_FILE             0x00000040&lt;br&gt;&lt;br&gt;
    #define FILE_CREATE_TREE_CONNECTION         0x00000080&lt;br&gt;&lt;br&gt;
    #define FILE_COMPLETE_IF_OPLOCKED           0x00000100&lt;br&gt;&lt;br&gt;
    #define FILE_NO_EA_KNOWLEDGE                0x00000200&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_FOR_RECOVERY              0x00000400&lt;br&gt;&lt;br&gt;
    #define FILE_RANDOM_ACCESS                  0x00000800&lt;br&gt;&lt;br&gt;
    #define FILE_DELETE_ON_CLOSE                0x00001000&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_BY_FILE_ID                0x00002000&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_FOR_BACKUP_INTENT         0x00004000&lt;br&gt;&lt;br&gt;
    #define FILE_NO_COMPRESSION                 0x00008000&lt;br&gt;&lt;br&gt;
    #define FILE_RESERVE_OPFILTER               0x00100000&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_REPARSE_POINT             0x00200000&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_NO_RECALL                 0x00400000&lt;br&gt;&lt;br&gt;
    #define FILE_OPEN_FOR_FREE_SPACE_QUERY      0x00800000&lt;br&gt;&lt;br&gt;
    #define FILE_COPY_STRUCTURED_STORAGE        0x00000041&lt;br&gt;&lt;br&gt;
    #define FILE_STRUCTURED_STORAGE             0x00000441&lt;br&gt;&lt;br&gt;
    #define FILE_VALID_OPTION_FLAGS             0x00ffffff&lt;br&gt;&lt;br&gt;
    #define FILE_VALID_PIPE_OPTION_FLAGS        0x00000032&lt;br&gt;&lt;br&gt;
    #define FILE_VALID_MAILSLOT_OPTION_FLAGS    0x00000032&lt;br&gt;&lt;br&gt;
    #define FILE_VALID_SET_FLAGS                0x00000036&lt;br&gt;&lt;br&gt;
(See ntddk.h)  &lt;/p&gt;

&lt;p&gt;To open &lt;code&gt;\\Device\\Tcp&lt;/code&gt; and &lt;code&gt;\\Device\\Udp&lt;/code&gt;:&lt;br&gt;&lt;br&gt;
WCHAR physmemNameTcp[] = L"\\Device\\TCP";&lt;br&gt;&lt;br&gt;
WCHAR physmemNameUdp[] = L"\\Device\\UDP";&lt;br&gt;&lt;br&gt;
HANDLE pTcpHandle;&lt;br&gt;&lt;br&gt;
HANDLE pUdpHandle;  &lt;/p&gt;

&lt;p&gt;HANDLE OpenDeviceTcpUdp(WCHAR * deviceName)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    NTSTATUS    status;&lt;br&gt;&lt;br&gt;
    UNICODE_STRING    physmemString;&lt;br&gt;&lt;br&gt;
    OBJECT_ATTRIBUTES attributes;&lt;br&gt;&lt;br&gt;
    IO_STATUS_BLOCK iosb;&lt;br&gt;&lt;br&gt;
    HANDLE pDeviceHandle;&lt;br&gt;&lt;br&gt;
    RtlInitUnicodeString(&amp;amp;physmemString, deviceName);&lt;br&gt;&lt;br&gt;
    if(GetLastError() != 0)&lt;br&gt;&lt;br&gt;
        return NULL;&lt;br&gt;&lt;br&gt;
    InitializeObjectAttributes( &amp;amp;attributes, &amp;amp;physmemString,&lt;br&gt;&lt;br&gt;
                            OBJ_CASE_INSENSITIVE, 0, NULL );&lt;br&gt;&lt;br&gt;
    status = ZwOpenFile( &amp;amp;pDeviceHandle, 0x100000, &amp;amp;attributes, &amp;amp;iosb, 3, 0 );&lt;br&gt;&lt;br&gt;
    if( !NT_SUCCESS( status ))&lt;br&gt;&lt;br&gt;
        return NULL;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;Next, the program uses &lt;code&gt;ZwQuerySystemInformation&lt;/code&gt; to retrieve all handles and related information for currently running processes. The function prototype is:&lt;br&gt;&lt;br&gt;
NTSYSAPI&lt;br&gt;&lt;br&gt;
NTSTATUS&lt;br&gt;&lt;br&gt;
NTAPI&lt;br&gt;&lt;br&gt;
ZwQuerySystemInformation(&lt;br&gt;&lt;br&gt;
    IN SYSTEM_INFORMATION_CLASS SystemInformationClass,&lt;br&gt;&lt;br&gt;
    IN OUT PVOID SystemInformation,&lt;br&gt;&lt;br&gt;
    IN ULONG SystemInformationLength,&lt;br&gt;&lt;br&gt;
    OUT PULONG ReturnLength OPTIONAL&lt;br&gt;&lt;br&gt;
    );&lt;br&gt;&lt;br&gt;
(This function structure is not publicly documented by Microsoft; see Gary Nebbett's "Windows NT/2000 Native API Reference".)  &lt;/p&gt;

&lt;p&gt;The first parameter is an enumeration specifying the system information type. &lt;code&gt;ZwQuerySystemInformation&lt;/code&gt; supports 54 types; we use type 16, &lt;code&gt;SystemHandleInformation&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
The &lt;code&gt;SYSTEM_HANDLE_INFORMATION&lt;/code&gt; structure is defined as:&lt;br&gt;&lt;br&gt;
    typedef struct _SYSTEM_HANDLE_INFORMATION {&lt;br&gt;&lt;br&gt;
        ULONG ProcessID;            // Process identifier&lt;br&gt;&lt;br&gt;
        UCHAR ObjectTypeNumber;     // Object type&lt;br&gt;&lt;br&gt;
        UCHAR Flags;                // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT&lt;br&gt;&lt;br&gt;
        USHORT Handle;              // Handle value&lt;br&gt;&lt;br&gt;
        PVOID  Object;              // Kernel object address pointed to by handle&lt;br&gt;&lt;br&gt;
        ACCESS_MASK GrantedAccess;  // Access rights granted when handle was created&lt;br&gt;&lt;br&gt;
    } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;&lt;br&gt;&lt;br&gt;
(Not publicly documented; see Nebbett's book.)  &lt;/p&gt;

&lt;p&gt;The second parameter outputs the query result.&lt;br&gt;&lt;br&gt;
The third sets the buffer size.&lt;br&gt;&lt;br&gt;
The fourth returns the required buffer size if the call fails due to insufficient buffer.  &lt;/p&gt;

&lt;p&gt;Code:  &lt;/p&gt;

&lt;h1&gt;
  
  
  define SystemHandleInformation 16
&lt;/h1&gt;

&lt;p&gt;PULONG GetHandleList()&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    ULONG cbBuffer = 0x1000;&lt;br&gt;&lt;br&gt;
    PULONG pBuffer = new ULONG[cbBuffer];&lt;br&gt;&lt;br&gt;
    NTSTATUS Status;&lt;br&gt;&lt;br&gt;
    do {&lt;br&gt;&lt;br&gt;
        Status = ZwQuerySystemInformation(&lt;br&gt;&lt;br&gt;
                    SystemHandleInformation,&lt;br&gt;&lt;br&gt;
                    pBuffer, cbBuffer * sizeof * pBuffer, NULL);&lt;br&gt;&lt;br&gt;
        if (Status == STATUS_INFO_LENGTH_MISMATCH) {&lt;br&gt;&lt;br&gt;
            delete [] pBuffer;&lt;br&gt;&lt;br&gt;
            pBuffer = new ULONG[cbBuffer *= 2];&lt;br&gt;&lt;br&gt;
        }&lt;br&gt;&lt;br&gt;
        else if (!NT_SUCCESS(Status)) {&lt;br&gt;&lt;br&gt;
            delete [] pBuffer;&lt;br&gt;&lt;br&gt;
            return NULL;&lt;br&gt;&lt;br&gt;
        }&lt;br&gt;&lt;br&gt;
    } while (Status == STATUS_INFO_LENGTH_MISMATCH);&lt;br&gt;&lt;br&gt;
    return pBuffer;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;If a process opens a port, it must have created kernel objects of type &lt;code&gt;\\Device\\Tcp&lt;/code&gt; or &lt;code&gt;\\Device\\Udp&lt;/code&gt;. By opening these objects ourselves and saving their handles, we can search the handle list for entries matching our saved handles, then retrieve the corresponding kernel object addresses. Code:&lt;br&gt;&lt;br&gt;
DWORD TcpHandle;&lt;br&gt;&lt;br&gt;
DWORD UdpHandle;&lt;br&gt;&lt;br&gt;
DWORD GetTcpUdpObject(PULONG pBuffer, HANDLE pHandle, DWORD ProcessId)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    DWORD objTYPE1, objTYPE2, HandleObject;&lt;br&gt;&lt;br&gt;
    PSYSTEM_HANDLE_INFORMATION pProcesses = (PSYSTEM_HANDLE_INFORMATION)(pBuffer + 1);&lt;br&gt;&lt;br&gt;
    for (i = 0; i &amp;lt; *pBuffer; i++) {&lt;br&gt;&lt;br&gt;
        if ((pProcesses[i].ProcessID) == ProcessId) {&lt;br&gt;&lt;br&gt;
            objTYPE1 = (DWORD)hDeviceTcpUdp;&lt;br&gt;&lt;br&gt;
            objTYPE2 = (DWORD)pProcesses[i].Handle;&lt;br&gt;&lt;br&gt;
            if (objTYPE1 == objTYPE2) {&lt;br&gt;&lt;br&gt;
                HandleObject = (DWORD)pProcesses[i].Object;&lt;br&gt;&lt;br&gt;
                return HandleObject;&lt;br&gt;&lt;br&gt;
            }&lt;br&gt;&lt;br&gt;
        }&lt;br&gt;&lt;br&gt;
    }&lt;br&gt;&lt;br&gt;
    return 0;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;This kernel object address is a linear (virtual) address. We must convert it to a physical address and extract relevant data. In &lt;em&gt;fport&lt;/em&gt;, the conversion is done as follows:&lt;br&gt;&lt;br&gt;
(See WebCrazy's article for details.)&lt;br&gt;&lt;br&gt;
void * NewmapPhy;  &lt;/p&gt;

&lt;p&gt;void GetPTE(DWORD objAddress)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    DWORD physmemBuff;&lt;br&gt;&lt;br&gt;
    DWORD newAddress1, newAddress2, newAddress3, newAddress4;&lt;br&gt;&lt;br&gt;
    DWORD * newAddress;&lt;br&gt;&lt;br&gt;
    physmemBuff = (DWORD)pMapPhysicalMemory;&lt;br&gt;&lt;br&gt;
    newAddress1 = physmemBuff + (objAddress &amp;gt;&amp;gt; 0x16) * 4;&lt;br&gt;&lt;br&gt;
    newAddress = (DWORD *)newAddress1;&lt;br&gt;&lt;br&gt;
    newAddress1 = *newAddress;&lt;br&gt;&lt;br&gt;
    newAddress2 = objAddress &amp;amp; 0x3FF000;&lt;br&gt;&lt;br&gt;
    newAddress3 = newAddress1 &amp;amp; 0x0FFFFF000;&lt;br&gt;&lt;br&gt;
    newAddress4 = newAddress2 + newAddress3;&lt;br&gt;&lt;br&gt;
    NewmapPhy = MapViewOfFile(ghPhysicalMemory, FILE_MAP_READ, 0, newAddress4, 0x1000);&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;Next, we retrieve the physical page corresponding to the linear address and access the page containing the kernel object data. The PTE structure is:&lt;br&gt;&lt;br&gt;
typedef struct {&lt;br&gt;&lt;br&gt;
    ULONG Present;&lt;br&gt;&lt;br&gt;
    ULONG WriteTable;&lt;br&gt;&lt;br&gt;
    ULONG User;&lt;br&gt;&lt;br&gt;
    ULONG WriteThru;&lt;br&gt;&lt;br&gt;
    ULONG NoCache;&lt;br&gt;&lt;br&gt;
    ULONG Accessed;&lt;br&gt;&lt;br&gt;
    ULONG Dirty;&lt;br&gt;&lt;br&gt;
    ULONG PageSize;&lt;br&gt;&lt;br&gt;
    ULONG Global;&lt;br&gt;&lt;br&gt;
    ULONG Available;&lt;br&gt;&lt;br&gt;
    ULONG Pfn;&lt;br&gt;&lt;br&gt;
} PTE, *PPTE;&lt;br&gt;&lt;br&gt;
(Note: This structure may not be fully accurate, but it suffices for our purposes.)  &lt;/p&gt;

&lt;p&gt;Code:&lt;br&gt;&lt;br&gt;
ULONG CurrWriteTable;&lt;br&gt;&lt;br&gt;
ULONG CurrNoCache;  &lt;/p&gt;

&lt;p&gt;void GetMustPar(DWORD objAddress)&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    DWORD CurrAddress = objAddress &amp;amp; 0xFFF;&lt;br&gt;&lt;br&gt;
    PPTE pte = (PPTE)((DWORD)NewmapPhy + CurrAddress);&lt;br&gt;&lt;br&gt;
    CurrWriteTable = pte-&amp;gt;WriteTable;&lt;br&gt;&lt;br&gt;
    CurrNoCache = pte-&amp;gt;NoCache;&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;Now we have all necessary data. The next step is to iterate through all processes and their handles. (Note: Not all handles—on Windows NT, &lt;code&gt;\\Device\\Tcp&lt;/code&gt; and &lt;code&gt;\\Device\\Udp&lt;/code&gt; have object type 0x16; on Windows 2000, it's 0x1A.) For each such handle, we use the above method to retrieve its PTE and &lt;code&gt;WriteTable&lt;/code&gt; value. If it matches that of &lt;code&gt;\\Device\\Tcp&lt;/code&gt; or &lt;code&gt;\\Device\\Udp&lt;/code&gt;, the handle likely represents an open port. We then confirm it. Confirmation code:&lt;br&gt;&lt;br&gt;
typedef struct _TDI_CONNECTION_INFO {&lt;br&gt;&lt;br&gt;
    ULONG          State;&lt;br&gt;&lt;br&gt;
    ULONG          Event;&lt;br&gt;&lt;br&gt;
    ULONG          TransmittedTsdus;&lt;br&gt;&lt;br&gt;
    ULONG          ReceivedTsdus;&lt;br&gt;&lt;br&gt;
    ULONG          TransmissionErrors;&lt;br&gt;&lt;br&gt;
    ULONG          ReceiveErrors;&lt;br&gt;&lt;br&gt;
    LARGE_INTEGER  Throughput;&lt;br&gt;&lt;br&gt;
    LARGE_INTEGER  Delay;&lt;br&gt;&lt;br&gt;
    ULONG          SendBufferSize;&lt;br&gt;&lt;br&gt;
    ULONG          ReceiveBufferSize;&lt;br&gt;&lt;br&gt;
    BOOLEAN        Unreliable;&lt;br&gt;&lt;br&gt;
} TDI_CONNECTION_INFO, *PTDI_CONNECTION_INFO;  &lt;/p&gt;

&lt;p&gt;typedef struct _TDI_CONNECTION_INFORMATION {&lt;br&gt;&lt;br&gt;
    LONG   UserDataLength;&lt;br&gt;&lt;br&gt;
    PVOID  UserData;&lt;br&gt;&lt;br&gt;
    LONG   OptionsLength;&lt;br&gt;&lt;br&gt;
    PVOID  Options;&lt;br&gt;&lt;br&gt;
    LONG   RemoteAddressLength;&lt;br&gt;&lt;br&gt;
    PVOID  RemoteAddress;&lt;br&gt;&lt;br&gt;
} TDI_CONNECTION_INFORMATION, *PTDI_CONNECTION_INFORMATION;&lt;br&gt;&lt;br&gt;
(See tdi.h)  &lt;/p&gt;

&lt;p&gt;void GetOpenPort(DWORD dwProcessesID, USHORT Handle, int NoCache)&lt;br&gt;&lt;br&gt;
// dwProcessesID: Process ID&lt;br&gt;&lt;br&gt;
// Handle: Handle of type \Device\Tcp or \Device\Udp&lt;br&gt;&lt;br&gt;
// NoCache: Value from PTE structure&lt;br&gt;&lt;br&gt;
{&lt;br&gt;&lt;br&gt;
    HANDLE hProc, DupHandle = NULL;&lt;br&gt;&lt;br&gt;
    HANDLE hEven = NULL;&lt;br&gt;&lt;br&gt;
    OVERLAPPED overlap;&lt;br&gt;&lt;br&gt;
    u_short openport;&lt;br&gt;&lt;br&gt;
    int i = 0;&lt;br&gt;&lt;br&gt;
    char procName[256] = {0};&lt;br&gt;&lt;br&gt;
    int portflag = 0;&lt;br&gt;&lt;br&gt;
    overlap.Internal = 0;&lt;br&gt;&lt;br&gt;
    overlap.InternalHigh = 0;&lt;br&gt;&lt;br&gt;
    overlap.Offset = 0;&lt;br&gt;&lt;br&gt;
    overlap.OffsetHigh = 0;&lt;br&gt;&lt;br&gt;
    hEven = CreateEvent(0, 1, 0, 0);&lt;br&gt;&lt;br&gt;
    overlap.hEvent = hEven;&lt;br&gt;&lt;br&gt;
    hProc = OpenProcess(PROCESS_DUP_HANDLE, 0, dwProcessesID);&lt;br&gt;&lt;br&gt;
    if (hProc) {&lt;br&gt;&lt;br&gt;
        DuplicateHandle(hProc, (HANDLE)Handle, GetCurrentProcess(), &amp;amp;DupHandle, 0, FALSE, 2);&lt;br&gt;&lt;br&gt;
        CloseHandle(hProc);&lt;br&gt;&lt;br&gt;
        if (DupHandle) {&lt;br&gt;&lt;br&gt;
            TDI_CONNECTION_INFO TdiConnInfo = {0};&lt;br&gt;&lt;br&gt;
            TDI_CONNECTION_INFORMATION TdiConnInformation = {0};&lt;br&gt;&lt;br&gt;
            DWORD dwRetu = 0;&lt;br&gt;&lt;br&gt;
            if (NoCache == 0x2) {&lt;br&gt;&lt;br&gt;
                TdiConnInformation.RemoteAddressLength = 4;&lt;br&gt;&lt;br&gt;
                if (DeviceIoControl(DupHandle, 0x210012,&lt;br&gt;&lt;br&gt;
                            &amp;amp;TdiConnInformation, sizeof(TdiConnInformation),&lt;br&gt;&lt;br&gt;
                            &amp;amp;TdiConnInfo, sizeof(TdiConnInfo), 0, &amp;amp;overlap)) {&lt;br&gt;&lt;br&gt;
                    openport = ntohs((u_short)TdiConnInfo.ReceivedTsdus);&lt;br&gt;&lt;br&gt;
                    procName = GetProcName(dwProcessesID);&lt;br&gt;&lt;br&gt;
                    printf("PID = %4d ProcessName = %15s PORT = %4d\n", dwProcessesID, procName, openport);&lt;br&gt;&lt;br&gt;
                }&lt;br&gt;&lt;br&gt;
            }&lt;br&gt;&lt;br&gt;
            if (NoCache == 0x1) {&lt;br&gt;&lt;br&gt;
                TdiConnInformation.RemoteAddressLength = 3;&lt;br&gt;&lt;br&gt;
                if (DeviceIoControl(DupHandle, 0x210012,&lt;br&gt;&lt;br&gt;
                            &amp;amp;TdiConnInformation, sizeof(TdiConnInformation),&lt;br&gt;&lt;br&gt;
                            &amp;amp;TdiConnInfo, sizeof(TdiConnInfo), 0, &amp;amp;overlap)) {&lt;br&gt;&lt;br&gt;
                    openport = ntohs((u_short)TdiConnInfo.ReceivedTsdus);&lt;br&gt;&lt;br&gt;
                    procName = GetProcName(dwProcessesID);&lt;br&gt;&lt;br&gt;
                    printf("PID = %4d ProcessName = %15s PORT = %4d\n", dwProcessesID, procName, openport);&lt;br&gt;&lt;br&gt;
                }&lt;br&gt;&lt;br&gt;
            }&lt;br&gt;&lt;br&gt;
        }&lt;br&gt;&lt;br&gt;
    }&lt;br&gt;&lt;br&gt;
    CloseHandle(hEven);&lt;br&gt;&lt;br&gt;
    CloseHandle(DupHandle);&lt;br&gt;&lt;br&gt;
}  &lt;/p&gt;

&lt;p&gt;The above is my analysis and implementation code for &lt;em&gt;fport.exe&lt;/em&gt;. The demo program is available for download from whitecell.org. If you find any issues, please let me know. ^_^  &lt;/p&gt;

&lt;p&gt;References:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;fport.exe
&lt;/li&gt;
&lt;li&gt;Gary Nebbett, &lt;em&gt;Windows NT/2000 Native API Reference&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;WebCrazy, &lt;em&gt;On Windows NT/2000 Paging Mechanism&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;NTDDK
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;About Us:  &lt;/p&gt;

&lt;p&gt;WSS (Whitecell Security Systems) is a non-profit, grassroots technical organization dedicated to research in system security. We uphold traditional hacker ethics and strive for technical excellence.  &lt;/p&gt;

&lt;p&gt;WSS Homepage: &lt;a href="http://www.whitecell.org/" rel="noopener noreferrer"&gt;http://www.whitecell.org/&lt;/a&gt;  &lt;/p&gt;

&lt;h2&gt;
  
  
  WSS Forum: &lt;a href="http://www.whitecell.org/forum/" rel="noopener noreferrer"&gt;http://www.whitecell.org/forum/&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://intl.sienovo.cn/blog/6799417" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6799417" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://intl.sienovo.cn" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>socket</category>
      <category>attributes</category>
      <category>file</category>
      <category>networking</category>
    </item>
    <item>
      <title>Comprehensive Guide to Linux Processes, Signals, IPC, and gprof Usage (Reprinted)</title>
      <dc:creator>Leo Liu</dc:creator>
      <pubDate>Sun, 17 May 2026 06:56:14 +0000</pubDate>
      <link>https://dev.to/sienovoleo/comprehensive-guide-to-linux-processes-signals-ipc-and-gprof-usage-reprinted-516h</link>
      <guid>https://dev.to/sienovoleo/comprehensive-guide-to-linux-processes-signals-ipc-and-gprof-usage-reprinted-516h</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published on the &lt;a href="https://sienovo.jytech.us/blog" rel="noopener noreferrer"&gt;Sienovo Engineering Blog&lt;/a&gt;. Sienovo is the overseas brand of 深圳信迈 (Shenzhen Xinmai), building edge AI computing solutions for industrial video analytics.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;Comprehensive Guide to Linux Processes, Signals, IPC, and gprof Usage (Reprinted)&lt;/p&gt;

&lt;p&gt;Source: ChinaUnix Blog　Date: 2008.03.14 15:48　(Comments: ) &lt;a href="http://linux.chinaunix.net/bbs/thread-983262-1-1.html" rel="noopener noreferrer"&gt;Comment here&lt;/a&gt; Thanks to 007xiong, Hoyt, and others. This article is excellent. Concerned that the original link might disappear someday, I'm making a backup here. Original link:&lt;br&gt;&lt;br&gt;
&lt;a href="http://www.mwjx.com/aboutfish/private/book/linux_c.txt" rel="noopener noreferrer"&gt;http://www.mwjx.com/aboutfish/private/book/linux_c.txt&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Introduction to C Programming under Linux&lt;br&gt;&lt;br&gt;
Compiled and written by: 007xiong&lt;br&gt;&lt;br&gt;
Original: Hoyt et al.&lt;br&gt;&lt;br&gt;
(1) Table of Contents&lt;br&gt;&lt;br&gt;
1) Introduction to Linux Program Design -- Basics&lt;br&gt;&lt;br&gt;
2) Introduction to Linux Program Design -- Processes&lt;br&gt;&lt;br&gt;
3) Introduction to Linux Program Design -- File Operations&lt;br&gt;&lt;br&gt;
4) Introduction to Linux Program Design -- Time Concepts&lt;br&gt;&lt;br&gt;
5) Introduction to Linux Program Design -- Signal Handling&lt;br&gt;&lt;br&gt;
6) Introduction to Linux Program Design -- Message Management&lt;br&gt;&lt;br&gt;
7) Introduction to Linux Program Design -- Thread Operations&lt;br&gt;&lt;br&gt;
8) Introduction to Linux Program Design -- Network Programming&lt;br&gt;&lt;br&gt;
9) Introduction to C Development Tools under Linux&lt;br&gt;&lt;br&gt;
(2) Detailed Content&lt;br&gt;&lt;br&gt;
1) Introduction to Linux Program Design -- Basics&lt;br&gt;&lt;br&gt;
Fundamentals of C Programming under Linux&lt;br&gt;&lt;br&gt;
Preface:&lt;br&gt;&lt;br&gt;
This article introduces the foundational knowledge required for C programming under Linux. In this article, we will learn:&lt;br&gt;&lt;br&gt;
Source code compilation&lt;br&gt;&lt;br&gt;
Writing Makefiles&lt;br&gt;&lt;br&gt;
Linking program libraries&lt;br&gt;&lt;br&gt;
Program debugging&lt;br&gt;&lt;br&gt;
Header files and system help&lt;br&gt;&lt;br&gt;
----------------------------------------------------------------------------&lt;br&gt;&lt;br&gt;
----  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Source Code Compilation
Under Linux, to compile a C source program, we use the GNU gcc compiler. Let's illustrate how to use gcc with an example.
Suppose we have the following very simple source program (hello.c):
int main(int argc,char **argv)
{
printf("Hello Linux\n");
}
To compile this program, simply execute the following command:
gcc -o hello hello.c
The gcc compiler will generate an executable file named hello. Running ./hello will display the program's output. In the command line, gcc indicates we are using gcc to compile our source code, the -o option specifies that we want the output executable file to be named hello, and hello.c is our source file.
The gcc compiler has many options, but generally, knowing just a few is sufficient. We already know the -o option, which specifies the desired name of the output executable file. The -c option means we only want the compiler to output object code without generating an executable file. The -g option tells the compiler to include debugging information for later program debugging.
Knowing these three options enables you to compile simple source programs you write. If you want to know more options, refer to gcc's help documentation, which provides detailed explanations of other options.
&lt;/li&gt;
&lt;li&gt;Writing Makefiles
Suppose we have the following program with the source code below:
/* main.c */
#include "mytool1.h"
#include "mytool2.h"
int main(int argc,char **argv)
{
mytool1_print("hello");
mytool2_print("hello");
}
/* mytool1.h */
#ifndef _MYTOOL_1_H
#define _MYTOOL_1_H
void mytool1_print(char *print_str);
#endif
/* mytool1.c */
#include "mytool1.h"
void mytool1_print(char *print_str)
{
printf("This is mytool1 print %s\n",print_str);
}
/* mytool2.h */
#ifndef _MYTOOL_2_H
#define _MYTOOL_2_H
void mytool2_print(char *print_str);
#endif
/* mytool2.c */
#include "mytool2.h"
void mytool2_print(char *print_str)
{
printf("This is mytool2 print %s\n",print_str);
}
Of course, since this program is very short, we could compile it like this:
gcc -c main.c
gcc -c mytool1.c
gcc -c mytool2.c
gcc -o main main.o mytool1.o mytool2.o
This way, we can also generate the main program, and it's not too troublesome. But what if one day we modify one of the files (say, mytool1.c)? Would we have to re-enter the above commands? You might say this is easy to solve—just write a SHELL script to do it. Yes, for this program, that would work. But if we think more complexly, what if our program has hundreds of source files? Would we still have the compiler recompile each one individually?
To solve this, clever programmers invented a great tool: make. By simply running make, we can resolve the above issue. Before running make, we must first write a very important file—Makefile. A possible Makefile for the above program is:
# This is the Makefile for the program above
main:main.o mytool1.o mytool2.o
gcc -o main main.o mytool1.o mytool2.o
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
mytool1.o:mytool1.c mytool1.h
gcc -c mytool1.c
mytool2.o:mytool2.c mytool2.h
gcc -c mytool2.c
With this Makefile, no matter which source file we modify, running the make command will cause the compiler to compile only the files related to the modified file; it won't bother with the others.
Next, let's learn how to write a Makefile.
Lines starting with # in a Makefile are comments. The most important part of a Makefile is the dependency description. The general format is:
target: components
TAB rule
The first line indicates the dependency relationship. The second line is the rule.
For example, the second line of our Makefile above:
main:main.o mytool1.o mytool2.o
indicates that the target (main) depends on the components (main.o, mytool1.o, mytool2.o). When a dependent object is modified after the target, the command specified in the rule line must be executed. As stated in the third line of our Makefile, execute gcc -o main main.o mytool1.o mytool2.o.
Note: The TAB in the rule line represents an actual TAB key.
Makefiles have three very useful variables: $@, $&amp;lt;, and $^. $@ represents the target file, $&amp;lt; represents the first dependent file, and $^ represents all dependent files. For example, in the rule:
main.o:main.c mytool1.h mytool2.h
gcc -c main.c
$@ is main.o, $&amp;lt; is main.c, and $^ is main.c mytool1.h mytool2.h.
&lt;/li&gt;
&lt;li&gt;Program Libraries
After writing a program, we often need to link it with standard libraries. For example, the following program:
#include 
#include 
int main(int argc,char **argv)
{
double value;
printf("Value:%f\n",value);
}
This program is quite simple, but when we compile it with gcc -o temp temp.c, the following error appears:
/tmp/cc33Kydu.o: In function &lt;code&gt;main':  
/tmp/cc33Kydu.o(.text+0xe): undefined reference to \&lt;/code&gt;log'
collect2: ld returned 1 exit status
This error occurs because the compiler cannot find the specific implementation of log. Although we included the correct header file, we still need to link the appropriate library during compilation. Under Linux, to use mathematical functions, we must link with the math library, so we need to add the -lm option. Using gcc -o temp temp.c -lm will compile correctly. Someone might ask, why didn't we need to link a library when using printf earlier? The reason is that for some commonly used functions, the gcc compiler automatically links certain standard libraries, so we don't need to specify them ourselves. Sometimes, when compiling a program, we also need to specify the library path, in which case we use the compiler's -L option to specify the path. For example, if we have a library in /home/hoyt/mylib, we need to add -L/home/hoyt/mylib during compilation. For standard libraries, we don't need to specify the path as long as they are in the default library paths. The system's default library paths are /lib, /usr/lib, and /usr/local/lib. Libraries in these three paths can be used without specifying the path.
Another issue: sometimes we use a function but don't know the library name. What should we do then? Unfortunately, I don't know the answer to this question either. I only have a crude method. First, I look in the standard library paths for a library related to the function I'm using. This is how I found the library file (libpthread.a) for thread functions. Of course, if I can't find it, there's only one clumsy method. For example, to find the library containing the sin function, I can only use the command nm -o /lib/*.so|grep sin&amp;gt;~/sin, then look in the ~/sin file. In the sin file, I find a line like libm-2.1.2.so:00009fa0 W sin, which tells me that sin is in the libm-2.1.2.so library, so I can use the -lm option (removing the leading lib and trailing version number, leaving just m, hence -lm). If you know a better method, please let me know immediately—I would be very grateful. Thank you!
&lt;/li&gt;
&lt;li&gt;Program Debugging
Our programs are unlikely to succeed on the first try. Many unexpected errors may occur, requiring us to debug the program.
The most commonly used debugging software is gdb. If you prefer a graphical interface, you can use xxgdb. Remember to include the -g option during compilation. For details on using gdb, refer to its help documentation. Since I haven't used this software much, I can't explain how to use it. However, I don't like using gdb. Tracing a program is quite tedious; I usually debug by outputting intermediate variable values within the program. Of course, you can choose your own method—there's no need to follow others. Now there are many IDE environments that include built-in debuggers. You can try a few to find one you like.
&lt;/li&gt;
&lt;li&gt;Header Files and System Help
Sometimes we only remember the general form of a function but not the exact expression, or we don't remember which header file declared the function. In such cases, we can seek help from the system.
For example, if we want to know the exact form of the fread function, we can simply run man fread, and the system will output a detailed explanation of the function and the header file where it is declared. If we want the description of the write function, running man write gives us the command description instead of the function description. To get the function description for write, we use man 2 write. The number 2 indicates that the write function is a system call. Another commonly used number is 3, indicating a C library function.
Remember, man is always our best helper, no matter what.
------------------------------------------------------------------------
Well, that's enough for this chapter. With this knowledge, we can now embark on exciting C programming adventures under Linux.
2) Introduction to Linux Program Design -- Processes
Process Creation under Linux
Preface:
This article introduces various concepts related to processes under Linux. We will learn:
Concept of processes
Process identity
Process creation
Daemon process creation
----------------------------------------------------------------------------
----
&lt;/li&gt;
&lt;li&gt;Concept of Processes
The Linux operating system is multi-user. At any given time, multiple users can issue various commands to the operating system. How does the operating system achieve a multi-user environment? Modern operating systems have concepts of programs and processes. What is a program, and what is a process? Loosely speaking, a program is a file containing executable code—a static file. A process, on the other hand, is an instance of a program that has started execution but has not yet finished. It is the concrete implementation of an executable file. A single program can have multiple processes, and each process can have multiple child processes, creating a hierarchy of parent and child processes. When a program is loaded into memory by the system, the system allocates certain resources (memory, devices, etc.) to it and performs a series of complex operations to turn the program into a process for system use. In the system, only processes exist, not programs. To distinguish between different processes, the system assigns each process an ID (like an ID card) for identification. To fully utilize resources, the system also categorizes processes into different states: new, running, blocked, ready, and completed. New means the process is being created; running means the process is executing; blocked means the process is waiting for an event; ready means the system is waiting for the CPU to execute; and completed means the process has finished and the system is reclaiming resources. For detailed explanations of the five process states, refer to "Operating Systems."
&lt;/li&gt;
&lt;li&gt;Process Identification
As mentioned above, we know that processes have an ID. How do we obtain a process's ID? The system call getpid retrieves the process ID, and getppid retrieves the parent process ID (the process that created the calling process).
#include 
pid_t getpid(void);
pid_t getppid(void);
Processes serve programs, and programs serve users. To identify the user associated with a process, the system links the process to a user, known as the process owner. Each user also has a user ID. The system call getuid retrieves the owner's ID. Since processes use resources, and Linux protects system resources, processes also have an effective user ID related to resource usage and permissions. The system call geteuid retrieves the effective user ID. Correspondingly, processes also have a group ID and an effective group ID. The system calls getgid and getegid retrieve the group ID and effective group ID, respectively.
#include 
#include 
uid_t getuid(void);
uid_t geteuid(void);
gid_t getgid(void);
gid_t getegid(void);
Sometimes we are interested in other user information (such as login name), in which case we can call getpwuid to retrieve it.
struct passwd {
char *pw_name; /* Login name */
char *pw_passwd; /* Login password */
uid_t pw_uid; /* User ID */
gid_t pw_gid; /* Group ID */
char *pw_gecos; /* Real name */
char *pw_dir; /* User directory */
char *pw_shell; /* User shell */
};
#include 
#include 
struct passwd *getpwuid(uid_t uid);
Next, let's practice using the functions we've learned with an example:
#include 
#include 
#include 
#include 
int main(int argc,char **argv)
{
pid_t my_pid,parent_pid;
uid_t my_uid,my_euid;
gid_t my_gid,my_egid;
struct passwd *my_info;
my_pid=getpid();
parent_pid=getppid();
my_uid=getuid();
my_euid=geteuid();
my_gid=getgid();
my_egid=getegid();
my_info=getpwuid(my_uid);
printf("Process ID:%ld\n",my_pid);
printf("Parent ID:%ld\n",parent_pid);
printf("User ID:%ld\n",my_uid);
printf("Effective User ID:%ld\n",my_euid);
printf("Group ID:%ld\n",my_gid);
printf("Effective Group ID:%ld\n",my_egid);
if(my_info)
{
printf("My Login Name:%s\n" ,my_info-&amp;gt;pw_name);
printf("My Password :%s\n" ,my_info-&amp;gt;pw_passwd);
printf("My User ID :%ld\n",my_info-&amp;gt;pw_uid);
printf("My Group ID :%ld\n",my_info-&amp;gt;pw_gid);
printf("My Real Name:%s\n" ,my_info-&amp;gt;pw_gecos);
printf("My Home Dir :%s\n", my_info-&amp;gt;pw_dir);
printf("My Work Shell:%s\n", my_info-&amp;gt;pw_shell);
}
}
&lt;/li&gt;
&lt;li&gt;Process Creation
Creating a process is simple. We just need to call the fork function.
#include 
#include 
pid_t fork();
When a process calls fork, the system creates a child process. The only differences between the child and parent processes are their process IDs and parent process IDs; everything else is identical, as if the parent process cloned itself. Of course, creating two identical processes is meaningless. To distinguish between parent and child processes, we must track the return value of fork. When fork fails (due to insufficient memory or reaching the maximum number of processes for the user), fork returns -1. Otherwise, the return value of fork is crucial. For the parent process, fork returns the child process's ID, while for the child process, fork returns 0. We use this return value to distinguish between parent and child processes. Why does the parent process create a child process? As mentioned earlier, Linux is a multi-user operating system, and at any given time, multiple users compete for system resources. Sometimes, a process creates a child process to compete for resources to complete tasks sooner. Once the child process is created, both parent and child processes continue execution from the point of fork, competing for system resources. Sometimes, we want the child process to continue executing while the parent process blocks until the child process completes. In this case, we can call the wait or waitpid system calls.
#include 
#include 
pid_t wait(int *stat_loc);
pid_t waitpid(pid_t pid,int *stat_loc,int options);
The wait system call blocks the parent process until a child process ends or the parent receives a signal. If the parent has no child processes or all child processes have ended, wait returns immediately. On success (due to a child process ending), wait returns the child process's ID; otherwise, it returns -1 and sets the global variable errno. stat_loc is the exit status of the child process, set by the child process via exit, _exit, or return. To obtain this value, Linux defines several macros to test the return value:
WIFEXITED: Checks if the child process exited normally.
WEXITSTATUS: Retrieves the exit status of the child process (valid when WIFEXITED is true).
WIFSIGNALED: Checks if the child process was terminated by an unhandled signal.
WTERMSIG: Retrieves the signal number that terminated the child process (valid when WIFSIGNALED is true).
waitpid waits for a specified child process to return. If pid is positive, it waits for the specified process (pid). If pid is 0, it waits for any process in the same group as the caller. If pid is -1, it behaves like the wait call. If pid is less than -1, it waits for any process whose group ID equals the absolute value of pid. stat_loc has the same meaning as in wait. The options parameter determines the parent process's state and can take two values: WNOHANG, which causes the parent to return immediately if no child exists; and WUNTRACED, which causes waitpid to return when the child process ends, but the exit status is not available.
After a parent process creates a child process, the child process usually needs to execute a different program. To invoke a system program, we can use the exec family of system calls. The exec family includes five functions:
#include 
int execl(const char *path,const char *arg,...);
int execlp(const char *file,const char *arg,...);
int execle(const char *path,const char *arg,...);
int execv(const char *path,char *const argv[]);
int execvp(const char *file,char *const argv[]);
The exec family can execute a given program. For detailed explanations of the exec family, refer to the system manual (man exec). Let's study an example. Note: compile with -lm to link the math library.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
void main(void)
{
pid_t child;
int status;
printf("This will demonstrate how to get child status\n");
if((child=fork())==-1)
{
printf("Fork Error :%s\n",strerror(errno));
exit(1);
}
else if(child==0)
{
int i;
printf("I am the child:%ld\n",getpid());
for(i=0;i&amp;lt;1000000;i++);
printf("I exit normally.\n");
exit(0);
}
else
{
printf("I am the parent:%ld\n",getpid());
wait(&amp;amp;status);
if(WIFEXITED(status))
{
printf("Child exited with code:%d\n",WEXITSTATUS(status));
}
else if(WIFSIGNALED(status))
{
printf("Child terminated by signal:%d\n",WTERMSIG(status));
}
}
}
&lt;/li&gt;
&lt;li&gt;Daemon Process Creation
Daemon processes are background processes that run independently of terminals. They are often used for system services. To create a daemon process, follow these steps:
&lt;/li&gt;
&lt;li&gt;Call fork to create a child process, then exit the parent process. This ensures the child is not a process group leader.
&lt;/li&gt;
&lt;li&gt;Call setsid to create a new session, making the child process a session leader and detaching it from the controlling terminal.
&lt;/li&gt;
&lt;li&gt;Change the working directory to the root directory to prevent the current directory from being locked.
&lt;/li&gt;
&lt;li&gt;Close unnecessary file descriptors and redirect standard input, output, and error to /dev/null.
Here is an example of a simple daemon process:
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
/* Default user mailbox path in Linux is /var/spool/mail/username */
#define MAIL "/var/spool/mail/hoyt"
/* Sleep for 10 seconds */
#define SLEEP_TIME 10
main(void)
{
pid_t child;
if((child=fork())==-1)
{
printf("Fork Error:%s\n",strerror(errno));
exit(1);
}
else if(child&amp;gt;0)
while(1);
if(kill(getppid(),SIGTERM)==-1)
{
printf("Kill Parent Error:%s\n",strerror(errno));
exit(1);
}
{
int mailfd;
while(1)
{
if((mailfd=open(MAIL,O_RDONLY))!=-1)
{
fprintf(stderr,"%s","\007");
close(mailfd);
}
sleep(SLEEP_TIME);
}
}
}
You can create your mailbox file in the default path and test this program. Of course, this program has many areas for improvement. We will enhance this small program later. Before I show my improvements, try improving it yourself—perhaps allowing the user to specify the mailbox path and sleep time. Believe in yourself—you can do it. Go ahead, brave explorer.
Well, that's enough for this section on processes. Processes are a very important concept, and many programs use child processes. Creating a child process is a fundamental requirement for every programmer!
3) Introduction to Linux Program Design -- File Operations
File Operations under Linux
Preface:
In this section, we will discuss the various functions for file operations under Linux.
File creation and read/write
File attributes
Directory operations
Pipe files
----------------------------------------------------------------------------
----
&lt;/li&gt;
&lt;li&gt;File Creation and Read/Write
I assume you already know the standard-level file operation functions (fopen, fread, fwrite, etc.). If not, don't worry. The system-level file operations we discuss here actually serve the standard-level operations.
When we need to open a file for read/write operations, we can use the system call open. After use, we call close to close the file.
#include 
#include 
#include 
#include 
int open(const char *pathname,int flags);
int open(const char *pathname,int flags,mode_t mode);
int close(int fd);
The open function has two forms. pathname is the filename (including path, default is current directory). flags can take one of the following values or a combination:
O_RDONLY: Open for reading only.
O_WRONLY: Open for writing only.
O_RDWR: Open for both reading and writing.
O_APPEND: Open in append mode.
O_CREAT: Create a file.
O_EXCL: If O_CREAT is used and the file exists, an error occurs.
O_NOBLOCK: Open in non-blocking mode.
O_TRUNC: If the file exists, truncate its contents.
The first three flags can only be used singly. If O_CREAT is used, we must use the second form of open and specify the mode flag to indicate file access permissions. mode can be a combination of the following:
-----------------------------------------------------------------
S_IRUSR User can read S_IWUSR User can write
S_IXUSR User can execute S_IRWXU User can read, write, execute
-----------------------------------------------------------------
S_IRGRP Group can read S_IWGRP Group can write
S_IXGRP Group can execute S_IRWXG Group can read, write, execute
-----------------------------------------------------------------
S_IROTH Others can read S_IWOTH Others can write
S_IXOTH Others can execute S_IRWXO Others can read, write, execute
-----------------------------------------------------------------
S_ISUID Set user ID S_ISGID Set group ID
-----------------------------------------------------------------
We can also use numbers to represent the permission bits. Linux uses five digits to represent file permissions: 00000. The first digit sets the user ID, the second sets the group ID, the third represents user permissions, the fourth group permissions, and the fifth others' permissions. Each digit can be 1 (execute), 2 (write), 4 (read), 0 (none), or a sum of these values.
For example, to create a file with user read/write/execute, group no permissions, others read/execute, and set user ID, we can use the mode --1 (set user ID) 0 (group not set) 7 (1+2+4) 0 (no permissions, use default) 5 (1+4), i.e., 10705:
open("temp",O_CREAT,10705);
If the file opens successfully, open returns a file descriptor. All subsequent file operations use this file descriptor.
After operations are complete, close the file by calling close, where fd is the file descriptor to close.
After opening a file, we perform read/write operations using the read and write functions.
#include 
ssize_t read(int fd, void *buffer,size_t count);
ssize_t write(int fd, const void *buffer,size_t count);
fd is the file descriptor for read/write operations, buffer is the memory address for writing to or reading from the file, and count is the number of bytes to read/write.
For regular files, read reads count bytes from the specified file (fd) into the buffer (remember to provide a sufficiently large buffer) and returns count.
If read reaches the end of the file or is interrupted by a signal, the return value is less than count. If interrupted by a signal with no data returned, read returns -1 and sets errno to EINTR. When the program reaches the end of the file, read returns 0.
write writes count bytes from buffer to file fd, returning the actual number of bytes written on success.
Next, let's study an example that copies a file.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define BUFFER_SIZE 1024
int main(int argc,char **argv)
{
int from_fd,to_fd;
int bytes_read,bytes_write;
char buffer[BUFFER_SIZE];
char *ptr;
if(argc!=3)
{
fprintf(stderr,"Usage:%s fromfile tofile\n\a",argv[0]);
exit(1);
}
/* Open source file */
if((from_fd=open(argv[1],O_RDONLY))==-1)
{
fprintf(stderr,"Open %s Error:%s\n",argv[1],strerror(errno));
exit(1);
}
/* Create destination file */
if((to_fd=open(argv[2],O_WRONLY|O_CREAT,S_IRUSR|S_IWUSR))==-1)
{
fprintf(stderr,"Open %s Error:%s\n",argv[2],strerror(errno));
exit(1);
}
/* The following code is a classic file copy */
while(bytes_read=read(from_fd,buffer,BUFFER_SIZE))
{
/* A fatal error occurred */
if((bytes_read==-1)&amp;amp;&amp;amp;(errno!=EINTR)) break;
else if(bytes_read&amp;gt;0)
{
ptr=buffer;
while(bytes_write=write(to_fd,ptr,bytes_read))
{
/* A fatal error occurred */
if((bytes_write==-1)&amp;amp;&amp;amp;(errno!=EINTR))break;
/* All read bytes written */
else if(bytes_write==bytes_read) break;
/* Only part written, continue */
else if(bytes_write&amp;gt;0)
{
ptr+=bytes_write;
bytes_read-=bytes_write;
}
}
/* Fatal error during write */
if(bytes_write==-1)break;
}
}
close(from_fd);
close(to_fd);
exit(0);
}
&lt;/li&gt;
&lt;li&gt;File Attributes
Files have various attributes, including creation time, size, etc., in addition to permissions.
Sometimes, we need to check if a file can be accessed in a certain way (read, write, etc.). In this case, we can use the access function.
#include 
int access(const char *pathname,int mode);
pathname is the filename, and mode is the attribute we want to check. It can take the following values or combinations: R_OK (readable), W_OK (writable), X_OK (executable), F_OK (file exists). The function returns 0 on success, or -1 if any condition fails.
To obtain other file attributes, we can use the stat or fstat functions.
#include 
#include 
int stat(const char *file_name,struct stat *buf);
int fstat(int filedes,struct stat *buf);
struct stat {
dev_t st_dev; /* Device */
ino_t st_ino; /* Inode */
mode_t st_mode; /* Mode */
nlink_t st_nlink; /* Hard links */
uid_t st_uid; /* User ID */
gid_t st_gid; /* Group ID */
dev_t st_rdev; /* Device type */
off_t st_off; /* File size in bytes */
unsigned long st_blksize; /* Block size */
unsigned long st_blocks; /* Number of blocks */
time_t st_atime; /* Last access time */
time_t st_mtime; /* Last modification time */
time_t st_ctime; /* Last change time (metadata) */
};
stat is used for files not opened, while fstat is for opened files. The most commonly used attribute is st_mode. We can use the following macros to determine if a given file is a regular file, directory, link, etc.:
S_ISLNK(st_mode): Is it a symbolic link? S_ISREG: Is it a regular file? S_ISDIR: Is it a directory? S_ISCHR: Is it a character device? S_ISBLK: Is it a block device? S_ISFIFO: Is it a FIFO file? S_ISSOCK: Is it a socket file? We will explain how to use these macros below.
&lt;/li&gt;
&lt;li&gt;Directory Operations
When writing programs, we sometimes need to get the current working directory. The C library function getcwd solves this problem.
#include 
char *getcwd(char *buffer,size_t size);
We provide a buffer of size size, and getcwd copies the current path into the buffer. If the buffer is too small, the function returns -1 and an error code.
Linux provides many directory operation functions. We'll learn a few simple and commonly used ones.
#include 
#include 
#include 
#include 
#include 
int mkdir(const char *path,mode_t mode);
DIR *opendir(const char *path);
struct dirent *readdir(DIR *dir);
void rewinddir(DIR *dir);
off_t telldir(DIR *dir);
void seekdir(DIR *dir,off_t off);
int closedir(DIR *dir);
struct dirent {
long d_ino;
off_t d_off;
unsigned short d_reclen;
char d_name[NAME_MAX+1]; /* File name */
mkdir is straightforward—it creates a directory. opendir opens a directory for reading. readdir reads an open directory. rewinddir is used to re-read a directory, similar to the rewind function. closedir closes a directory. telldir and seekdir are similar to ftell and fseek.
Next, we'll develop a small program that takes one parameter. If the parameter is a filename, it outputs the file's size and last modification time. If it's a directory, it outputs the size and modification time of all files in that directory.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
static int get_file_size_time(const char *filename)
{
struct stat statbuf;
if(stat(filename,&amp;amp;statbuf)==-1)
{
printf("Get stat on %s Error:%s\n",
filename,strerror(errno));
return(-1);
}
if(S_ISDIR(statbuf.st_mode))return(1);
if(S_ISREG(statbuf.st_mode))
printf("%s size:%ld bytes\tmodified at %s",
filename,statbuf.st_size,ctime(&amp;amp;statbuf.st_mtime));
return(0);
}
int main(int argc,char **argv)
{
DIR *dirp;
struct dirent *direntp;
int stats;
if(argc!=2)
{
printf("Usage:%s filename\n\a",argv[0]);
exit(1);
}
if(((stats=get_file_size_time(argv[1]))==0)||(stats==-1))exit(1);
if((dirp=opendir(argv[1]))==NULL)
{
printf("Open Directory %s Error:%s\n",
argv[1],strerror(errno));
exit(1);
}
while((direntp=readdir(dirp))!=NULL)
if(get_file_size_time(direntp-&amp;gt;d_name)==-1)break;
closedir(dirp);
exit(0);
}
&lt;/li&gt;
&lt;li&gt;Pipe Files
Pipes are a form of inter-process communication (IPC) that allow data to be passed between processes. A pipe has two ends: one for
---&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;This article was translated from Chinese to English with AI assistance and a light human review. The original is published at &lt;a href="https://sienovo.jytech.us/blog/6852194" rel="noopener noreferrer"&gt;Sienovo Blog&lt;/a&gt;. The original Chinese source is at &lt;a href="https://blog.csdn.net/yeyuangen/article/details/6852194" rel="noopener noreferrer"&gt;CSDN&lt;/a&gt;. Learn more about &lt;a href="https://sienovo.jytech.us" rel="noopener noreferrer"&gt;Sienovo edge AI computing&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>linux</category>
      <category>struct</category>
      <category>buffer</category>
      <category>string</category>
    </item>
  </channel>
</rss>
