<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>
|