데이터 베이스 MySQL 튜토리얼 memcached探索之thread model(2)

memcached探索之thread model(2)

Jun 07, 2016 pm 03:11 PM
memcached model thread 아래에 탐구하다

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>


본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

Go 언어의 미래 개발 동향을 살펴보세요 Go 언어의 미래 개발 동향을 살펴보세요 Mar 24, 2024 pm 01:42 PM

제목: Go 언어의 미래 개발 동향 탐구 인터넷 기술의 급속한 발전과 함께 프로그래밍 언어도 끊임없이 진화하고 발전하고 있습니다. 그중 Go 언어(Golang)는 구글이 개발한 오픈소스 프로그래밍 언어로 단순성, 효율성, 동시성 기능으로 많은 사랑을 받고 있습니다. 점점 더 많은 기업과 개발자가 애플리케이션 구축에 Go 언어를 채택하기 시작하면서 Go 언어의 향후 개발 동향이 많은 주목을 받고 있습니다. 1. Go 언어의 특징과 장점 Go 언어는 가비지 수집 메커니즘을 갖춘 정적인 유형의 프로그래밍 언어이며,

캔버스 속성의 비밀을 밝히다 캔버스 속성의 비밀을 밝히다 Jan 17, 2024 am 10:08 AM

캔버스 속성의 비밀을 탐색하려면 구체적인 코드 예제가 필요합니다. 캔버스는 HTML5의 매우 강력한 그래픽 그리기 도구를 통해 웹 페이지에 복잡한 그래픽, 동적 효과, 게임 등을 쉽게 그릴 수 있습니다. 하지만 이를 사용하기 위해서는 Canvas의 관련 속성과 메소드를 숙지하고 사용법을 익혀야 합니다. 이 기사에서는 Canvas의 핵심 속성 중 일부를 살펴보고 특정 코드 예제를 제공하여 독자가 이러한 속성을 사용하는 방법을 더 잘 이해할 수 있도록 돕습니다.

Trezor Cold Wallet: Model One 및 Model T 기능 및 사용 가이드 Trezor Cold Wallet: Model One 및 Model T 기능 및 사용 가이드 Jan 19, 2024 pm 04:12 PM

많은 중앙화된 거래소에서 문제가 발생한 후 점점 더 많은 통화 투자자들이 중앙화된 거래소에서 발생하는 위험을 줄이기 위해 자산을 콜드 지갑으로 이전하기 시작했습니다. 이 글에서는 세계 최초의 콜드월렛 제공업체인 Trezor를 소개하겠습니다. 2014년 최초의 콜드월렛이 출시된 이후 전 세계 여러 나라에서 판매되고 있습니다. Trezor의 제품에는 2014년에 출시된 Model One과 2018년에 출시된 고급 버전인 Model T가 포함됩니다. 다음에서는 계속해서 이 두 제품과 다른 콜드월렛의 차이점을 소개하겠습니다. Trezor 콜드월렛이란 무엇인가요? 2014년 Trezor는 최초의 콜드 지갑 ModelOne을 출시했습니다. 일반적인 BTC, ETH, USDT 및 기타 통화 외에도 지갑은 1,000개 이상의 다른 통화도 지원합니다.

Go 언어에서 일반적으로 사용되는 데이터베이스 선택 탐색 Go 언어에서 일반적으로 사용되는 데이터베이스 선택 탐색 Jan 28, 2024 am 08:04 AM

Go 언어에서 일반적으로 사용되는 데이터베이스 선택 탐색 소개: 최신 소프트웨어 개발에서는 웹 애플리케이션, 모바일 애플리케이션, 사물 인터넷 애플리케이션 등 데이터 저장과 쿼리가 분리될 수 없습니다. Go 언어에는 뛰어난 데이터베이스 옵션이 많이 있습니다. 이 기사에서는 Go 언어에서 일반적으로 사용되는 데이터베이스 선택을 살펴보고 독자가 자신의 필요에 맞는 데이터베이스를 이해하고 선택하는 데 도움이 되는 특정 코드 예제를 제공합니다. 1. SQL 데이터베이스 MySQL MySQL은 인기 있는 오픈 소스 관계형 데이터베이스 관리 시스템입니다. 다양한 기능을 지원하며,

배낭을 메고 티베트 여행을 갑니다. ① 제가 가지고 다니는 가방은 몇 리터 정도가 적당하다고 생각하시나요? 저는 170인데 처음으로 체력이 좋습니다. 배낭을 메고 티베트 여행을 갑니다. ① 제가 가지고 다니는 가방은 몇 리터 정도가 적당하다고 생각하시나요? 저는 170인데 처음으로 체력이 좋습니다. Jan 07, 2024 am 10:06 AM

티베트로 배낭여행을 가려고 합니다. ① 가방은 몇 리터 정도 가지고 가는 것이 가장 좋은지 알려주세요. 170인데 체력이 처음이라 60 정도 들어갔습니다. 리터 이상. 전체 여행은 자동차로 이루어졌습니다. 배낭이 필요하지 않으면 25-40 리터의 여행 가방이 더 편리합니다. 티베트 여행에 필요한 물품: 선글라스, 선햇, 자외선 차단제, 스킨 크림, 립밤, 긴팔 상의, 특별한 여행이나 알리, 북부 티베트 및 쓰촨-티베트 노선 여행을 위한 스웨터. 지참 권장사항: 침낭(방한용품), 시트(더러움 방지용품), 다운 재킷, 여행용 신발 또는 등산화, 슬리퍼, 칫솔, 치약, 수건, 롤링페이퍼, 종이 속옷, 소독 물티슈, 손전등, 방수 성냥, 칼 , 로프. 컴퓨터를 앞가방에 넣을 수 있나요? 일부 백팩에는 컴퓨터를 넣을 수 있나요?

Go에서 그래프 프로그래밍 살펴보기: 그래프 API 구현 가능성 Go에서 그래프 프로그래밍 살펴보기: 그래프 API 구현 가능성 Mar 25, 2024 am 11:03 AM

Go 언어의 그래픽 프로그래밍 탐구: 그래픽 API 구현 가능성 컴퓨터 기술의 지속적인 발전으로 그래픽 프로그래밍은 컴퓨터 과학에서 중요한 응용 분야가 되었습니다. 그래픽 프로그래밍을 통해 다양하고 정교한 그래픽 인터페이스, 애니메이션 효과 및 데이터 시각화를 실현하여 사용자에게 보다 직관적이고 친숙한 대화형 경험을 제공할 수 있습니다. 최근 몇 년간 Go 언어의 급속한 발전으로 점점 더 많은 개발자들이 그래픽 프로그래밍 분야에서 Go 언어 적용에 관심을 돌리기 시작했습니다. 이 기사에서는 구현 방법을 살펴보겠습니다.

Linux 커널 소스 코드 배포에 대한 심층 탐구 Linux 커널 소스 코드 배포에 대한 심층 탐구 Mar 15, 2024 am 10:21 AM

이것은 Linux 커널 소스 코드 배포를 심층적으로 탐구하는 1500 단어 분량의 기사입니다. 제한된 공간으로 인해 Linux 커널 소스 코드의 조직 구조에 중점을 두고 독자의 이해를 돕기 위해 몇 가지 구체적인 코드 예제를 제공합니다. Linux 커널은 소스 코드가 GitHub에서 호스팅되는 오픈 소스 운영 체제 커널입니다. 전체 Linux 커널 소스 코드 배포판은 매우 방대하며 여러 하위 시스템 및 모듈과 관련된 수십만 줄의 코드를 포함합니다. Linux 커널 소스 코드를 더 깊이 이해하려면

Golang 프로젝트 공개: Go 언어로 인기 있는 프로젝트 탐색 Golang 프로젝트 공개: Go 언어로 인기 있는 프로젝트 탐색 Feb 29, 2024 pm 04:09 PM

Golang 프로젝트 공개: Go 언어의 인기 프로젝트 살펴보기 효율적이고 간결하며 강력한 프로그래밍 언어인 Go 언어는 최근 몇 년간 개발자들로부터 많은 관심과 호감을 불러일으켰습니다. 많은 프로젝트 중에는 높은 성능, 동시 처리, 간결한 코드 및 기타 특성으로 인해 많은 개발자의 관심을 끄는 존경 받고 인기 있는 프로젝트가 있습니다. 이 기사에서는 독자들이 이러한 뛰어난 Go 프로젝트를 심층적으로 탐색하고 특정 코드 예제를 결합하여 그 뒤에 있는 디자인 아이디어와 엔지니어링 구현을 공개하도록 안내합니다. 1.GinGin은 사용자 친화적입니다.

See all articles