Heim Datenbank MySQL-Tutorial memcached探索之thread model(2)

memcached探索之thread model(2)

Jun 07, 2016 pm 03:11 PM
memcached model thread unter ICH 探索

6. 下面我们看看主线程dispatch_thread的事件处理设置。在memcached.c中的main函数中 /* create unix mode sockets after dropping privileges */ if ( settings . socketpath ! = NULL ) { errno = 0 ; if ( server_socket_unix ( settings . socketpath ,

6. 下面我们看看主线程dispatch_thread的事件处理设置。在memcached.c中的main函数中

<span><font face="新宋体"><span>/* create unix mode sockets after dropping privileges */</span><br>    <span>if</span> <span>(</span>settings<span>.</span>socketpath <span>!</span><span>=</span> <span>NULL</span><span>)</span> <span>{</span><br>        <span>errno</span> <span>=</span> 0<span>;</span><br>        <span>if</span> <span>(</span>server_socket_unix<span>(</span>settings<span>.</span>socketpath<span>,</span>settings<span>.</span>access<span>)</span><span>)</span> <span>{</span><br>            vperror<span>(</span><span>"failed to listen on UNIX socket: %s"</span><span>,</span> settings<span>.</span>socketpath<span>)</span><span>;</span><br>            <span>exit</span><span>(</span>EX_OSERR<span>)</span><span>;</span><br>        <span>}</span><br>    <span>}</span><br><br>    <span>/* create the listening socket, bind it, and init */</span><br>    <span>if</span> <span>(</span>settings<span>.</span>socketpath <span>=</span><span>=</span> <span>NULL</span><span>)</span> <span>{</span><br>        <span>int</span> udp_port<span>;</span><br><br>        <span>const</span> <span>char</span> <span>*</span>portnumber_filename <span>=</span> <span>getenv</span><span>(</span><span>"MEMCACHED_PORT_FILENAME"</span><span>)</span><span>;</span><br>        <span>char</span> temp_portnumber_filename<span>[</span>PATH_MAX<span>]</span><span>;</span><br>        <span>FILE</span> <span>*</span>portnumber_file <span>=</span> <span>NULL</span><span>;</span><br><br>        <span>if</span> <span>(</span>portnumber_filename <span>!</span><span>=</span> <span>NULL</span><span>)</span> <span>{</span><br>            snprintf<span>(</span>temp_portnumber_filename<span>,</span><br>                     <span>sizeof</span><span>(</span>temp_portnumber_filename<span>)</span><span>,</span><br>                     <span>"%s.lck"</span><span>,</span> portnumber_filename<span>)</span><span>;</span><br><br>            portnumber_file <span>=</span> <span>fopen</span><span>(</span>temp_portnumber_filename<span>,</span> <span>"a"</span><span>)</span><span>;</span><br>            <span>if</span> <span>(</span>portnumber_file <span>=</span><span>=</span> <span>NULL</span><span>)</span> <span>{</span><br>                <span>fprintf</span><span>(</span><span>stderr</span><span>,</span> <span>"Failed to open \"%s\": %s\n"</span><span>,</span><br>                        temp_portnumber_filename<span>,</span> <span>strerror</span><span>(</span><span>errno</span><span>)</span><span>)</span><span>;</span><br>            <span>}</span><br>        <span>}</span><br><br>        <span>errno</span> <span>=</span> 0<span>;</span><br>        <span>if</span> <span>(</span>settings<span>.</span>port <span>&</span><span>&</span> server_socket<span>(</span>settings<span>.</span>port<span>,</span> tcp_transport<span>,</span><br>                                           portnumber_file<span>)</span><span>)</span> <span>{</span><br>            vperror<span>(</span><span>"failed to listen on TCP port %d"</span><span>,</span> settings<span>.</span>port<span>)</span><span>;</span><br>            <span>exit</span><span>(</span>EX_OSERR<span>)</span><span>;</span><br>        <span>}</span><br><br>        </font><font face="新宋体"><span>/*<br>         * initialization order: first create the listening sockets<br>         * (may need root on low ports), then drop root if needed,<br>         * then daemonise if needed, then init libevent (in some cases<br>         * descriptors created by libevent wouldn't survive forking).<br>         */</span><br>        udp_port <span>=</span> settings<span>.</span>udpport <span>?</span> settings<span>.</span>udpport <span>:</span> settings<span>.</span>port<span>;</span><br><br>        <span>/* create the UDP listening socket and bind it */</span><br>        <span>errno</span> <span>=</span> 0<span>;</span><br>        <span>if</span> <span>(</span>settings<span>.</span>udpport <span>&</span><span>&</span> server_socket<span>(</span>settings<span>.</span>udpport<span>,</span> udp_transport<span>,</span><br>                                              portnumber_file<span>)</span><span>)</span> <span>{</span><br>            vperror<span>(</span><span>"failed to listen on UDP port %d"</span><span>,</span> settings<span>.</span>udpport<span>)</span><span>;</span><br>            <span>exit</span><span>(</span>EX_OSERR<span>)</span><span>;</span><br>        <span>}</span><br><br>        <span>if</span> <span>(</span>portnumber_file<span>)</span> <span>{</span><br>            <span>fclose</span><span>(</span>portnumber_file<span>)</span><span>;</span><br>            <span>rename</span><span>(</span>temp_portnumber_filename<span>,</span> portnumber_filename<span>)</span><span>;</span><br>        <span>}</span><br>    <span>}</span><br>    <span>/* Drop privileges no longer needed */</span><br>    drop_privileges<span>(</span><span>)</span><span>;</span><br>    <span>/* enter the event loop */</span><br>    event_base_loop<span>(</span>main_base<span>,</span> 0<span>)</span><span>; //主线程(dispatcher_thread)的事件监听循环。。。</span></font></span>

<span><font face="新宋体"><span></span><br></font></span>


7. 继续跟踪server_socket函数(memcached.c中)

<span><font face="新宋体"><span>/**<br> * Create a socket and bind it to a specific port number<br> * @param port the port number to bind to<br> * @param transport the transport protocol (TCP / UDP)<br> * @param portnumber_file A filepointer to write the port numbers to<br> * when they are successfully added to the list of ports we<br> * listen on.<br> */</span><br><span>static</span> <span>int</span> server_socket<span>(</span><span>int</span> port<span>,</span> <span>enum</span> network_transport transport<span>,</span><br>                         <span>FILE</span> <span>*</span>portnumber_file<span>)</span> <span>{</span><br>    <span>int</span> sfd<span>;</span><br>    <span>struct</span> <span>linger</span> ling <span>=</span> <span>{</span>0<span>,</span> 0<span>}</span><span>;</span><br>    <span>struct</span> <span>addrinfo</span> <span>*</span>ai<span>;</span><br>    <span>struct</span> <span>addrinfo</span> <span>*</span>next<span>;</span><br>    <span>struct</span> <span>addrinfo</span> hints <span>=</span> <span>{</span> <span>.</span>ai_flags <span>=</span> <span>AI_PASSIVE</span><span>,</span><br>                              <span>.</span>ai_family <span>=</span> <span>AF_UNSPEC</span> <span>}</span><span>;</span><br>    <span>char</span> port_buf<span>[</span><span>NI_MAXSERV</span><span>]</span><span>;</span><br>    <span>int</span> <span>error</span><span>;</span><br>    <span>int</span> success <span>=</span> 0<span>;</span><br>    <span>int</span> flags <span>=</span>1<span>;</span><br><br>    hints<span>.</span>ai_socktype <span>=</span> IS_UDP<span>(</span>transport<span>)</span> <span>?</span> <span>SOCK_DGRAM</span> <span>:</span> <span>SOCK_STREAM</span><span>;</span><br><br>    <span>if</span> <span>(</span>port <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>        port <span>=</span> 0<span>;</span><br>    <span>}</span><br>    snprintf<span>(</span>port_buf<span>,</span> <span>sizeof</span><span>(</span>port_buf<span>)</span><span>,</span> <span>"%d"</span><span>,</span> port<span>)</span><span>;</span><br>    <span>error</span><span>=</span> <span>getaddrinfo</span><span>(</span>settings<span>.</span>inter<span>,</span> port_buf<span>,</span> <span>&</span>hints<span>,</span> <span>&</span>ai<span>)</span><span>;</span><br>    <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> 0<span>)</span> <span>{</span><br>        <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> <span>EAI_SYSTEM</span><span>)</span><br>          <span>fprintf</span><span>(</span><span>stderr</span><span>,</span> <span>"getaddrinfo(): %s\n"</span><span>,</span> <span>gai_strerror</span><span>(</span><span>error</span><span>)</span><span>)</span><span>;</span><br>        <span>else</span><br>          <span>perror</span><span>(</span><span>"getaddrinfo()"</span><span>)</span><span>;</span><br>        <span>return</span> 1<span>;</span><br>    <span>}</span><br><br>    <span>for</span> <span>(</span>next<span>=</span> ai<span>;</span> next<span>;</span> next<span>=</span> next<span>-</span><span>></span>ai_next<span>)</span> <span>{</span><br>        conn <span>*</span>listen_conn_add<span>;</span><br>        <span>if</span> <span>(</span><span>(</span>sfd <span>=</span> new_socket<span>(</span>next<span>)</span><span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{ <span>//creat socket</span></span><br>            </font><font face="新宋体"><span>/* getaddrinfo can return "junk" addresses,<br>             * we make sure at least one works before erroring.<br>             */</span><br>            <span>continue</span><span>;</span><br>        <span>}</span><br><br><span>#</span><span>ifdef</span> IPV6_V6ONLY<br>        <span>if</span> <span>(</span>next<span>-</span><span>></span>ai_family <span>=</span><span>=</span> <span>AF_INET6</span><span>)</span> <span>{</span><br>            <span>error</span> <span>=</span> <span>setsockopt</span><span>(</span>sfd<span>,</span> <span>IPPROTO_IPV6</span><span>,</span> IPV6_V6ONLY<span>,</span> <span>(</span><span>char</span> <span>*</span><span>)</span> <span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>;</span><br>            <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> 0<span>)</span> <span>{</span><br>                <span>perror</span><span>(</span><span>"setsockopt"</span><span>)</span><span>;</span><br>                <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>                <span>continue</span><span>;</span><br>            <span>}</span><br>        <span>}</span><br><span>#</span><span>endif</span><br>  <span>      </span></font></span>//setsockopt
<span><font face="新宋体">        <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_REUSEADDR<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>; </span><br>        <span>if</span> <span>(</span>IS_UDP<span>(</span>transport<span>)</span><span>)</span> <span>{</span><br>            maximize_sndbuf<span>(</span>sfd<span>)</span><span>;</span><br>        <span>}</span> <span>else</span> <span>{</span><br>            <span>error</span> <span>=</span> <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_KEEPALIVE<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>;</span><br>            <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> 0<span>)</span><br>                <span>perror</span><span>(</span><span>"setsockopt"</span><span>)</span><span>;</span><br><br>            <span>error</span> <span>=</span> <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_LINGER<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>ling<span>,</span> <span>sizeof</span><span>(</span>ling<span>)</span><span>)</span><span>;</span><br>            <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> 0<span>)</span><br>                <span>perror</span><span>(</span><span>"setsockopt"</span><span>)</span><span>;</span><br><br>            <span>error</span> <span>=</span> <span>setsockopt</span><span>(</span>sfd<span>,</span> <span>IPPROTO_TCP</span><span>,</span> TCP_NODELAY<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>;</span><br>            <span>if</span> <span>(</span><span>error</span> <span>!</span><span>=</span> 0<span>)</span><br>                <span>perror</span><span>(</span><span>"setsockopt"</span><span>)</span><span>;</span><br>        <span>}</span><br>  <span>      //bind</span><br>        <span>if</span> <span>(</span><span>bind</span><span>(</span>sfd<span>,</span> next<span>-</span><span>></span>ai_addr<span>,</span> next<span>-</span><span>></span>ai_addrlen<span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>            <span>if</span> <span>(</span><span>errno</span> <span>!</span><span>=</span> EADDRINUSE<span>)</span> <span>{</span><br>                <span>perror</span><span>(</span><span>"bind()"</span><span>)</span><span>;</span><br>                <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>                <span>freeaddrinfo</span><span>(</span>ai<span>)</span><span>;</span><br>                <span>return</span> 1<span>;</span><br>            <span>}</span><br>            <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>            <span>continue</span><span>;</span><br>        <span>}</span> <span>else</span> <span>{</span><br>            success<span>+</span><span>+</span><span>;</span></font></span>

<span><span></span><font face="新宋体">         <span>   //TCP listen</span><br>            <span>if</span> <span>(</span><span>!</span>IS_UDP<span>(</span>transport<span>)</span> <span>&</span><span>&</span> <span>listen</span><span>(</span>sfd<span>,</span> settings<span>.</span>backlog<span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>                <span>perror</span><span>(</span><span>"listen()"</span><span>)</span><span>;</span><br>                <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>                <span>freeaddrinfo</span><span>(</span>ai<span>)</span><span>;</span><br>                <span>return</span> 1<span>;</span><br>            <span>}</span><br>            <span>if</span> <span>(</span>portnumber_file <span>!</span><span>=</span> <span>NULL</span> <span>&</span><span>&</span><br>                <span>(</span>next<span>-</span><span>></span>ai_addr<span>-</span><span>></span>sa_family <span>=</span><span>=</span> <span>AF_INET</span> <span>|</span><span>|</span><br>                 next<span>-</span><span>></span>ai_addr<span>-</span><span>></span>sa_family <span>=</span><span>=</span> <span>AF_INET6</span><span>)</span><span>)</span> <span>{</span><br>                <span>union</span> <span>{</span><br>                    <span>struct</span> <span>sockaddr_in</span> in<span>;</span><br>                    <span>struct</span> <span>sockaddr_in6</span> in6<span>;</span><br>                <span>}</span> my_sockaddr<span>;</span><br>                <span>socklen_t</span> len <span>=</span> <span>sizeof</span><span>(</span>my_sockaddr<span>)</span><span>;</span><br>                <span>if</span> <span>(</span><span>getsockname</span><span>(</span>sfd<span>,</span> <span>(</span><span>struct</span> <span>sockaddr</span><span>*</span><span>)</span><span>&</span>my_sockaddr<span>,</span> <span>&</span>len<span>)</span><span>=</span><span>=</span>0<span>)</span> <span>{</span><br>                    <span>if</span> <span>(</span>next<span>-</span><span>></span>ai_addr<span>-</span><span>></span>sa_family <span>=</span><span>=</span> <span>AF_INET</span><span>)</span> <span>{</span><br>                        <span>fprintf</span><span>(</span>portnumber_file<span>,</span> <span>"%s INET: %u\n"</span><span>,</span><br>                                IS_UDP<span>(</span>transport<span>)</span> <span>?</span> <span>"UDP"</span> <span>:</span> <span>"TCP"</span><span>,</span><br>                                <span>ntohs</span><span>(</span>my_sockaddr<span>.</span>in<span>.</span>sin_port<span>)</span><span>)</span><span>;</span><br>                    <span>}</span> <span>else</span> <span>{</span><br>                        <span>fprintf</span><span>(</span>portnumber_file<span>,</span> <span>"%s INET6: %u\n"</span><span>,</span><br>                                IS_UDP<span>(</span>transport<span>)</span> <span>?</span> <span>"UDP"</span> <span>:</span> <span>"TCP"</span><span>,</span><br>                                <span>ntohs</span><span>(</span>my_sockaddr<span>.</span>in6<span>.</span>sin6_port<span>)</span><span>)</span><span>;</span><br>                    <span>}</span><br>                <span>}</span><br>            <span>}</span><br>        <span>}</span><br><br>        <span>if</span> <span>(</span>IS_UDP<span>(</span>transport<span>)</span><span>)</span> </font><span><font face="新宋体">{ <br></font></span></span>

<font face="新宋体">            //UDP 的处理中不需要accept,所以直接派发connection到工作线程。</font><span><span></span><br><font face="新宋体">            <span>int</span> c<span>;</span><br><br>            <span>for</span> <span>(</span>c <span>=</span> 0<span>;</span> c <span> settings<span>.</span>num_threads<span>;</span> c<span>+</span><span>+</span><span>)</span> <span>{</span><br>                <span>/* this is guaranteed to hit all threads because we round-robin */</span><br>                dispatch_conn_new<span>(</span>sfd<span>,</span> conn_read<span>,</span> EV_READ <span>|</span> EV_PERSIST<span>,</span><br>                                  UDP_READ_BUFFER_SIZE<span>,</span> transport<span>)</span><span>;</span><br>            <span>}</span><br>        <span>}</span> <span>else</span> </span></font><span><font face="新宋体">{  <br></font></span></span>

<span><span><font face="新宋体">         <span> <span> //TCP的处理(注意,这里dispatcher_thread同样调用了conn_new来绑定conn_event到其main_base. 并且此时conn的初始状态为conn_listening, 事件为持久可读, 而在conn_new中注册了conn_event的回调函数为event_handler,所以,dispatche_thread在当前listen的socket可读时就会调用event_handler,进而调用driver_machine(c) 进入状态机。而在driver_machine中如果是主线程(dispatcher_thread)则会在accept socket后调用dispatch_new_conn函数来给各worker_thread派发connection...)</span></span></font></span></span><span><span></span><br><font face="新宋体">            <span>if</span> <span>(</span><span>!</span><span>(</span>listen_conn_add <span>=</span> conn_new<span>(</span>sfd<span>,</span> conn_listening<span>,</span><br>                                             EV_READ <span>|</span> EV_PERSIST<span>,</span> 1<span>,</span><br>                                             transport<span>,</span> main_base<span>)</span><span>)</span><span>)</span> <span>{</span><br>                <span>fprintf</span><span>(</span><span>stderr</span><span>,</span> <span>"failed to create listening connection\n"</span><span>)</span><span>;</span><br>                <span>exit</span><span>(</span><span>EXIT_FAILURE</span><span>)</span><span>;</span><br>            <span>}</span><br>            listen_conn_add<span>-</span><span>></span>next <span>=</span> listen_conn<span>;</span><br>            listen_conn <span>=</span> listen_conn_add<span>;</span><br>        <span>}</span><br>    <span>}</span><br><br>    <span>freeaddrinfo</span><span>(</span>ai<span>)</span><span>;</span><br><br>    <span>/* Return zero iff we detected no errors in starting up connections */</span><br>    <span>return</span> success <span>=</span><span>=</span> 0<span>;</span><br><span>}</span></font></span>


8. 看看UDP和TCP模式下dispatcher_thread都会调用的dispatch_new_conn函数(在thread.c中)

<span><font face="新宋体"><span>/*<br> * Dispatches a new connection to another thread. This is only ever called<br> * from the main thread, either during initialization (for UDP) or because<br> * of an incoming connection.<br> */</span><br><span>void</span> dispatch_conn_new<span>(</span><span>int</span> sfd<span>,</span> <span>enum</span> conn_states init_state<span>,</span> <span>int</span> event_flags<span>,</span><br>                       <span>int</span> read_buffer_size<span>,</span> <span>enum</span> network_transport transport<span>)</span> <span>{</span><br>    CQ_ITEM <span>*</span>item <span>=</span> cqi_new<span>(</span><span>)</span><span>;</span><br>    <span>int</span> tid <span>=</span> <span>(</span>last_thread <span>+</span> 1<span>)</span> <span>%</span> settings<span>.</span>num_threads<span>; //轮询的方式找worker_thread</span><br><br>    LIBEVENT_THREAD <span>*</span>thread <span>=</span> threads <span>+</span> tid<span>;</span><br><br>    last_thread <span>=</span> tid<span>;</span><br><br>    item<span>-</span><span>></span>sfd <span>=</span> sfd<span>;</span><br>    item<span>-</span><span>></span>init_state <span>=</span> init_state<span>;</span><br>    item<span>-</span><span>></span>event_flags <span>=</span> event_flags<span>;</span><br>    item<span>-</span><span>></span>read_buffer_size <span>=</span> read_buffer_size<span>;</span><br>    item<span>-</span><span>></span>transport <span>=</span> transport<span>;</span><br>  </font><span>  </span></span><span><span>//push conn到worker_thread的CQ中</span></span>
<span><font face="新宋体">    cq_push<span>(</span>thread<span>-</span><span>></span>new_conn_queue<span>,</span> item<span>)</span><span>; </span><br><br>    MEMCACHED_CONN_DISPATCH<span>(</span>sfd<span>,</span> thread<span>-</span><span>></span>thread_id<span>)</span><span>;</span><br>    <span>if</span> <span>(</span><span>write</span><span>(</span>thread<span>-</span><span>></span>notify_send_fd<span>,</span> <span>""</span><span>,</span> 1<span>)</span> <span>!</span><span>=</span> 1<span>)</span> <span>{</span><br>        <span>perror</span><span>(</span><span>"Writing to thread notify pipe"</span><span>)</span><span>;</span><br>    <span>}</span><br><span>}</span><br></font></span>


9. 先看看unix domain socket模式下主线程的事件处理设置。(在上面的6中调用的 server_socket_unix函数

<span><font face="新宋体"><span>static</span> <span>int</span> server_socket_unix<span>(</span><span>const</span> <span>char</span> <span>*</span>path<span>,</span> <span>int</span> access_mask<span>)</span> <span>{</span><br>    <span>int</span> sfd<span>;</span><br>    <span>struct</span> <span>linger</span> ling <span>=</span> <span>{</span>0<span>,</span> 0<span>}</span><span>;</span><br>    <span>struct</span> <span>sockaddr_un</span> addr<span>;</span><br>    <span>struct</span> stat tstat<span>;</span><br>    <span>int</span> flags <span>=</span>1<span>;</span><br>    <span>int</span> old_umask<span>;</span><br><br>    <span>if</span> <span>(</span><span>!</span>path<span>)</span> <span>{</span><br>        <span>return</span> 1<span>;</span><br>    <span>}</span><br><br>    <span>if</span> <span>(</span><span>(</span>sfd <span>=</span> new_socket_unix<span>(</span><span>)</span><span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>        <span>return</span> 1<span>;</span><br>    <span>}</span><br><br>    </font><font face="新宋体"><span>/*<br>     * Clean up a previous socket file if we left it around<br>     */</span><br>    <span>if</span> <span>(</span>lstat<span>(</span>path<span>,</span> <span>&</span>tstat<span>)</span> <span>=</span><span>=</span> 0<span>)</span> <span>{</span><br>        <span>if</span> <span>(</span>S_ISSOCK<span>(</span>tstat<span>.</span>st_mode<span>)</span><span>)</span><br>            unlink<span>(</span>path<span>)</span><span>;</span><br>    <span>}</span><br><br>    <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_REUSEADDR<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>;</span><br>    <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_KEEPALIVE<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>flags<span>,</span> <span>sizeof</span><span>(</span>flags<span>)</span><span>)</span><span>;</span><br>    <span>setsockopt</span><span>(</span>sfd<span>,</span> SOL_SOCKET<span>,</span> SO_LINGER<span>,</span> <span>(</span><span>void</span> <span>*</span><span>)</span><span>&</span>ling<span>,</span> <span>sizeof</span><span>(</span>ling<span>)</span><span>)</span><span>;</span><br><br>    </font><font face="新宋体"><span>/*<br>     * the memset call clears nonstandard fields in some impementations<br>     * that otherwise mess things up.<br>     */</span><br>    <span>memset</span><span>(</span><span>&</span>addr<span>,</span> 0<span>,</span> <span>sizeof</span><span>(</span>addr<span>)</span><span>)</span><span>;</span><br><br>    addr<span>.</span>sun_family <span>=</span> <span>AF_UNIX</span><span>;</span><br>    <span>strncpy</span><span>(</span>addr<span>.</span>sun_path<span>,</span> path<span>,</span> <span>sizeof</span><span>(</span>addr<span>.</span>sun_path<span>)</span> <span>-</span> 1<span>)</span><span>;</span><br>    <span>assert</span><span>(</span><span>strcmp</span><span>(</span>addr<span>.</span>sun_path<span>,</span> path<span>)</span> <span>=</span><span>=</span> 0<span>)</span><span>;</span><br>    old_umask <span>=</span> umask<span>(</span> <span>~</span><span>(</span>access_mask<span>&</span>0777<span>)</span><span>)</span><span>;</span><br>    <span>if</span> <span>(</span><span>bind</span><span>(</span>sfd<span>,</span> <span>(</span><span>struct</span> <span>sockaddr</span> <span>*</span><span>)</span><span>&</span>addr<span>,</span> <span>sizeof</span><span>(</span>addr<span>)</span><span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>        <span>perror</span><span>(</span><span>"bind()"</span><span>)</span><span>;</span><br>        <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>        umask<span>(</span>old_umask<span>)</span><span>;</span><br>        <span>return</span> 1<span>;</span><br>    <span>}</span><br>    umask<span>(</span>old_umask<span>)</span><span>;</span><br>    <span>if</span> <span>(</span><span>listen</span><span>(</span>sfd<span>,</span> settings<span>.</span>backlog<span>)</span> <span>=</span><span>=</span> <span>-</span>1<span>)</span> <span>{</span><br>        <span>perror</span><span>(</span><span>"listen()"</span><span>)</span><span>;</span><br>        <span>close</span><span>(</span>sfd<span>)</span><span>;</span><br>        <span>return</span> 1<span>;</span><br>    <span>}</span><br>    <span>if</span> <span>(</span><span>!</span><span>(</span>listen_conn <span>=</span> conn_new<span>(</span>sfd<span>,</span> conn_listening<span>, //同样是调用conn_new</span><br>                                 EV_READ <span>|</span> EV_PERSIST<span>,</span> 1<span>,</span><br>                                 local_transport<span>,</span> main_base<span>)</span><span>)</span><span>)</span> <span>{</span><br>        <span>fprintf</span><span>(</span><span>stderr</span><span>,</span> <span>"failed to create listening connection\n"</span><span>)</span><span>;</span><br>        <span>exit</span><span>(</span><span>EXIT_FAILURE</span><span>)</span><span>;</span><br>    <span>}</span><br><br>    <span>return</span> 0<span>;</span><br><span>}</span></font><br></span>


Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn

Heiße KI -Werkzeuge

Undresser.AI Undress

Undresser.AI Undress

KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover

AI Clothes Remover

Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool

Undress AI Tool

Ausziehbilder kostenlos

Clothoff.io

Clothoff.io

KI-Kleiderentferner

AI Hentai Generator

AI Hentai Generator

Erstellen Sie kostenlos Ai Hentai.

Heißer Artikel

R.E.P.O. Energiekristalle erklärten und was sie tun (gelber Kristall)
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. Beste grafische Einstellungen
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. So reparieren Sie Audio, wenn Sie niemanden hören können
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25: Wie man alles in Myrise freischaltet
3 Wochen vor By 尊渡假赌尊渡假赌尊渡假赌

Heiße Werkzeuge

Notepad++7.3.1

Notepad++7.3.1

Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version

SublimeText3 chinesische Version

Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1

Senden Sie Studio 13.0.1

Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6

Dreamweaver CS6

Visuelle Webentwicklungstools

SublimeText3 Mac-Version

SublimeText3 Mac-Version

Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Entdecken Sie die zukünftigen Entwicklungstrends der Go-Sprache Entdecken Sie die zukünftigen Entwicklungstrends der Go-Sprache Mar 24, 2024 pm 01:42 PM

Titel: Erkundung der zukünftigen Entwicklungstrends der Go-Sprache Mit der rasanten Entwicklung der Internettechnologie werden auch Programmiersprachen ständig weiterentwickelt und verbessert. Unter anderem ist die von Google entwickelte Open-Source-Programmiersprache Go (Golang) wegen ihrer Einfachheit, Effizienz und Parallelitätsfunktionen sehr gefragt. Da immer mehr Unternehmen und Entwickler beginnen, die Go-Sprache zum Erstellen von Anwendungen zu verwenden, hat der zukünftige Entwicklungstrend der Go-Sprache große Aufmerksamkeit erregt. 1. Eigenschaften und Vorteile der Go-Sprache Die Go-Sprache ist eine statisch typisierte Programmiersprache mit Garbage-Collection-Mechanismus und

Enthüllung der Geheimnisse der Leinwandeigenschaften Enthüllung der Geheimnisse der Leinwandeigenschaften Jan 17, 2024 am 10:08 AM

Um die Geheimnisse des Canvas-Attributs zu erkunden, benötigen Sie spezifische Codebeispiele. Canvas ist ein sehr leistungsfähiges Grafik-Zeichentool in HTML5. Damit können wir problemlos komplexe Grafiken, dynamische Effekte, Spiele usw. auf Webseiten zeichnen. Um es verwenden zu können, müssen wir jedoch mit den zugehörigen Eigenschaften und Methoden von Canvas vertraut sein und deren Verwendung beherrschen. In diesem Artikel werden wir einige der Kerneigenschaften von Canvas untersuchen und spezifische Codebeispiele bereitstellen, um den Lesern zu helfen, besser zu verstehen, wie diese Eigenschaften verwendet werden sollten.

Trezor Cold Wallet: Funktions- und Nutzungshandbuch für Model One und Model T Trezor Cold Wallet: Funktions- und Nutzungshandbuch für Model One und Model T Jan 19, 2024 pm 04:12 PM

Nachdem an vielen zentralisierten Börsen Probleme aufgetreten waren, begannen immer mehr Kryptowährungsinvestoren, Vermögenswerte auf Cold Wallets zu übertragen, um die von zentralisierten Börsen ausgehenden Risiken zu verringern. In diesem Artikel wird Trezor vorgestellt, der weltweit erste Cold Wallet-Anbieter. Seit der Einführung des ersten Cold Wallets im Jahr 2014 wurde es in vielen Ländern auf der ganzen Welt verkauft. Zu den Produkten von Trezor gehören das 2014 eingeführte Model One und die 2018 eingeführte Weiterentwicklung des Model T. Im Folgenden werden weiterhin die Unterschiede zwischen diesen beiden Produkten und anderen Cold Wallets vorgestellt. Was ist Trezor Cold Wallet? Im Jahr 2014 brachte Trezor das erste Cold Wallet ModelOne auf den Markt. Neben gängigen BTC, ETH, USDT und anderen Währungen unterstützt das Wallet auch mehr als 1.000 weitere Währungen.

Erkundung häufig verwendeter Datenbankauswahlen in der Go-Sprache Erkundung häufig verwendeter Datenbankauswahlen in der Go-Sprache Jan 28, 2024 am 08:04 AM

Entdecken Sie häufig verwendete Datenbankauswahlen in der Go-Sprache. Einführung: In der modernen Softwareentwicklung, egal ob es sich um Webanwendungen, mobile Anwendungen oder Internet-of-Things-Anwendungen handelt, sind Datenspeicherung und Abfrage untrennbar miteinander verbunden. In der Go-Sprache verfügen wir über viele hervorragende Datenbankoptionen. In diesem Artikel werden häufig verwendete Datenbankoptionen in der Go-Sprache untersucht und spezifische Codebeispiele bereitgestellt, um den Lesern das Verständnis und die Auswahl einer Datenbank zu erleichtern, die ihren Anforderungen entspricht. 1. SQL-Datenbank MySQL MySQL ist ein beliebtes relationales Open-Source-Datenbankverwaltungssystem. Es unterstützt eine Vielzahl von Funktionen und

Ich werde mit einem Rucksack nach Tibet reisen. ① Wie viele Liter Gepäck kann ich zum ersten Mal mitnehmen? Ich werde mit einem Rucksack nach Tibet reisen. ① Wie viele Liter Gepäck kann ich zum ersten Mal mitnehmen? Jan 07, 2024 am 10:06 AM

Ich plane eine Rucksacktour in Tibet. ① Sagen Sie mir bitte, was die beste Konfiguration ist. Ich bin 170 und habe eine gute körperliche Stärke Liter oder mehr. Die gesamte Reise dauerte nicht mit dem Auto, ein Koffer ist praktischer, wenn man etwas mitnehmen muss Tasche ist mehr als genug. Notwendige Utensilien für Reisen nach Tibet: Sonnenbrille, Sonnenhut, Sonnencreme, Hautcreme, langärmelige Oberteile, Pullover für besondere Reisen oder Reisen nach Ali, Nordtibet und zur Sichuan-Tibet-Linie Es wird empfohlen, Folgendes mitzubringen: Schlafsack (Kälteschutz), Laken (Schmutzschutz), Daunenjacke, Reise- oder Wanderschuhe, Hausschuhe, Zahnbürste, Zahnpasta, Handtuch, Zigarettenpapier, Papierunterwäsche, Desinfektionstücher, Taschenlampe, wasserfeste Streichhölzer, Messer , Seil. Kann ein Computer in der Vordertasche transportiert werden? Kann ein Computer in der Vordertasche transportiert werden?

Erkunden der Graphprogrammierung in Go: Möglichkeiten der Implementierung von Graph-APIs Erkunden der Graphprogrammierung in Go: Möglichkeiten der Implementierung von Graph-APIs Mar 25, 2024 am 11:03 AM

Erforschung der Grafikprogrammierung in der Go-Sprache: die Möglichkeit der Implementierung von Grafik-APIs Mit der kontinuierlichen Weiterentwicklung der Computertechnologie ist die Grafikprogrammierung zu einem wichtigen Anwendungsgebiet in der Informatik geworden. Durch Grafikprogrammierung können wir verschiedene exquisite grafische Schnittstellen, Animationseffekte und Datenvisualisierungen realisieren und den Benutzern ein intuitiveres und benutzerfreundlicheres interaktives Erlebnis bieten. Mit der rasanten Entwicklung der Go-Sprache in den letzten Jahren haben immer mehr Entwickler begonnen, ihre Aufmerksamkeit auf die Anwendung der Go-Sprache im Bereich der Grafikprogrammierung zu richten. In diesem Artikel befassen wir uns mit der Implementierung

Eine ausführliche Untersuchung der Verteilung des Linux-Kernel-Quellcodes Eine ausführliche Untersuchung der Verteilung des Linux-Kernel-Quellcodes Mar 15, 2024 am 10:21 AM

Dies ist ein Artikel mit 1500 Wörtern, der die Verteilung des Linux-Kernel-Quellcodes eingehend untersucht. Aufgrund des begrenzten Platzes konzentrieren wir uns auf die Organisationsstruktur des Linux-Kernel-Quellcodes und stellen einige spezifische Codebeispiele bereit, um den Lesern ein besseres Verständnis zu ermöglichen. Der Linux-Kernel ist ein Open-Source-Betriebssystemkernel, dessen Quellcode auf GitHub gehostet wird. Die gesamte Quellcodeverteilung des Linux-Kernels ist sehr umfangreich und enthält Hunderttausende Codezeilen, die mehrere verschiedene Subsysteme und Module umfassen. Um ein tieferes Verständnis des Linux-Kernel-Quellcodes zu erlangen

Golang-Projekt enthüllt: Entdecken Sie beliebte Projekte in der Go-Sprache Golang-Projekt enthüllt: Entdecken Sie beliebte Projekte in der Go-Sprache Feb 29, 2024 pm 04:09 PM

Golang-Projekt enthüllt: Entdecken Sie beliebte Projekte der Go-Sprache. Als effiziente, prägnante und leistungsstarke Programmiersprache hat die Go-Sprache in den letzten Jahren viel Aufmerksamkeit und Gunst bei Entwicklern auf sich gezogen. Unter vielen Projekten gibt es einige angesehene und beliebte Projekte, die aufgrund ihrer hohen Leistung, gleichzeitigen Verarbeitung, ihres prägnanten Codes und anderer Merkmale zum Fokus der Anziehungskraft einer großen Anzahl von Entwicklern geworden sind. Dieser Artikel führt die Leser dazu, diese hervorragenden Go-Projekte eingehend zu erkunden und spezifische Codebeispiele zu kombinieren, um die Designideen und technischen Implementierungen dahinter aufzuzeigen. 1.GinGin ist benutzerfreundlich

See all articles