《Socket用法详解.docx》由会员分享,可在线阅读,更多相关《Socket用法详解.docx(21页珍藏版)》请在三一办公上搜索。
1、在客户/服务器通信模式中,客户端纪要主动创建与服务器连接的SOCket(套接字),服务器端收到了客户端的连接恳求,也会创建与客户连接的Socket.Socket可看诧是通信连接两端的收发器,服务器与客户端都通过Socket来收发数据.这篇文章首先介绍Socket类的各个构造方法,以及成员方法的用法,接着介绍SoCket的一些选项的作用,这些选项可限制客户建立与服务器的连接,以及接收和发送数据的行为.-.构造SocketSocket的构造方法有以N几种垂枝形式:SoCketoSocket(InetAddressaddress,intport)throwsUnknowHostException,I
2、OExceptionSocketfInetAddressaddress,intport,InetAddressIocaIAddr,intIocaIPort)throwsIOExceptionSocket(Stringhost,intport)throwsUnknovzHostException,IOExceptionSoCket(Stringhost,Intport,InetAddressIocaIAddr1intIocaIPort)throwsIOException除了第一个不带参数的构造方法以外,其他构造方法都会试图建立与服务器的连接,假如连接胜利,就返回Socket对象;假如因为某些缘由
3、连接失败,就会抛出IOExcept.on.1.1 运用无参数构造方法,设定等待建立连接的超时时间Socketsocket=newSocket();SocketAddressremoteAddr=newInetSoCketAddreSS(osIhOSt”,8000);socket.connect(remoteAddr,60000);等待建.立连接的超时时间为1分钟以上代码用丁连接到本地机器上的监听8000转口的服务器程序,等待连接的最长时间为1分钟.假如在1分仲内连接胜利则COnneto方法顺当返回;假如在1分钟内出现某种异样,则她出该异样;他如超过1分钟后,即没有连接胜利,也没有出现其他异样,
4、那么会拍出SOCketTimeOUtEXCePtion.Sket类的ConnecusocketAddressendpointJnttimeout)方法仇说连接服务器,参数endpomt指定蜃务器的地址,参数timeout设定超时数据,以学秒为单位.假如参数timeout谀为0,表示恒久不会超时,默认是不会超时的.1.2 设:定服务器的地址除了第一个不带参数的构造方法,其他沟造方法都须要在参数中设定服务器的地址,包括服务器的IP地址或主机名,以及布口;SocketfInetAddressaddress,intport)第个参数address表示主机的IP地址SoCkeUStringhost,in
5、tport)第一个参数host表示主机的名字InetAddress类表示服务器的IP地址,InetAddress类供应系列静态工厂方法,用于构造自身的实例,例如:返回本地主机的IP地址InetAddressaddrl=lnetAddress.get1.ocalHost();返回代表222.3457的IP地址InetAddressaddr2=lnetAddress.getByName(222.34.5.7);返回域名为javathinker.org的IP地址InetAddressaddr3=letAddress.getByName(javathinker.org);1.3 设定客户端的地址在个S
6、ocket对象中,即包含远程服务器的IP地址和端口信息,也包含本地客户端的IP地址和雄Il信息.就认状况”客户端的IPifti11尸客户和阴“!:的上机,客户端的加然网课作系统随机安排.Socket类还有两个构造方法允许显式地设置客户端的IP地址和端口:参数IocaIAddr和IOCalPOrt用来设置客户端的IP地址和端”SOCketUnetAddreSSaddress,intport,InetAddressIocaIAddr,intIocaIPort)throwsIOExceptionSocket(Stringhost,intport,InetAddressIocaIAddr,intIoc
7、aIPort)throwsIOException假如一个主机同时属于两个以上的网络,它就可能拥有两个以上的IP地址.例如,一个主机在Internet网络中的IP地址为-222.67.1.34,在一个局域网中的IP地址为-112.543”.假定这个主机上的客户程序希望和向个局域网的个服务器程序(地址为:11254.45:80(Xr)通信,客户端可依据如卜方式构造Socket对您:InetAddressremoteAddrl=lnctAddress.gctByName(112.5.4.45);InetAddressIocaIAddrl=InetAddreSSEetByNamerll2.5.4.3)
8、;SocketSocketl三newSOcket(remoteAddrl,8000,IocaIAddrl,2345);客户端运用缩口23451.4 客户连接服务器时可能抛出的异Fl当Socket的构造方法恳求连接服务器时,可能会抛出下面的异样.UnKnownHostException:假如无法识别主机的名字或IP地址,就会抛出这种异样.ConnectEXCePtion:假如没有服务器进程监听指定的端口,或者服务器进程拒绝连接,就会摘出这种异样.SocketTimeoutException:钱如等待连接卸时,就会抛出这种异样.BindException:假如无法把Socket对收。指定的本地IP
9、地址改制11绑定,就会抛出这种异样.以上4中异样都是IOException的干脆或间接子类.如图2-1所示.IOExceptionUnknownHostException-InterruptediOExcepttonSocketTimeoutExcepttonI-SocketExceptionBindExceptionIConnectException图2-1客户端连接服务器时可能抛出的异样二,获得Socket的信息住一个Socket对象中同时包含了远程服务器的IP地址和端口信息,以及客户本地的IP地址和端口信息.此外,从Socket对象中还可以获得输出流和输入流,分别用丁向服务器发送数据,以
10、及接收从服务器端发来的数据.以下方法用于找得Socket的有关信息.getl11etAddress():获得远程服务器的IP地址.getPort():获得远程服务器的端口.get1.ocalAddress():获得客户本地的IP地址.get1.ocalPort():获得客户本地的箍口.getlnputStream():获得输入流.假如Socket还没仃连接,或者已经关闭,或拧已经通过ShutdownInputO方法关闭输入流,那么此方法会抛出IOExceptIon.getOutputStream():狭得输出流,合如Socket还没有连接,或者己经关闭,或者已经通过ShutdownOutput
11、O方法关闭输出流,那么此方法会抛出IOException.这里有个HTTPCIient类的例子,代码我是写好了,也测试过了,因为篇幅缘由就不贴了.这个HTTPCIient炎用于访问网页javathinker.org/mdex.jsp.该网页位于个主机名(也叫域名)为javathinker.org的远程HTTP服务器上,它Ki听80端口.在HTTPCIient类中,先创建了一个连接到该H11P服务器的Socket对象,然后发送符合HTTP协议的恳来,接芥接收从HTTP服务器上发回的响应结果.,.关闭Socket当客户与限务器的通信结束,应当刚好关闭Socket,以糅放$。Cket占用的包括埔口在
12、内的各种资制Socket的close()方法负送关闭Socket.当一个Socket时象被关闭,就不能再通过它的输入源和输出流进行1/0操作,否则会导致IOException.为了输保关闭Socket的操作总是被执行,剧烈建议把这个操作放在finally代码块中:Socketsocket=null;try(socket=newSket(javathinker.org,80);执行接收和发送数据的操作catch(IOExceptione)e.printStackTrace();finallyy(If(SoCketI=null)socket.close();catch(IOExceptione)e
13、.printStackTracc();)SOCket类供应3个状态测试方法.isClosed():假如Socket已经连接到远程主机并Il还没有关闭,则返回true,否则返回false.isConnected():假如SocketW经连接到远程主机,则返回true,否则返回false.isBound(1:假如Socket已经与一个本地绑定,让返回true,否则返回false.假如要推断一个Socket对飘当前是否处于连接状态,可采纳以下方式:booleanisConnected=socket.isConnected()&!socket.isClosed();四.半关闭Socket进程A与进程B
14、通过Socket通信,找定进程A输出数据,进程B读入数据.进程A如何告知迸程B全陆数据已经输出完毕?下文略五.设巴SoCket的选项SoCket仃以下几个选项.TCP.NODEIAY:表示马上发送数据.So-RESUSEADDR:表示是否允许乘用Socket所绑定的本地地址.SO.TIMEOUT:表示接收数据时的等待超时数据.SojJNGER:表示当执行Socket的CbseO方法时,是否马上关闭底层的Socket.SO_SNFBUF:表示发送数据的缓冲区的大小.SO-RCVBUF:去示接收数据的短冲区的大小.SO.KEEPA1.IVE:表示对于长时间处于空闹状态的Socket,是否要自动把它
15、关闭.OOBIN1.INE:表示是否支持发送一个字H的TCP脍急数据.5.1 TCP_NODE1.AY选项设置该选项:PUbliCvoidsetTcpNoDelay(booleanon)throwsSocketException读取该选项:PUbliCbooleangetTcpNoDeIayf)throwsSocketException我认状况E,发送数据采纳Negale翼法.Negale算法是指发送方发送的数据不会马上发出,而是先放在缓冲区,等缓存区满了再发出.发送完批数据后,会等待接收方对这批数据的回应,然后再发送下一批数据.NegaIe法适用于发送方纪要发送大批量数据,并且接收方会刚好作
16、出回应的场合,这种算法通过削减传输数据的次数来提高通信效率.假如发送方持续地发送小批量的数据,并且接收方不肯定会马上发送响应数据,那么Negale算法会使发送方运行很慢.对于GUI程序,如网络地戏程序(服务器须要实时踉踪客户端双标的移动),这个问题尤其突出.客户端鼠标位较改动的信息须要实时发送到旅务器上,由于Negale里法采纳缓冲,大大减低了实时响应速度,导致客户程序运行很慢.TCP_NODEIAY的默认位为false,我示采纳Negale算法.假如调用SeRCPNODelaWtrue)方法,就会关闭SOCket的缓冲,输保数据刚好发送:if(!socket.getTCpNoDeIay(I)
17、socketsetTcpNoDelay(true);假如Socket的底层实现不支持TCP_NODE1.AY选项,那么gctTcpNoDelay()和SetTcpNoDeIay方法会抛出SocketException.5.2 SO_RESUSEADDR选项设置该选项:publicvoidSetReSUSeAddreS5(booleanon)throwsSocitetException读取该选项:publicbooleangetResuseAddress()throwsSocketException当接收方通过Socket(f)close()方法关闭Socket时,假如网络上还有发送到这个Soc
18、ket的数据,那么底层的Socket不会马上样放本地端口,而是会等待一段时间,确保接收到了网络上发送过来的延迟数据,然后再释放流I1.Socket接收到延迟数据后,不会对这些数据作任何处理.Socket接收延迟数据的目的是,确保这些数据不会被其他礴巧绑定到同样端口的制进程接收到.客户程序一般采纳随机端11,因此出现两个客户程序绑定到同样前11的可能性不大.很多服务器程序都运用固定的端口.当服务器程序关闭后,有可能它的端口还会被占用一段时间,祖如此时节上在河个主机上重启服务器程序,由于端口己经被占月I,使得服务器程序无法绑定到该那口,启动失败.(第三篇文章会对此作出介绍).为了确保一个进程关闭S
19、ocket后,即使它还没择放箫口,同一个主机上的其他进程还可以马上里用该端,可以网用Socket的SetResuseAddress(Irue)方法:if(!socket.getResuseAddress()socket.setResuseddress(true);4*(得留意的是SoCket.SetResuseAddresskrue)方法必需在Socket还没彳i绑定到,个本地淘”之前调用,杏则执行Socket-SetResuseAddress(true)方法无效.因此必需依据以下方式创建SOCket对象,然后再连接远程服务器:Socketsocket=newSocket();此时Socket
20、对飘未绑定本地缩口,并且未连接远程服务器socket.setReuseAddress(true);SocketAddrcssremoteAddr=newInetSOCketAddreSS(IoCalhoSt”,8000);SOCket.connect(remoteAddr);连接远程服务器,并且绑定IC名的本始端I1或者:Socketsocket=newSocket();此时SOCke对象为绑定本地端11,并且未连接远程服务器socket,setReuseAddress(true;SocketAddressIocaIAddr=newInetSocketAddress(localhost,900
21、0);SocketAddressremoteAddr=newInetSoCketAddreSS(IoCaIhOSt”,8000);socket.bmd(kalAddr);与本地湘Il绑定Socket.Connect(FemoteAddr);连接远程服务RS此外,两个共用同一个端口的进程必需都调用SoCket.setResuseAddress(true)方法,才能使得一个进程关闭SOCket后,另一个进程的Socket能修马上也用相同端115.3 SojnMEOUT选项设K该选项:publicvoidsetSoTime方法,该方法不会马上返网,而是进入堵塞状态.同时,底层的Socket会尝试发送
22、剩余的数据.只有满意以下两个条件之一,dose()方法才返回:(D底层的Socket己经发送完全部的剩余数据;2)尽管底层的Socket还没有发送完全部的剩余数据,但已经堵塞了3600秒(小选这里是秒,而非晶秒),close。方法的堵案时间超过3600秒,也会返回,剩余未发送的数据被丢箱值得留意的是,在以上两种状况内,当Ck)SeO方法返回后,底层的Socket会被美闱,断开连接.此夕卜,setSo1.ingerfbooleanon,intseconds)方法中的seconds参数以秒为单位,而不是以老杪为单位.假如未设置SoJjNGER选项,getSo1.inger()返I5I的结果是-1,
23、假如设St(SOCketSetSoUnger(true,80),getSo1.i11ger()返回的结果是80.Tips:当程序通过ft出流写数据时,仅仅表示程序向网络提交了批数据,用网络负责输送到接收方.当程序关闭Socket,有可能这批数据还在网络上传输,还未到达接收方,这里.所说的”未发送完的数擀”就是指这种还在网络上传愉,未被接收方接收的数据.例子SimpIeCIientJava与SimPI。SerVerJaVa所示是一对前沽的客户/服务器程序.SimpleQient类发送一万个字符给SimpIeServer,然后网用Socket的close()方法关闭SOCket.SimpIeSer
24、ver通过ServerSocket的accept()方法接受了SimpIeCIient的连接总求后,并不巧上接收客户发送的数据,而是睡眠5秒钟埼再接收数据.等到SimpIeServer起先接收数据时,SimpIeCIient有可能已经执行了Socket(f)close()方法,那么SimpIeServer还能接收到SimPleCIient发送的数据吗?SimpIeCIientjava略,SimpIeServerjava略SimpIeCIientjava中SySlem.out.println(”起先关闭Socket);longbegin=System.jrrentTimeMillis();soc
25、ket.close();longend=SystemxurrentTimeMiIIisO;SySlem.out.println(关闭Soeket所用的时间为+(endbegin)+ms,);下而分3种状况演示SimpIeCIient关闭S。Cket的行为.未设置SoJJNGER选项,当SimpIeCIIent执行SoCket的close()方法时,马上返回,SimpIeCIient的打印结果如下:起先关闭SOCket关闭SOCket所用的时间为:OmS等到Simpleaient结束运行,SimpIeServer可能才刚刚结束睡眠,起先接收SimPIeaient发送的数fi,i.此时尽管Simp
26、IeCIient已经执行了Socket的close()方法,并JlSimpIeCIient程序本身也运行结束了,但从SlmpIeServer的打印结果可以看出,SimpIeServer仍旧接收到了全部的数据.之所以出现这种状况,是因为当SimpIeCIient执行(Socket的close()方法后,底层的SOCket事实上弁没有真正关闭,与SimPleSerVer的连接依阳存在.底层的Socket会存在一段时间,直到发送完全部的数据.设拧SOJJNGER选项,socket.setSo1.lnger(true,0),这次当SimPIeaient执行Socket的CIoSeo方法时,会强行关闭底
27、层的Socket,全部未发送完的数据丢失.SimpIeCIient的打印结果如下:起先关闭SoCket关闭SoCket所用的时间为:0ms从打印结果钎出,SimpIeCIient执行Socket的dose()方法时,也马上返回.当SimPIeSerVer结束睐晚起先接收SimpIeCIient发送的数据时,由于SimpIeCIient已经关闭底层$。Cket,断开连接,因此SimPIeSerVer在添数据时会拍出SocketException:.SoCketEXCePtion:Connectionreset设置SO_1.INGER选项,SOCket.sets。1.inger(true,3600
28、).这次当SimpIeCIientRtjSocket的close()方法时,会进入堵塞状态,知道等待了3600杪,或者底层Sket已经把全部未发送的剩余数据发送完毕,才会从close()方法返回.SimpIeCIient的打印结果如下:起先关闭Socket当SimpIeServer结束15秒钟的睡叫起先接收SimpIeCIient发送的数据时,SimpIeCIient还在这屿Socket的dose()方法,并且处于堵塞状态.SimpIeCIient与SimpIeServer之间的连接依旧存在,W此SirnPleSerVer能峡接收到SimpIeCIient发送的全部数据.5.5 SO_RCVB
29、UF选项设Tt该选项:publicvoidSetReceIveBufferSize(intsize)throwsSocketException读取该选项:publicintgetReceiveBufferSize()throwsSocketExceptionSO-RCVBUF表示Socket的用于输入数据的缓冲区的大小.一般说来,传输大的连续的数据块(基于HHP或FTP协议的通信)可以运用较大的级冲区,这可以削减传输数据的次数,提l传输数据的效率.而对于交互频繁旦单次传送数据量比较小的通信方式(TeInet和网络嬉戏),用应当采纳小的陵冲区,确保小批量的数据能刚好发送给对方.这种设定镶冲区大小
30、的原则也同样适用Socket的SO_$NDBUF选项.如底层Socket不支持SO_RCVBUF选项,那么SetRecetveBufferSizeO方法会枪出SocketException.5.6 So-SNDBUF选项设区该选项:publicvoidSetSendBlJfferSiZe(intsize)throwsSocketException读取该选项:publicintgetSendBufferSize()throwsSocketExceptionSO_SNDBUF表示Socket的用于输出数据的缓冲区的大小.假如底层Socket不支总SO_SNDBUF选项,SetsendBufferS
31、izeO方法会抛出SocketException.5.7 SO.KEEPA1.IVE选项设置该选项:PUbIiCvoidsetKeepAlive(booleanon)throv/sSocketException读取该选项:publicbooleangetKeepAltve()throwsSOCketEXCePtiOn原杼中这个方法返回的类”!是int当SO_KEEPA1.IVE选项为true吐发示底层的TCP实现会监视该连接是否有效.当连接处于穹闱状态(连接的两端没有相互传送数幅)超过J2小时时,本地的TCP实现会发送一个数据包给远程的Soket,暇如远程Socket没有发回响应,TCP实现就
32、会持续尝试11分钟,百到接收到响应为止.假如在12分钟内未收到响应,TCP实现就会自动关闭本地Socket,断开连接.在不同的网络平台上,TCP实现尝试与远程Socket对话的时限仃所差别.SO.KEEPA1.IVE选项的默认值为false,我示TCP不会监视连接是否有效,不活动的客户端可能会恒久存在下去,而不会留意到服务S已经崩溃.以卜代码把SO_KEEPA1.IVE选项设为true:if(!socket.getKeepAlive()socket.setKeepAlive(trueh5.8OO8INlJNE选项设置该选项:publicVOidSetOOBInline(booleanon)th
33、rowsSocketException读取该选项:publicbooleangetOOBInline()throwsSocketException凉书中这个方法返回的类型是int当OOBINUNE为true时,K示支持发送个字节的TCP紧急数据.Socket类的SendUrgentData(intdata)方法用于发送一个字节的TCP紧急数据.OOBINUNE的默认值为false,在这种状况卜:当接收方收到紧急数据时不作任何处理,干脆将其去弃.假如用户帘望发送紧急数据,应当把OOBINUNE设为true:socket.setOOBInline(tre);此时接收方会把接收到的紧急数据与一般数据
34、放在同样的队列中.值得招总的是,除非运用一些更高层次的协议,否则接收方处理紧急数据的实力有限,当紧急数据到来时,接收方不会得到任何通知,因此接收方很难区分一般数据与紧急数据,只好依据同样的方式处理它们.5.9 服务类型选项当用户通过邮局发送殷信、挂号信或快件时,事实上是选样了邮局供应的不同的服务.发送股信的价格最低,但发送速衣慢,并且牢靠性没有保证.发送挂号信的价格梢高,但牢靠性有保证.发送快件的价格最高,发送速度最快,并Il军胞性有保证.在Intemet上传愉数据也分为不同的服务类型,它们有不同的定价.用户可以依据自己的襦求,选择不同的限务类型.例如I,发送视频须要较高的带宽,快速到达目的地
35、,以保证接收方看到连续的画面,而发送电了邮件可以运用较低的带宽,延迟几个小时到达目的地也没有关系.IP规定了4种服务类型,用来定性地描述服务的质量.低成本:发送成本低.高牢兼性:保证把数据半靠地送达目的地.域高吞吐量:一次可以接收或发送大批盘的数据.最小延迟:传输数据的速度快,把数据快速送达目的地.这4种服务类吧还可以进行组合.例如,可以同时要求获祝高车阴性和嫌小延迟.SOcket类中供应/设置和读取会务类里的方法.设置服务类型:publicvoidSetTraffieaaSSQnttrafficclass)throwsSockctExceptionSOCket类用4个整数表小服务类型.低成本
36、:0x02(二进制的倒数其次位为1)高军非性:0x04(二进制的倒数第三位为1)以高吞吐量::0x08(二进制的倒数第四位为1)最小延迟:0x10(二进制的倒数第五位为1)例如,以下代码恳求高牢匏性传输服务:socket=newSocket(host,port);socket.setTrafficass(0x04);再例如,以下代玛居求高牢靠性和域小延迟传输服务:socket.setTrafficass(0x040xl0);把OXo4JoXIO进行位或运。5.10 设定连接时间、延迟和带宽的相对垂要性在JDK1.51I11还为Socket类供应/一个SetPerfOrmanCePreferen
37、CeS()方法:publicvoidsetPerformancePreferences(intnnectionTime,intlatency,intbandwidth)以上方法的3个参数表示网络传怆数据的3选指标.梦数ConnectionTime:表示用最少时I司建立连接.参数IatenCy:表示被小延迟.参数bandwidth:表示最高带宽一SetPerYormancePreferencesO方法用来设定这3项指标之间的相时重要性.可以为这些参数给了随意的整数,这些整数之间的相财大小就确定了相应参数的相对也要性.例如,假如参数ConnectionTime为2,参数latency为1,而参数bandwidth为3,就表示最高带宽最市场其次是最少连接时间,期终是最小延迟.