您的当前位置:首页正文

net develop (socket)

2021-11-12 来源:意榕旅游网
ACrashCourseinUNIXTCP/IPSocketProgrammingJohnSelbieCEN4500Spring1997

Introduction

A\"socket\"isaloosetermusedtodescribe\"anendpointforcommunication.\"ThetraditionalBerkleySocketAPIisasetofCfunctioncallsusedtosupportnetworkcommunication.TheSocketsAPIisnotspecifictoTCP/IP.Therefore,developingTCP/IPnetworkapplicationsrequiresslightlymoreoverheadofprogrammingandunderstandingtoaccountforthegenericparametersofthelibrary'sfunctioncalls.Onceunderstood,Socketprogrammingisaseasyasreadingandwritingtodiskfiles.

ThematerialpresentedhereissomewhatspecifictoC,UNIX,andTCP/IP.HoweverthegeneralformatfortheSocketAPIhasbeenportedtosuchlanguagesasJavaandPerl.InadditionsomeUNIXvendorssupportotherprotocolssuchasIPX,SNA,andDEC-NETwiththeirsocketlibraries.TheMicrosoftWindowsversionoftheSocketAPI(\"WinSock\")isalsoverysimilar.It'sbelievedthatonceasoftwaredevelopergainsagoodunderstandingofUNIX/CSockets,heorshecanquicklyunderstandimplementationsforotherlanguagesandoperatingsystems.

IncludeFiles

WhenwritingCorC++programsthatusethesocketlibrarygoaheadandincludealltheseheaderfiles:

UNIX:

#include#include#include#include#include#include#include#include#include#include#include#include#include

CompilingandLinking

UndermostversionsofUNIX(Linux,BSD,SunOS,IRIX)compilingisdoneasusual:gccmy_socket_program.c-omy_socket_program

However,Solarisrequiresthedevelopertoexplicitlylinkthesocketandnetworkserviceslibrarywiththeprogram:

ccmy_socket_program-omy_socket_program-lsocket-lnsl

TheSolarisCcompilerthatisusuallylocatedin/opt/SUNWspro/bin,isrecommendedovergcc.

ApplicationsandTCP/IP

ProgramswrittenbyasoftwaredevelopermayuseeitherTCPorUDPforcommunicatingwithremotehostsontheInternet.BothareservicesthatworkontopoftheIPnetworkprotocol.TCPisareliable\"streams\"servicethatrequiresaconnectionestablishmentphasebetweenahostmakinganactiveconnectiontoaremoteserverhostmakingapassiveone.UDPisanunreliabledatagramserviceanddoesnotrequireanyconnectionestablishmentbeforesending.ThegeneralorderoflibrarycallsforaUDPcommunicationsessionisasfollows:socket()bind()

sendto()and/orrecvfrom()close()

ForTCPclients,theorderoflibrarycallsisasfollows:socket()bind()connect()

send()and/orrecv()close()

ForTCPserverprograms,theorderoflibrarycallsisasfollows:socket()bind()

listen()accept()

send()and/orrecv()close()

SocketAddressStructures

Fromanapplicationprogrammingpointofview,theonlydifferencesbetweennetworkprotocolsaretheaddressschemesused.Otherwise,operationssuchasconnect,send,receive,anddisconnectareprobablytheonlythingsadeveloperhastothinkaboutwhendesigninganetworkapplication.ForTCP/IP,anidealAPIwouldbeonethatunderstoodIPaddressesandportnumbers.Sincethesocketlibraryisdesignedtobeusedformultipleprotocols,addressesarereferencedbyageneric

structureasfollows:structsockaddr{

unsignedshortsa_family;charsa_data[14];};Thesa_familyfieldspecifiesthetypeofprotocol.ForTCP/IP,thisfieldisalwayssettoAF_INET.Theremaining14bytes(sa_data)ofthisstructurearealwaysprotocoldependent.ForTCP/IP,IPaddressesandportnumbersareplacedinthisfield.Tofacilitateoperatingwiththesefields,aspecifictypeofsocketaddressstructureisusedinsteadoftheoneabove.structsockaddr_in{shortsin_family;unsignedshortsin_port;structin_addrsin_addr;charsin_zero[8];};

Ifit'snotalreadyapparent,thesestructuresarecompatiblewitheachother.Theybothare16bytesinsize.Itisalsoreadilyseenthatthefirsttwobytesofeachstructurearethefamilyfield.Thus,astructsockaddr_incanalwaysbecasttoastructsockaddr.Asockaddr_instructurecontainsanin_addrstructureasamemberfield.Ithasthefollowingformstructin_addr{

unsignedlongs_addr;};

Browsingtheheaderfilerevealsthatthisreallyisn'ttheformofthestructure.It'sreallyaverycomplicateduniondesignedtoholdanIPaddressinavarietyofways.Regardless,thein_addrstructisexactly4byteslong,whichisthesamesizeasanIPaddress.Inthesockaddr_instructure,thesin_portfieldisa16-bitunsignedvalueusedtorepresentaportnumber.It'simportanttorememberthatthesefieldsalwaysneedtobesetandinterpretedinnetworkbyteorder.Forexample:

structsockaddr_insin;sin.sin_family=AF_INET;sin.sin_port=htons(9999)

sin.sin_addr.s_addr=inet_addr(\"128.227.224.3\");

Intheabovecodeexample,thestructuresin,holdstheIPaddress,128.227.224.3,andreferencestheportnumber9999.Twoutilityfunctionsareusedtosetthesevalues.Thefunctionhtonsreturnstheintegerargumentpassedintoitinnetworkbyteorder.Thefunctioninet_addrconvertsthestringargumentfromadotted-quadintoa32-bitinteger.Itsreturnvalueisalsoinnetworkbyteorder.

Thestructureabovecouldbeusedtoreferenceahostandapplicationinwhichadatagramistobedelivered.Theusesofthesockaddr_instructurewillbecoveredinmoredetailbelow.

socket

Thesocketlibrarycallhasthefollowingprototype:intsocket(intfamily,inttype,intprotocol);

Inshort,thisfunctioncreates\"anendpointforcommunication\".Thereturnvaluefromthisfunctionisahandletoasocket.Thisnumberispassedasaparametertoalmostalloftheotherlibrarycalls.

SincethefocusofthisdocumentisonTCP/IPbasedsockets,thefamilyparametershouldbesettoAF_INET.ThetypeparametercanbeeitherSOCK_STREAM(forTCP),orSOCK_DGRAM(forUDP).Theprotocolfieldisintendedforspecifyingaspecificprotocolincasethenetworkmodelsupportdifferenttypesofstreamanddatagrammodels.However,TCP/IPonlyhasoneprotocolforeach,sothisfieldshouldalwaysbesetto0.Examples:

TocreateaUDPsocket:

ints;

s=socket(AF_INET,SOCK_DGRAM,0);TocreateaTCPsocket:

ints;

s=socket(AF_INET,SOCK_STREAM,0);

bind

Beforesendingandreceivingdatawithasocket,itmustfirstbeassociatedwithalocalsourceportandanetworkinterfaceaddress.ThemappingofasockettoaTCP/UDPsourceportandIPaddressiscalleda\"binding\".

Itmaybethecasewherethesocketisbeingusedasaserver,andthusmustbeabletolistenforclientrequestsonaspecificport.Itcanalsobethecasethataclientprogramdoesn'tneedaspecificsourceport,sinceallit'sconcernedaboutdoingissendingandreceivingmessageswitha

specificportontheremotehost.

Furthercomplicationsarisewhentherearemorethanonenetworkdevicesonthehostrunningtheprogram.Sothequestionofsendingthrough\"whichnetwork\"mustbeansweredaswell.Thebindfunctioncallisusedtodeclarethemappingbetweenthesocket,theTCP/UDPsourceport,andthenetworkinterfacedevice.Theprototypeforbindisasfollows:

bind(intsocket,structsockaddr*address,intaddress_length);

Thefirstargumentisasockethandle(thenumberreturnedfromthesocketfunctioncall).Thesecondargumentisasocketaddressstructure.WithTCP/IP,thisisreallyasockaddr_instructure.Thesin_portfieldoftheaddressargumentisthelocalsourceportnumberassociatedwiththissocket.Thatis,forevery\"send\"operationwiththissocket,thesourceportfieldintheTCP/UDPheadergetssetwiththisvalue.Ifspecifyinganexactsourceportisnotrequired,settingthisvaluetoINADDR_ANY(0)allowstheoperatingsystemtopickanyavailableportnumber.Thesin_addrfieldspecifieswhichnetworkinterfacedevicetouse.SincemosthostsonlyhaveonenetworkinterfaceandonlyoneIPaddress,thisfieldshouldbesetwiththehost'sownIPaddress.However,thesocketlibraryprovidesnoimmediatewayofforahosttodetermineit'sownIPaddress!However,specifyingthevalueofINADDR_ANY(0)inthisfieldtellstheoperatingsystemtopickanyavailableinterfaceandaddress.

Theaddressofthesockaddr_instructureispassedintothebindcall,sothatthesocketwillnowbereadytocommunicatewithremotehosts.Thethirdparameterpassedtobindisthelengthofthesockaddr_instructure.Example:

structsockaddr_insin;ints;

s=socket(AF_INET,SOCK_DGRAM,0);sin.sin_family=AF_INET;sin.sin_port=htons(9999);

sin.sin_addr.s_addr=INADDR_ANY;bind(s,(structsockaddr*)&sin,sizeof(sin));

/*sisnowausableUDPsocket.Sourceportis9999*/

Itisrecommendedthatthereturnfrombindbechecked.Bindwillfailbyreturning-1iftheportthatisbeingrequestedforuseisalreadytaken.WhenbindiscalledonaUDPsocket,thesocketisnowreadytosendandreceivedatagrams.ForTCPsockets,thesocketisnowreadyforthe

connectoracceptcalls.UDPSockets

OnceaUDPsockethasbeencreatedandboundtoalocalsourceport,itisnowcapableofbeingusedforsendingandreceivingdatagrams.Thefunctionsforsendingandreceivingdatagramsaresendtoandrecvfom.Sendtohasthefollowingprototype:

intsendto(intsocket,char*buffer,intlength,intflags,structsockaddr*destination_address,intaddress_size);

WheresocketisaUDPsocketthathasbeencreatedandboundtoasourceport.bufferisapointertoanarrayofbytesthataretobesentoverthenetwork.Thelengthfieldspecifieshowlongthisarrayis.Theflagsfieldisnormally0.

Thedestinationaddressisalsoasockaddrstructure.Asockaddr_instructurecanbecastedintothisfield.Usethesin_addrfieldtospecifythedestinationIPaddressandsin_portforthedestinationport.Forexample:

structsockaddr_insin;sin.sin_family=AF_INET;

sin.sin_port=htons(12345);//htonsfornetworkbyteordersin.sin_addr.s_addr=inet_addr(\"128.227.22.43\");char*msg=\"Hello,World\";

sendto(s,msg,strlen(msg)+1,0,(structsockaddr*)sin,sizeof(sin));

Intheaboveexample,sisassumedtobeacreatedUDPsocketthathasalreadyboundtoalocalport.Whensendtoiscalled,aUDPdatagramissenttothehostat128.227.22.43.It'sassumedthereisaprocesswithasocketboundtoport12345waitingonarecvfromcalltoreceivethecontentsofthemessagebeingsent.Thesendtofunctionreturnsthenumberofbytessent,or-1ifanerroroccurred.WithUDPsockets,it'snotusuallynecessarytochecktoseehowmanybytesweresentbecausethisinformationisspecifiedinthelengthfield.Recvfromhasthefollowingprototype:

intrecvfrom(intsocket,char*buffer,intlength,intflags,structsockaddr*sender_address,int*address_size);

Recvfromissimilartosendto.Bufferisapointertoabytearraythatistobefilledwiththecontentsofthedatagram.Thelengthargumentspecifiesthemaximumlengthtocopyintobuffer.Thisistopreventbufferover-runerrorsincasethedatagramislargerthanexpected.Theflagsfieldisnormally0.Thesender_addressargumentisapointertoasocketaddressstructurethatgetsfilledwithacopyofthesender'sIPaddressandsourceport.Theaddress_sizeparametermustbeinitializedtothesizeofthesockaddrstructurebeingused.Onreturnitwillholdthenumberofbytesthatwerecopiedintothesender_addressstructure.

Recvfromreturnsthenumberofbytescopiedintothebytearraypointedtobybuffer.Ifthebufferspacespecifiedinlengthislessthanthatoftheoriginaldatagram,onlylengthbyteswillbecopiedintobuffer,andtherestwillbelost.Forexample:structsockaddr_insin;charmsg[10000];intret;intsin_length;

sin_length=sizeof(sin);

ret=recvfrom(s,msg,10000,0,(structsockaddr*)sin,&sin_length);printf(\"%dbytesreceivedfrom%s(port%d)\\n\ret,inet_ntoa(sin.sin_addr),sin.sin_port);

Intheaboveexample,recvfromwillwaituntilitreceivesadatagramonthelocalportassociatedwiththesockets.Theprintfstatementwilllistinformationregardingthesize,sourceIPaddress,andsourceportofthedatagramreceived.

Foranyopensocketthathasbeensuccessfullybindedtoaport,theapplicationmaycallsendtoandrecvfromusingthatsocketasmanytimesasitneedsto.

Fragmentationiscompletelytransparenttotheapplicationsthataresendingandreceivingdatagrams.

TCPSockets

connect()

listen()/accept()send()recv()

close

Whenthedatatransfersessionisover,simplycallcloseonthesocketasyouwouldafile:

close(s);//sisacreatedsocket

ForUDPsockets,thiswillreleasetheownershiponthelocalportthatisboundtothissocket.ForTCP,thiswillinitiateatwo-wayshutdownbetweenbothhostsbeforegivingupportownership.IfaTCPsocketcallsclose,anypendingorsubsequentrecvcallsbytheremotehostwillresultinrecvreturning0toindicateaconnectionshutdownontheotherendhasoccurred.Attemptingtocallsendonasocketthatisconnectedtoahostthathascalledclosewillresultinsendreturning-1.Unlessit'sknownapriorithattheremotehosthasonlycalledshutdown,itisrecommendedthattheapplicationcallcloseonit'ssocketsothattheTCPconnectionwillbeproperlyterminatedonbothsides.shutdown

TCPsocketscanalsoengageinahalf-closeoperationusingtheshutdownfunctioncall.It'sprototypeisasfollows:shutdown(intsocket,inthow);

Ifthehowfieldis0,thiswilldisallowfurtherreading(recv)fromthesocket.Ifthehowfieldis1,subsequentwrites(send)willbedisallowed.Thesocketwillstillneedtobepassedtoclose.RelationshipBetweenSocketsandFileDescriptors

Sockethandlesareintegervalues.InUNIX,sockethandlescanbepassedtomostofthelow-levelPOSIXI/Ofunctions.Forexample:read(s,buffer,buffer_len);

Intheaboveexample,scouldbeeitherasocketorfilehandle.Callingreadonanopensocketisequivalenttorecvandrecvfrom.However,ifthesocketisUDP,theninformationaboutthesenderofthedatagramwillnotbereturned.Similarlythewritefunctioncallisequivalenttosendandsendto.UDPsocketsmaycallconnecttousesendandwrite.It'salwaysrecommendedthatthesocketlibraryfunctionsbeusedinsteadofthefileI/Oequivalents.UtilityFunctions

Thereareseverallibrarycallsthatarenotactuallypartofthesocketlibraryfamily,butareneverthelessusedinsocketprogramming.Belowisabriefdescriptionofeach.

unsignedintinet_addr(char*str);IfthestringcontainedinstrrepresentsanIPaddressitdotted-quadnotation,inet_addrwillreturnit'sequivalent32-bitvalueinnetworkbyteorder.Thisvaluecanbepassedintothesin_addr.s_addrfieldofasocketaddr_instructure.Ifthestringcannotbeinterpretedasadotted-quad,-1isreturned(castedasanunsignedinteger).

char*inet_ntoa(structin_addrip);Convertsthe32-bitvaluewhichisassumedtobeinnetworkbyteorderandcontainediniptoastring.Thepointerreturnedbyinet_ntoacontainsthisstring.However,subsequentcallstoinet_ntoawillalwaysreturnthesamepointer,socopyingthestringtoanotherbufferisrecommendedbeforecallingagain.

intgethostname(char*name,intlength);Copiesthename(uptolengthbytes)ofthehostnameofthelocalcomputerintothecharacterarraypointedtobyname.structhostent*gethostbyname(char*strHost);IfthestringcontainedinstrHostrepresentsahostname(suchas\"rain\"or\"rain.cise.ufl.edu\"),gethostbynamewillreturnapointertoahostentstructurecontainingadditionalinformationaboutthehostincludingadditionalnamesandIPaddressesassociatewiththathost.GethostbynamewilldoesalltheworkoflookingupaddressentriesinlocaldatabasefilesaswellasmakingDNSqueries.NULLisreturnedifthehostnameisunknown.Theformatforthehostentstructureisasfollows:

structhostent{

char*h_name;/*officialnameofhost*/char**h_aliases;/*aliaslist*/

shorth_addrtype;/*hostaddresstype*/shorth_length;/*lengthofaddress*/char**h_addr_list;/*listofaddresses*/

#defineh_addrh_addr_list[0]/*address,forbackwardcompat*/};

Inshort,thefirstIPaddressiscontainedwithinthefirst4bytesofthefirstentryinh_addr_list.h_addrcanbeusedtoreferencethisvalue.Usinggethostbynameandinet_addr,averygoodresolverfunctioncanbewrittentoconvertstringstheusertypesasInternetaddressesintoequivalent32-bitnumbersforsocketcalls.unsignedintresolve(char*ip_addr){

structhostent*hp;unsignedintip;

hp=gethostbyname(ip_addr);if(!hp){

ip=inet_addr(ip_addr);if((int)ip==-1)return-1;elsereturnip;}

//hp->h_lengthshouldequalto4memcpy(&ip,hp->h_addr,4);returnip;}

unsignedlonghtonl(unsignedlongul);

unsignedlongntohl(unsignedlongul);unsignedshortntohs(unsignedshortus);unsignedshorthtons(unsignedshortus);

Thesefunctionsareveryusefulforconvertingintegervaluestoandfromnetworkbyteorder.Onbig-endianmachinessuchasSunSparcsandMotorolaprocessors,thesefunctionssimplyreturnthevaluepassedasanargument.OnlittleendianmachinessuchastheIntelx86andanysystemrunningWindowsNT,thesecallswillperformbyteswappingoperations.Onmostmachines,htonsisequivalenttontohs.Thismaynotbetrueforfuture64-bitsystemsorotherarchitectures.intselect(intnfds,fd_set*readfds,fd_set*writefds,fd_set*exceptfds,conststructtimeval*timeout);Whenanapplicationcallsrecvorrecvfromitisblockeduntildataarrivesforthatsocket.Anapplicationcouldbedoingotherusefulprocessingwhiletheincomingdatastreamisempty.Anotherpotentialproblemsituationiswhenanapplicationreceivesdatafrommultiplesockets.Callingrecvorrecvfromonasocketthathasnodatainit'sinputqueuepreventsimmediatereceptionofdatafromothersockets.Theselectfunctioncallsolvesthisproblembyallowingtheprogramtopollallthesockethandlestoseeiftheyareavailablefornon-blockingreadingandwritingoperations.

Adescriptionoftheargumentsinselectisasfollows:

nfds-Somesocketimplementationsignorethisargument.It'svalueshouldbeequalto1+(thesockethandlewiththehighestvalue.)

readfds-Apointertoasetoffileandsocketdescriptorsthataretobepolledfornon-blockingreadingandwritingoperations.CanbeNULLtoindicateanemptyset.

writefds,exceptfds-Sameasreadfds,exceptthesesetscontainthefile/sockethandlestopollfornon-blockingwritingoperationsanderrordetection.CanbeNULLtoindicateanemptyset.timeout-Apointertoatimevalstructthatspecifieshowlongtheselectcallshouldpollthe

descriptorsforanavailableI/Ooperation.Ifthetimeoutvalueis0,thenselectwillreturnimmediately.IfthetimeoutargumentisNULL,thenselectwillblockuntilatleastonefile/sockethandleisreadyforanavailableI/Ooperation.OtherwiseselectwillreturnaftertheamountoftimeinthetimeouthaselapsedORwhenatleastonefile/socketdescriptorisreadyforanI/Ooperation.ThereturnvaluefromselectisthenumberofhandlesspecifiedinthefiledescriptorsetsthatarereadyforI/O.Ifthetimelimitspecifiedbythetimeoutfieldisreached,selectreturn0.Thefollowingmacrosexistformanipulatingafiledescriptorset:

FD_CLR(s,*set)Removesthedescriptorsfromset.

FD_ISSET(s,*set)Nonzeroifsisamemberoftheset,zerootherwise.FD_SET(s,*set)Addsdescriptorstoset.

FD_ZERO(*set)InitializesthesettotheNULLset.Example:fd_setfds;

structtimevaltv;

//sockisanintializedsockethandletv.tv_sec=2;

tv.tv_usec=500000;

//tvnowrepresents2.5seconds

FD_ZERO(&fds);

FD_SET(sock,&fds);//addssocktothefiledescriptorset/*wait2.5secondsforanydatatobereadfromanysinglesocket*/select(sock+1,&fds,NULL,NULL,&tv);if(FD_ISSET(sock,&fds))

recvfrom(s,buffer,buffer_len,0,&sa,&sa_len);else

/*dosomethingelse*/

Conclusions

Developerswhousethefunctioncallsdescribedinthisdocumentshouldalwayscheckthereturnvalueforeach.ConsultingtheUNIXon-linemanualpages(\"man\")foracompletedescriptionofeachfunctioncallisrecommendedaswell.

因篇幅问题不能全部显示,请点此查看更多更全内容