您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 企业财务 > LWIP之SOCKET的实现
LWIP之SOCKET的实现协议栈的实现目的,无非是要上层用来实现app的socket编程。好,我们就从socket开始。为了兼容性,lwip的socket应该也是提供标准的socket接口函数,恩,没错,在src\include\lwip\socket.h文件中可以看到下面的宏定义:#ifLWIP_COMPAT_SOCKETS#defineaccept(a,b,c)lwip_accept(a,b,c)#definebind(a,b,c)lwip_bind(a,b,c)#defineshutdown(a,b)lwip_shutdown(a,b)#defineclosesocket(s)lwip_close(s)#defineconnect(a,b,c)lwip_connect(a,b,c)#definegetsockname(a,b,c)lwip_getsockname(a,b,c)#definegetpeername(a,b,c)lwip_getpeername(a,b,c)#definesetsockopt(a,b,c,d,e)lwip_setsockopt(a,b,c,d,e)#definegetsockopt(a,b,c,d,e)lwip_getsockopt(a,b,c,d,e)#definelisten(a,b)lwip_listen(a,b)#definerecv(a,b,c,d)lwip_recv(a,b,c,d)#definerecvfrom(a,b,c,d,e,f)lwip_recvfrom(a,b,c,d,e,f)#definesend(a,b,c,d)lwip_send(a,b,c,d)#definesendto(a,b,c,d,e,f)lwip_sendto(a,b,c,d,e,f)#definesocket(a,b,c)lwip_socket(a,b,c)#defineselect(a,b,c,d,e)lwip_select(a,b,c,d,e)#defineioctlsocket(a,b,c)lwip_ioctl(a,b,c)#ifLWIP_POSIX_SOCKETS_IO_NAMES#defineread(a,b,c)lwip_read(a,b,c)#definewrite(a,b,c)lwip_write(a,b,c)#defineclose(s)lwip_close(s)先不说实际的实现函数,光看这些定义的宏,就是标准socket所必须有的接口。接着看这些实际的函数实现。这些函数实现在src\api\socket.c中。先看下接受连接的函数,这个是tcp的原型:intlwip_accept(ints,structsockaddr*addr,socklen_t*addrlen)可以看到这里的socket类型参数s,实际上是个int型在这个函数中的第一个函数调用是sock=get_socket(s);这里的sock变量类型是lwip_socket,定义如下:/**Containsallinternalpointersandstatesusedforasocket*/structlwip_socket{/**socketscurrentlyarebuiltonnetconns,eachsockethasonenetconn*/structnetconn*conn;/**datathatwasleftfromthepreviousread*/structnetbuf*lastdata;/**offsetinthedatathatwasleftfromthepreviousread*/u16_tlastoffset;/**numberoftimesdatawasreceived,setbyevent_callback(),testedbythereceiveandselectfunctions*/u16_trcvevent;/**numberoftimesdatawasreceived,setbyevent_callback(),testedbyselect*/u16_tsendevent;/**socketflags(currently,onlyusedforO_NONBLOCK)*/u16_tflags;/**lasterrorthatoccurredonthissocket*/interr;};好,这个结构先不管它,接着看下get_socket函数的实现【也是在src\api\socket.c文件中】,在这里我们看到这样一条语句sock=&sockets[s];很明显,返回值也是这个sock,它是根据传进来的序列号在sockets数组中找到对应的元素并返回该元素的地址。好了,那么这个sockets数组是在哪里被赋值了这些元素的呢?进行到这里似乎应该从标准的socket编程的开始,也就是socket函数讲起,那我们就顺便看一下。它对应的实际实现是下面这个函数Intlwip_socket(intdomain,inttype,intprotocol)【src\api\socket.c】这个函数根据不同的协议类型,也就是函数中的type参数,创建了一个netconn结构体的指针,接着就是用这个指针作为参数调用了alloc_socket函数,下面具体看下这个函数的实现staticintalloc_socket(structnetconn*newconn){inti;/*Protectsocketarray*/sys_sem_wait(socksem);/*allocateanewsocketidentifier*/for(i=0;iNUM_SOCKETS;++i){if(!sockets[i].conn){sockets[i].conn=newconn;sockets[i].lastdata=NULL;sockets[i].lastoffset=0;sockets[i].rcvevent=0;sockets[i].sendevent=1;/*TCPsendbufisempty*/sockets[i].flags=0;sockets[i].err=0;sys_sem_signal(socksem);returni;}}sys_sem_signal(socksem);return-1;}对了,就是这个时候对全局变量sockets数组的元素赋值的。既然都来到这里了,那就顺便看下netconn结构的情况吧。它的学名叫netconndescriptor/**Anetconndescriptor*/structnetconn{/**typeofthenetconn(TCP,UDPorRAW)*/enumnetconn_typetype;/**currentstateofthenetconn*/enumnetconn_statestate;/**thelwIPinternalprotocolcontrolblock*/union{structip_pcb*ip;structtcp_pcb*tcp;structudp_pcb*udp;structraw_pcb*raw;}pcb;/**thelasterrorthisnetconnhad*/err_terr;/**semthatisusedtosynchroneouslyexecutefunctionsinthecorecontext*/sys_sem_top_completed;/**mboxwherereceivedpacketsarestoreduntiltheyarefetchedbythenetconnapplicationthread(cangrowquitebig)*/sys_mbox_trecvmbox;/**mboxwherenewconnectionsarestoreduntilprocessedbytheapplicationthread*/sys_mbox_tacceptmbox;/**onlyusedforsocketlayer*/intsocket;#ifLWIP_SO_RCVTIMEO/**timeouttowaitfornewdatatobereceived(orconnectionstoarriveforlisteningnetconns)*/intrecv_timeout;#endif/*LWIP_SO_RCVTIMEO*/#ifLWIP_SO_RCVBUF/**maximumamountofbytesqueuedinrecvmbox*/intrecv_bufsize;#endif/*LWIP_SO_RCVBUF*/u16_trecv_avail;/**TCP:whendatapassedtonetconn_writedoesn'tfitintothesendbuffer,thistemporarilystoresthemessage.*/structapi_msg_msg*write_msg;/**TCP:whendatapassedtonetconn_writedoesn'tfitintothesendbuffer,thistemporarilystoreshowmuchisalreadysent.*/intwrite_offset;#ifLWIP_TCPIP_CORE_LOCKING/**TCP:whendatapassedtonetconn_writedoesn'tfitintothesendbuffer,thistemporarilystoreswhethertowakeuptheoriginalapplicationtaskifdatacouldn'tbesentinthefirsttry.*/u8_twrite_delayed;#endif/*LWIP_TCPIP_CORE_LOCKING*//**Acallbackfunctionthatisinformedabouteventsforthisnetconn*/netconn_callbackcallback;};【src\include\lwip\api.h】到此,对这个结构都有些什么,做了一个大概的了解。下面以SOCK_STREAM类型为例,看下netconn的new过程:在lwip_socket函数中有caseSOCK_DGRAM:conn=netconn_new_with_callback((protocol==IPPROTO_UDPLITE)?NETCONN_UDPLITE:NETCONN_UDP,event_callback);#definenetconn_new_with_callback(t,c)netconn_new_with_proto_and_callback(t,0,c)简略实现如下:structnetconn*netconn_new_with_proto_and_callback(enumnetconn_typet,u8_tproto,netconn_callbackcallback){structnetconn*conn;structapi_msgmsg;conn=netconn_alloc(t,callback);if(conn!=NULL){msg.function=do_newconn;msg.msg.msg.n.proto=proto;msg.msg.conn=conn;TCPIP_APIMSG(&msg);}returnconn;}主要就看TCPIP_APIMSG了,这个宏有两个定义,一个是LWIP_TCPIP_CORE_LOCKING的,一个非locking的。分别分析这两个不同类型的函数*Callthelowerpartofanetconn_*function*Thisfunctionhasexclusiveacce
本文标题:LWIP之SOCKET的实现
链接地址:https://www.777doc.com/doc-5509708 .html