zoukankan      html  css  js  c++  java
  • 使用ptrace向已运行进程中注入.so并执行相关函数

    这个总结的很好,从前一个项目也用到这中技术
    转自:http://blog.csdn.net/myarrow/article/details/9630377

    1. 简介

        使用ptrace向已运行进程中注入.so并执行相关函数,其中的“注入”二字的真正含义为:此.so被link到已运行进程(以下简称为:目标进程)空间中,从而.so中的函数在目标进程空间中有对应的地址,然后通过此地址便可在目标进程中进行调用。

         到底是如何注入的呢?

         本文实现方案为:在目标进程中,通过dlopen把需要注入的.so加载到目标进程的空间中。

    2. 如何让目标进程执行dlopen加载.so?

         显然,目标进程本来是没有实现通过dlopen来加载我们想注入的.so,为了实现此功能,我们需要目标进程执行一段我们实现的代码,此段代码的功能为通过dlopen来加载一个.so。

    3. 【加载.so的实现代码】

        加载需要注入的.so的实现代码如下所示:     

    1. .global _dlopen_addr_s       @dlopen函数在目标进程中的地址     注:以下全局变化在C中可读写  
    2. .global _dlopen_param1_s     @dlopen参数1<.so>在目标进程中的地址   
    3. .global _dlopen_param2_s     @dlopen参数2在目标进程中的地址  
    4.   
    5. .global _dlsym_addr_s        @dlsym函数在目标进程中的地址  
    6. .global _dlsym_param2_s      @dlsym参数2在目标进程中的地址,其实为函数名  
    7.   
    8. .global _dlclose_addr_s      @dlcose在目标进程中的地址  
    9.   
    10. .global _inject_start_s      @汇编代码段的起始地址  
    11. .global _inject_end_s        @汇编代码段的结束地址  
    12.   
    13. .global _inject_function_param_s  @hook_init参数在目标进程中的地址  
    14.   
    15. .global _saved_cpsr_s        @保存CPSR,以便执行完hook_init之后恢复环境  
    16. .global _saved_r0_pc_s       @保存r0-r15,以便执行完hook_init之后恢复环境  
    17.   
    18.   
    19. .data  
    20.   
    21. _inject_start_s:  
    22.     @ debug loop  
    23. 3:  
    24.     @sub r1, r1, #0  
    25.     @B 3b  
    26.   
    27.     @ dlopen  
    28.     ldr r1, _dlopen_param2_s        @设置dlopen第二个参数, flag  
    29.     ldr r0, _dlopen_param1_s        @设置dlopen第一个参数 .so  
    30.     ldr r3, _dlopen_addr_s          @设置dlopen函数  
    31.     blx r3                          @执行dlopen函数,返回值位于r0中  
    32.     subs r4, r0, #0                 @把dlopen的返回值soinfo保存在r4中,以方便后面dlclose使用  
    33.     beq 2f  
    34.   
    35.     @dlsym  
    36.     ldr r1, _dlsym_param2_s        @设置dlsym第二个参数,第一个参数已经在r0中了  
    37.     ldr r3, _dlsym_addr_s          @设置dlsym函数  
    38.     blx r3                         @执行dlsym函数,返回值位于r0中  
    39.     subs r3, r0, #0                @把返回值<hook_init在目标进程中的地址>保存在r3中  
    40.     beq 1f  
    41.   
    42.     @call our function  
    43.     ldr r0, _inject_function_param_s  @设置hook_init第一个参数  
    44.         blx r3                            @执行hook_init  
    45.     subs r0, r0, #0  
    46.     beq 2f  
    47.   
    48. 1:  
    49.     @dlclose                          
    50.     mov r0, r4                        @把dlopen的返回值设为dlcose的第一个参数  
    51.     ldr r3, _dlclose_addr_s           @设置dlclose函数  
    52.     blx r3                            @执行dlclose函数  
    53.   
    54. 2:  
    55.     @restore context  
    56.     ldr r1, _saved_cpsr_s             @恢复CPSR  
    57.     msr cpsr_cf, r1  
    58.     ldr sp, _saved_r0_pc_s            @恢复寄存器r0-r15  
    59.     ldmfd sp, {r0-pc}  
    60.       
    61.   
    62.       
    63.   
    64. _dlopen_addr_s:                           @初始化_dlopen_addr_s  
    65. .word 0x11111111  
    66.   
    67. _dlopen_param1_s:  
    68. .word 0x11111111  
    69.   
    70. _dlopen_param2_s:  
    71. .word 0x2                                 @RTLD_GLOBAL  
    72.   
    73. _dlsym_addr_s:  
    74. .word 0x11111111  
    75.   
    76. _dlsym_param2_s:  
    77. .word 0x11111111  
    78.   
    79. _dlclose_addr_s:  
    80. .word 0x11111111  
    81.   
    82. _inject_function_param_s:  
    83. .word 0x11111111  
    84.   
    85. _saved_cpsr_s:  
    86. .word 0x11111111  
    87.   
    88. _saved_r0_pc_s:  
    89. .word 0x11111111  
    90.   
    91.   
    92. _inject_end_s:                     @代码结束地址  
    93.   
    94. .space 0x400, 0                    @代码段空间大小  
    95.   
    96. .end  

    4. 如何把【加载.so的实现代码】写入目标进程并启动执行?

       为了把【加载.so的实现代码】写入目标进程,主要有以下两步操作:

       1) 在目标进程中找到存放【加载.so的实现代码】的空间(通过mmap实现)

       2) 把【加载.so的实现代码】写入目标进程指定的空间

       3) 启动执行

    4.1 在目标进程中找到存放【加载.so的实现代码】的空间

        通过mmap来实现,其实现步骤如下:

       1) 获取目标进程中mmap地址
       2) 把mmap参数据放入r0-r3,另外两个写入目标进程sp 
       3) pc设置为mmap地址,lr设置为0
       4) 把准备好的寄存器写入目标进程(PTRACE_SETREGS),并启动目标进程运行(PTRACE_CONT)
       5) 分配的内存首地址位于r0 (PTRACE_GETREGS)

    4.2 为【加载.so的实现代码】中的全局变量赋值

       1) 获取目标进程中dlopen地址并赋值给_dlopen_addr_s

       2) 获取目标进程中dlsym地址并赋值给_dlsym_addr_s

       3) 获取目标进程中dlclose地址并赋值给_dlclose_addr_s

       4) 把需要加载的.so的路径放入 汇编代码中,并获取此路径在目标进程中的地址然后赋值给_dlopen_param1_s

       5) 把需要加载的.so中的hook_init放入 汇编代码中,并获取此路径在目标进程中的地址然后赋值给_dlsym_param2_s

       6) 把目标进程中的cpsr保存在_saved_cpsr_s中

       7) 把目标进程中的r0-r15存入汇编代码中,并获取此变量在目标进程中的地址然后赋值给_saved_r0_pc_s

       8) 通过ptrace( PTRACE_POKETEXT,...)把汇编代码写入目标进程中,起始地址由前面的mmap所分配

       9) 把目标进程的pc设置为汇编代码的起始地址,然后调用ptrace(PTRACE_DETACH,...)以启动目标进程执行

    5. 把汇编代码写入目标进程并执行的实现代码

    5.1 主函数 writecode_to_targetproc

    1. #include <stdio.h>  
    2. #include <stdlib.h>  
    3. #include <asm/ptrace.h>  
    4. #include <asm/user.h>  
    5. #include <asm/ptrace.h>  
    6. #include <sys/wait.h>  
    7. #include <sys/mman.h>  
    8. #include <dlfcn.h>  
    9. #include <dirent.h>  
    10. #include <unistd.h>  
    11. #include <string.h>  
    12. #include <android/log.h>  
    13. #include <sys/types.h>  
    14. #include <sys/socket.h>  
    15. #include <netinet/in.h>  
    16. #include <sys/stat.h>  
    17.   
    18. #define MAX_PATH 0x100  
    19. #define REMOTE_ADDR( addr, local_base, remote_base ) ( (uint32_t)(addr) + (uint32_t)(remote_base) - (uint32_t)(local_base) )  
    20.   
    21. /* write the assembler code into target proc, 
    22.  * and invoke it to execute 
    23.  */  
    24. int writecode_to_targetproc(   
    25.     pid_t target_pid, // target process pid  
    26.     const char *library_path, // the path of .so that will be   
    27.                               // upload to target process   
    28.     const char *function_name, // .so init fucntion e.g. hook_init  
    29.     void *param, // the parameters of init function  
    30.     size_t param_size ) // number of parameters   
    31. {  
    32.     int ret = -1;  
    33.     void *mmap_addr, *dlopen_addr, *dlsym_addr, *dlclose_addr;  
    34.     void *local_handle, *remote_handle, *dlhandle;  
    35.     uint8_t *map_base;  
    36.     uint8_t *dlopen_param1_ptr, *dlsym_param2_ptr, *saved_r0_pc_ptr, *inject_param_ptr, *remote_code_ptr, *local_code_ptr;  
    37.   
    38.     struct pt_regs regs, original_regs;  
    39.   
    40.     // extern global variable in the assembler code   
    41.     extern uint32_t _dlopen_addr_s, _dlopen_param1_s, _dlopen_param2_s,   
    42.             _dlsym_addr_s, _dlsym_param2_s, _dlclose_addr_s,   
    43.             _inject_start_s, _inject_end_s, _inject_function_param_s,   
    44.             _saved_cpsr_s, _saved_r0_pc_s;  
    45.   
    46.     uint32_t code_length;  
    47.   
    48.     long parameters[10];  
    49.   
    50.     // make target_pid as its child process and stop  
    51.     if ( ptrace_attach( target_pid ) == -1 )  
    52.         return -1;  
    53.   
    54.     // get the values of 18 registers from target_pid  
    55.     if ( ptrace_getregs( target_pid, ®s ) == -1 )  
    56.         goto exit;  
    57.   
    58.     // save original registers   
    59.     memcpy( &original_regs, ®s, sizeof(regs) );  
    60.   
    61.     // get mmap address from target_pid  
    62.     // the mmap is the address of mmap in the cur process  
    63.     mmap_addr = get_remote_addr( target_pid, "/system/lib/libc.so", (void *)mmap );  
    64.   
    65.     // set mmap parameters  
    66.     parameters[0] = 0;  // addr  
    67.     parameters[1] = 0x4000; // size  
    68.     parameters[2] = PROT_READ | PROT_WRITE | PROT_EXEC;  // prot  
    69.     parameters[3] =  MAP_ANONYMOUS | MAP_PRIVATE; // flags  
    70.     parameters[4] = 0; //fd  
    71.     parameters[5] = 0; //offset  
    72.   
    73.     // execute the mmap in target_pid  
    74.     if ( ptrace_call( target_pid, (uint32_t)mmap_addr, parameters, 6, ®s ) == -1 )  
    75.         goto exit;  
    76.   
    77.     // get the return values of mmap <in r0>  
    78.     if ( ptrace_getregs( target_pid, ®s ) == -1 )  
    79.         goto exit;  
    80.   
    81.     // get the start address for assembler code  
    82.     map_base = (uint8_t *)regs.ARM_r0;  
    83.   
    84.     // get the address of dlopen, dlsym and dlclose in target process  
    85.     dlopen_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlopen );  
    86.     dlsym_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlsym );  
    87.     dlclose_addr = get_remote_addr( target_pid, "/system/bin/linker", (void *)dlclose );  
    88.   
    89.     // set the start address for assembler code in target process  
    90.     remote_code_ptr = map_base + 0x3C00;  
    91.   
    92.     // set the start address for assembler code in cur process  
    93.     local_code_ptr = (uint8_t *)&_inject_start_s;  
    94.   
    95.     // set global variable of assembler code  
    96.     // and these address is in the target process  
    97.     _dlopen_addr_s = (uint32_t)dlopen_addr;  
    98.     _dlsym_addr_s = (uint32_t)dlsym_addr;  
    99.     _dlclose_addr_s = (uint32_t)dlclose_addr;  
    100.   
    101.     code_length = (uint32_t)&_inject_end_s - (uint32_t)&_inject_start_s;  
    102.       
    103.     dlopen_param1_ptr = local_code_ptr + code_length + 0x20;  
    104.     dlsym_param2_ptr = dlopen_param1_ptr + MAX_PATH;  
    105.     saved_r0_pc_ptr = dlsym_param2_ptr + MAX_PATH;  
    106.     inject_param_ptr = saved_r0_pc_ptr + MAX_PATH;  
    107.   
    108.   
    109.     // save library path to assembler code global variable  
    110.     strcpy( dlopen_param1_ptr, library_path );  
    111.     _dlopen_param1_s = REMOTE_ADDR( dlopen_param1_ptr, local_code_ptr, remote_code_ptr );  
    112.       
    113.   
    114.     // save function name to assembler code global variable  
    115.     strcpy( dlsym_param2_ptr, function_name );  
    116.     _dlsym_param2_s = REMOTE_ADDR( dlsym_param2_ptr, local_code_ptr, remote_code_ptr );  
    117.   
    118.     // save cpsr to assembler code global variable  
    119.     _saved_cpsr_s = original_regs.ARM_cpsr;  
    120.   
    121.     // save r0-r15 to assembler code global variable  
    122.     memcpy( saved_r0_pc_ptr, &(original_regs.ARM_r0), 16 * 4 ); // r0 ~ r15  
    123.     _saved_r0_pc_s = REMOTE_ADDR( saved_r0_pc_ptr, local_code_ptr, remote_code_ptr );  
    124.   
    125.     // save function parameters to assembler code global variable  
    126.     memcpy( inject_param_ptr, param, param_size );  
    127.     _inject_function_param_s = REMOTE_ADDR( inject_param_ptr, local_code_ptr, remote_code_ptr );  
    128.   
    129.     // write the assembler code into target process  
    130.     // now the values of global variable is in the target process space  
    131.     ptrace_writedata( target_pid, remote_code_ptr, local_code_ptr, 0x400 );  
    132.   
    133.     memcpy( ®s, &original_regs, sizeof(regs) );  
    134.   
    135.     // set sp and pc to the start address of assembler code  
    136.     regs.ARM_sp = (long)remote_code_ptr;  
    137.     regs.ARM_pc = (long)remote_code_ptr;  
    138.   
    139.     // set registers for target process  
    140.     ptrace_setregs( target_pid, ®s );  
    141.   
    142.     // make the target_pid is not a child process of cur process  
    143.     // and make target_pid continue to running  
    144.     ptrace_detach( target_pid );  
    145.   
    146.     // now finish it successfully  
    147.     ret = 0;  
    148.   
    149. exit:  
    150.     return ret;  
    151. }  

    5.2 attach目标进程ptrace_attach

    1. int ptrace_attach( pid_t pid )  
    2. {  
    3.     // after PTRACE_ATTACH, the proc<pid> will stop  
    4.     if ( ptrace( PTRACE_ATTACH, pid, NULL, 0  ) < 0 )  
    5.     {  
    6.         perror( "ptrace_attach" );  
    7.         return -1;  
    8.     }  
    9.   
    10.     // wait proc<pid> stop  
    11.     waitpid( pid, NULL, WUNTRACED );  
    12.   
    13.     // after PTRACE_SYSCALL, the proc<pid> will continue,  
    14.     // but when exectue sys call function, proc<pid> will stop  
    15.     if ( ptrace( PTRACE_SYSCALL, pid, NULL, 0  ) < 0 )  
    16.     {  
    17.         perror( "ptrace_syscall" );  
    18.         return -1;  
    19.     }  
    20.   
    21.     // wait proc<pid> stop  
    22.     waitpid( pid, NULL, WUNTRACED );  
    23.   
    24.     return 0;  
    25. }  

    5.3 获取目标进程寄存器值ptrace_getregs

    1. int ptrace_getregs( pid_t pid, struct pt_regs* regs )  
    2. {  
    3.     if ( ptrace( PTRACE_GETREGS, pid, NULL, regs ) < 0 )  
    4.     {  
    5.         perror( "ptrace_getregs: Can not get register values" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  


    5.4 获取目标进程中指定模块中指定函数的地址get_remote_addr

    1.    
    2. /* find the start address of module whose name is module_name  
    3.  * in the designated process 
    4.  */  
    5. void* get_module_base( pid_t pid, const char* module_name )  
    6. {  
    7.     FILE *fp;  
    8.     long addr = 0;  
    9.     char *pch;  
    10.     char filename[32];  
    11.     char line[1024];  
    12.   
    13.     if ( pid < 0 )  
    14.     {  
    15.         /* self process */  
    16.         snprintf( filename, sizeof(filename), "/proc/self/maps", pid );  
    17.     }  
    18.     else  
    19.     {  
    20.         snprintf( filename, sizeof(filename), "/proc/%d/maps", pid );  
    21.     }  
    22.   
    23.     fp = fopen( filename, "r" );  
    24.   
    25.     if ( fp != NULL )  
    26.     {  
    27.         while ( fgets( line, sizeof(line), fp ) )  
    28.         {  
    29.             if ( strstr( line, module_name ) )  
    30.             {  
    31.                 pch = strtok( line, "-" );  
    32.                 addr = strtoul( pch, NULL, 16 );  
    33.   
    34.                 if ( addr == 0x8000 )  
    35.                     addr = 0;  
    36.   
    37.                 break;  
    38.             }  
    39.         }  
    40.         fclose( fp ) ;  
    41.     }  
    42.   
    43.     return (void *)addr;  
    44. }  
    45.   
    46. void* get_remote_addr( pid_t target_pid, const char* module_name, void* local_addr )  
    47. {  
    48.     void* local_handle, *remote_handle;  
    49.   
    50.     local_handle = get_module_base( -1, module_name );  
    51.     remote_handle = get_module_base( target_pid, module_name );  
    52.   
    53.     return (void *)( (uint32_t)local_addr + (uint32_t)remote_handle - (uint32_t)local_handle );  
    54. }  

    5.5 在目标进程中执行指定函数ptrace_call

    1. int ptrace_call( pid_t pid, uint32_t addr, long *params, uint32_t num_params, struct pt_regs* regs )  
    2. {  
    3.     uint32_t i;  
    4.   
    5.     // put the first 4 parameters into r0-r3  
    6.     for ( i = 0; i < num_params && i < 4; i ++ )  
    7.     {  
    8.         regs->uregs[i] = params[i];  
    9.     }  
    10.   
    11.     // push remained params into stack  
    12.     if ( i < num_params )  
    13.     {  
    14.         regs->ARM_sp -= (num_params - i) * sizeof(long) ;  
    15.         ptrace_writedata( pid, (void *)regs->ARM_sp, (uint8_t *)¶ms[i], (num_params - i) * sizeof(long) );  
    16.     }  
    17.     // set the pc to func <e.g: mmap> that will be executed  
    18.     regs->ARM_pc = addr;  
    19.     if ( regs->ARM_pc & 1 )  
    20.     {  
    21.         /* thumb */  
    22.         regs->ARM_pc &= (~1u);  
    23.         regs->ARM_cpsr |= CPSR_T_MASK;  
    24.     }  
    25.     else  
    26.     {  
    27.         /* arm */  
    28.         regs->ARM_cpsr &= ~CPSR_T_MASK;  
    29.     }  
    30.   
    31.     // when finish this func, pid will stop  
    32.     regs->ARM_lr = 0;      
    33.   
    34.     // set the regsister and start to execute  
    35.     if ( ptrace_setregs( pid, regs ) == -1   
    36.         || ptrace_continue( pid ) == -1 )  
    37.     {  
    38.         return -1;  
    39.     }  
    40.   
    41.     // wait pid finish work and stop  
    42.     waitpid( pid, NULL, WUNTRACED );  
    43.   
    44.     return 0;  
    45. }  

    5.6 把代码写入目标进程指定地址ptrace_writedata

    1. int ptrace_writedata( pid_t pid, uint8_t *dest, uint8_t *data, size_t size )  
    2. {  
    3.     uint32_t i, j, remain;  
    4.     uint8_t *laddr;  
    5.   
    6.     union u {  
    7.         long val;  
    8.         char chars[sizeof(long)];  
    9.     } d;  
    10.   
    11.     j = size / 4;  
    12.     remain = size % 4;  
    13.   
    14.     laddr = data;  
    15.   
    16.     for ( i = 0; i < j; i ++ )  
    17.     {  
    18.         memcpy( d.chars, laddr, 4 );  
    19.         ptrace( PTRACE_POKETEXT, pid, dest, d.val );  
    20.   
    21.         dest  += 4;  
    22.         laddr += 4;  
    23.     }  
    24.   
    25.     if ( remain > 0 )  
    26.     {  
    27.         d.val = ptrace( PTRACE_PEEKTEXT, pid, dest, 0 );  
    28.         for ( i = 0; i < remain; i ++ )  
    29.         {  
    30.             d.chars[i] = *laddr ++;  
    31.         }  
    32.   
    33.         ptrace( PTRACE_POKETEXT, pid, dest, d.val );  
    34.           
    35.     }  
    36.   
    37.     return 0;  
    38. }  

    5.7 设置目标进程寄存器ptrace_setregs

    1. int ptrace_setregs( pid_t pid, struct pt_regs* regs )  
    2. {  
    3.     if ( ptrace( PTRACE_SETREGS, pid, NULL, regs ) < 0 )  
    4.     {  
    5.         perror( "ptrace_setregs: Can not set register values" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  

    5.8 detach目标进程ptrace_detach

    1. int ptrace_detach( pid_t pid )  
    2. {  
    3.     if ( ptrace( PTRACE_DETACH, pid, NULL, 0 ) < 0 )  
    4.     {  
    5.         perror( "ptrace_detach" );  
    6.         return -1;  
    7.     }  
    8.   
    9.     return 0;  
    10. }  


    6.  需要被加载的.so

        需要被加载的.so例子程序如下,其目的是替换目标进程libapp.so中的strlen函数。其主要实现见hook_init。

    1. int g_isInit = 0;      
    2. pthread_t g_hThread;       
    3.   
    4. __attribute__((visibility("default"))) void hook_init( char *args )  
    5. {  
    6.    if( g_isInit == 1 )  
    7.    {  
    8.       printf("i am already in!");  
    9.       return;  
    10.    }  
    11.   
    12.    void* soHandle = NULL;  
    13.      
    14.    // the libapp.so is a .so of target process, and it call strcmp  
    15.    soHandle  = dlopen( "libapp.so", RTLD_GLOBAL );  
    16.    if( soHandle != NULL )  
    17.    {  
    18.       g_realstrcmp = NULL;  
    19.       replaceFunc( soHandle, "strcmp", my_strcmp, (void**)&g_realstrcmp );  
    20.         
    21.       int ret = pthread_create( &g_hThread, NULL, my_thread, NULL );  
    22.       if( ret != 0 )  
    23.       {  
    24.          printf("create thread error:%d", ret );  
    25.       }  
    26.         
    27.       g_isInit = 1;  
    28.    }  
    29.      
    30. }  

    6.1 替换函数replaceFunc

    1. // replace function of libapp.so  
    2. // e.g: replace strcmp of libapp.so with my_strcmp  
    3. void replaceFunc(void *handle,const char *name, void* pNewFun, void** pOldFun )  
    4. {  
    5.   
    6.    if(!handle)  
    7.       return;  
    8.         
    9.    soinfo *si = (soinfo*)handle;     
    10.    Elf32_Sym *symtab = si->symtab;    
    11.    const char *strtab = si->strtab;    
    12.    Elf32_Rel *rel = si->plt_rel;  
    13.    unsigned count = si->plt_rel_count;   
    14.    unsigned idx;   
    15.   
    16.    // these external functions that are called by libapp.so   
    17.    // is in the plt_rel  
    18.    for(idx=0; idx<count; idx++)   
    19.    {    
    20.       unsigned type = ELF32_R_TYPE(rel->r_info);    
    21.       unsigned sym = ELF32_R_SYM(rel->r_info);    
    22.       unsigned reloc = (unsigned)(rel->r_offset + si->base);    
    23.       char *sym_name = (char *)(strtab + symtab[sym].st_name);   
    24.         
    25.       if(strcmp(sym_name, name)==0)   
    26.       {   
    27.          *pOldFun = (void *)*((unsigned*)reloc);   
    28.           *((unsigned*)reloc)= pNewFun;  
    29.          break;  
    30.       }   
    31.       rel++;    
    32.    }   
    33. }  

    6.2 新函数及其它函数

    1. // global function variable, save the address of strcmp of libapp.so  
    2. int (*g_realstrcmp)(const char *s1, const char *s2);  
    3.   
    4. // my strcmp function  
    5. int my_strcmp(const char *s1, const char *s2)  
    6. {  
    7.     if( g_realstrcmp != NULL )  
    8.     {  
    9.         int nRet = g_realstrcmp( s1, s2 );  
    10.         printf("***%s: s1=%s, s2=%s ",__FUNCTION__, s1, s2 );  
    11.         return nRet;  
    12.     }  
    13.   
    14.     return -1;  
    15. }  
    16.   
    17.   
    18. // create a thread  
    19. void* my_thread( void* pVoid )  
    20. {  
    21.     int sock;  
    22.     sock = socket(AF_INET, SOCK_DGRAM, 0);  
    23.     if( sock < -1 )  
    24.     {  
    25.       printf("create socket failed! ");  
    26.       return 0;  
    27.     }  
    28.   
    29.     struct sockaddr_in addr_serv;    
    30.     int len;    
    31.     memset(&addr_serv, 0, sizeof(struct sockaddr_in));    
    32.     addr_serv.sin_family = AF_INET;    
    33.     addr_serv.sin_port = htons(9999);     
    34.     addr_serv.sin_addr.s_addr = inet_addr("127.0.0.1");    
    35.     len = sizeof(addr_serv);    
    36.   
    37.     int flags = fcntl( sock, F_GETFL, 0);   
    38.     fcntl( sock, F_SETFL, flags | O_NONBLOCK);  
    39.     int nPreState = -1;  
    40.     unsigned char data=0;  
    41.     while( 1 )  
    42.     {  
    43.         data++;  
    44.         sendto( sock, &data,  sizeof( data ), 0, (struct sockaddr *)&addr_serv, sizeof( addr_serv ) );  
    45.         usleep( 30000 );  
    46.     }  
    47. }  
  • 相关阅读:
    jMeter 里 CSV Data Set Config Sharing Mode 的含义详解
    如何使用 jMeter Parallel Controller
    使用 Chrome 开发者工具 coverage 功能分析 web 应用的渲染阻止资源的执行分布情况
    使用 Chrome 开发者工具的 lighthouse 功能分析 web 应用的性能问题
    关于 SAP 电商云首页加载时触发的 OCC API 请求
    SAP UI5 确保控件 id 全局唯一的实现方法
    SAP 电商云 Accelerator 和 Spartacus UI 的工作机制差异
    介绍一个好用的能让网页变成黑色背景的护眼 Chrome 扩展应用
    Chrome 开发者工具 performance 标签页的用法
    Client Side Cache 和 Server Side Cache 的区别
  • 原文地址:https://www.cnblogs.com/fly-fish/p/3835958.html
Copyright © 2011-2022 走看看