版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、1.5 用Java 编写客户/服务器程序n在Java中,有三种套接字类:.Socket、.ServerSocket和DatagramSocket。其中Socket和ServerSocket类建立在TCP协议基础上,DatagramSocket 类建立在UDP协议基础上。n传输层向应用层提供了套接字Socket 接口,Socket 封装了下层的数据传输细节,应用层的程序通过Socket来建立与远程主机的连接以及进行数据传输。图1-18 套接字可看过是通信连接两端的收发器1.5.1 创建EchoServer图1-19 服务器与客户利用ServerSocket 和Socket来通信1.5.1 创建E
2、choServern服务器程序通过一直监听端口,来接收客户程序的连接请求。在服务器程序中,需要先创建一个ServerSocket对象,在构造方法中指定监听的端口: ServerSocket server=new ServerSocket(8000); /监听8000端口nServerSocket的构造方法负责在操作系统中把当前进程注册为服务器进程。服务器程序接下来调用ServerSocket 对象的accept()方法,该方法一直监听端口,等待客户的连接请求,如果接收到一个连接请求,accept()方法就会返回一个Socket 对象,这个Socket对象与客户端的Socket对象形成了一条通信
3、线路: Socket socket=server.accept(); /等待客户的连接请求1.5.1 创建EchoServernSocket 类提供了getInputStream()方法和getOutputStream()方法,分别返回输入流InputStream 对象和输出流OutputStream 对象。程序只需向输出流写数据,就能向对方发送数据;只需从输入流读数据,就能接收来自对方的数据。n与普通I/O流一样,Socket 的输入流和输出流也可以用过滤流来装饰。在以下代码中,先获得输出流,然后用PrintWriter 装饰它,PrintWriter 的println()方法能够写一行数据
4、;以下代码接着获得输入流,然后用BufferedReader 装饰它,BufferedReader 的readLine()方法能够读入一行数据: OutputStream socketOut = socket.getOutputStream(); /参数true 表示每写一行,PrintWriter缓存就自动溢出,把数据写到目的地 PrintWriter pw=new PrintWriter(socketOut,true); InputStream socketIn = socket.getInputStream(); BufferedReader br=new BufferedReader(
5、new InputStreamReader(socketIn);1.5.1 创建EchoServern例程1-2 EchoServer.javaimport java.io.*;import .*;public class EchoServer private int port=8000; private ServerSocket serverSocket; public EchoServer() throws IOException serverSocket = new ServerSocket(port); System.out.println(服务器启动); public String
6、echo(String msg) return echo: + msg; private PrintWriter getWriter(Socket socket)throws IOException OutputStream socketOut = socket.getOutputStream();1.5.1 创建EchoServer return new PrintWriter(socketOut,true); private BufferedReader getReader(Socket socket)throws IOException InputStream socketIn = so
7、cket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn); public void service() while (true) Socket socket=null; try socket = serverSocket.accept(); /等待客户连接 System.out.println(New connection accepted +socket.getInetAddress() + : +socket.getPort(); BufferedReader br =getReader
8、(socket); PrintWriter pw = getWriter(socket); String msg = null;1.5.1 创建EchoServer while (msg = br.readLine() != null) System.out.println(msg); pw.println(echo(msg); if (msg.equals(bye) /如果客户发送消息为“bye”,就结束通信 break; catch (IOException e) e.printStackTrace(); finally try if(socket!=null) socket.close(
9、); /断开连接 catch (IOException e) e.printStackTrace(); / service() 方法结束 public static void main(String args)throws IOException new EchoServer().service(); 1.5.2 创建EchoClientn在EchoClient程序中,为了与EchoServer通信,需要先创建一个Socket 对象: String host=localhost; String port=8000; Socket socket=new Socket(host,port);n当参
10、数host 的取值为“localhost”,表示EchoClient与EchoServer进程运行在同一个主机上。如果Socket对象成功创建,就表示建立了EchoClient与EchoServer 之间的连接。接下来,EchoClient 从Socket 对象中得到了输出流和输入流,就能与EchoServer 交换数据。1.5.2 创建EchoClientimport .*;import java.io.*;import java.util.*;public class EchoClient private String host=localhost; private int port=80
11、00; private Socket socket; public EchoClient()throws IOException socket=new Socket(host,port); public static void main(String args)throws IOException new EchoClient().talk(); 1.5.2 创建EchoClientprivate PrintWriter getWriter(Socket socket)throws IOException OutputStream socketOut = socket.getOutputStr
12、eam(); return new PrintWriter(socketOut,true); private BufferedReader getReader(Socket socket)throws IOException InputStream socketIn = socket.getInputStream(); return new BufferedReader(new InputStreamReader(socketIn); public void talk()throws IOException try BufferedReader br=getReader(socket); Pr
13、intWriter pw=getWriter(socket); BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in); String msg=null; while(msg=localReader.readLine()!=null)1.5.2 创建EchoClient pw.println(msg); System.out.println(br.readLine(); if(msg.equals(bye) break; catch(IOException e) e.printStackTra
14、ce(); finally trysocket.close();catch(IOException e)e.printStackTrace(); 运行EchoServer和EchoClientn运行范例时,需要打开两个DOS 界面,先在一个DOS 界面中运行“java EchoServer”命令,再在另一个DOS界面中运行“java EchoClient”命令。图1-20 显示了运行这两个程序的DOS界面。在EchoClient 控制台,用户输入字符串“hi”,程序就会输出“echo:hi”第2章 Socket用法详解 参考Java网络编程精解的第2章n2.1 构造Socketn2.2 获取S
15、ocket的信息n2.3 关闭Socketn2.4 半关闭Socketn2.5 设置Socket的选项n2.6 发送邮件的SMTP客户程序2.1 构造SocketnSocket的构造方法有以下几种重载形式:n(1)Socket() n(2)Socket(InetAddress address, int port)throws UnknownHostException,IOException n(3)Socket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException n(4)S
16、ocket(String host, int port) throws UnknownHostException,IOException n(5)Socket(String host, int port, InetAddress localAddr, int localPort) throws IOException 2.1.1 设定等待建立连接的超时时间 n设定等待建立连接的超时时间Socket socket=new Socket();SocketAddress remoteAddr=new InetSocketAddress(localhost,8000);/等待建立连接的超时时间为1分钟
17、socket.connect(remoteAddr, 60000); 2.1.2 设定服务器的地址nSocket(InetAddress address, int port) Socket(String host, int port) nInetAddress的用法如下:/返回本地主机的IP地址InetAddress addr1=InetAddress.getLocalHost(); /返回代表的IP地址InetAddress addr2=InetAddress.getByName(); /返回域名为的IP地址Ine
18、tAddress addr3=InetAddress.getByName(); 2.1.3 设定客户端的地址n在一个Socket对象中,既包含远程服务器的IP地址和端口信息,也包含本地客户端的IP地址和端口信息。默认情况下,客户端的IP地址来自于客户程序所在的主机,客户端的端口则由操作系统随机分配。Socket类还有两个构造方法允许显式的设置客户端的IP地址和端口:nSocket(InetAddress address, int port, InetAddress localAddr, int localPort)throws IOException nS
19、ocket(String host, int port, InetAddress localAddr, int localPort) throws IOException 2.1.4 客户连接服务器时可能抛出的异常n当Socket的构造方法请求连接服务器时,可能会抛出以下异常:nUnknownHostException:如果无法识别主机的名字或IP地址,就会抛出这种异常。nConnectException:如果没有服务器进程监听指定的端口,或者服务器进程拒绝连接,就会抛出这种异常。nSocketTimeoutException:如果等待连接超时,就会抛出这种异常。nBindException:
20、如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。2.1.4 客户连接服务器时可能抛出的异常2.1.4 客户连接服务器时可能抛出的异常n抛出UnknownHostException的情况:如果无法识别主机的名字或IP地址,就会抛出这种异常。n抛出ConnectException的情况:n没有服务器进程监听指定的端口。n服务器进程拒绝连接。n抛出SocketTimeoutException的情况:如果客户端等待连接超时,就会抛出这种异常。n抛出BindException的情况:如果无法把Socket对象与指定的本地IP地址或端口绑定,就会抛出这种异常。2.2 获取Soc
21、ket的信息 n以下方法用于获取Socket的有关信息:ngetInetAddress():获得远程服务器的IP地址。ngetPort():获得远程服务器的端口。ngetLocalAddress():获得客户本地的IP地址。ngetLocalPort():获得客户本地的端口。ngetInputStream():获得输入流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownInput()方法关闭输入流,那么此方法会抛出IOException。ngetOutputStream():获得输出流。如果Socket还没有连接,或者已经关闭,或者已经通过shutdownOutput()
22、方法关闭输出流,那么此方法会抛出IOException。2.3 关闭Socketn当客户与服务器的通信结束,应该及时关闭Socket,以释放Socket占用的包括端口在内的各种资源。Socket的close()方法负责关闭Socket。Socket socket=null;trysocket=new Socket(,80);/执行接收和发送数据的操作catch(IOException e) e.printStackTrace();finally try if(socket!=null)socket.close(); catch(IOException e)
23、e.printStackTrace();2.3 关闭SocketnSocket类提供了三个状态测试方法:nisClosed() nisConnected() nisBound() n如果要判断一个Socket对象当前是否处于连接状态,可采用以下方式:String isConnected=socket.isConnected() & !socket.isClosed();2.4 半关闭Socketn有的时候,可能仅仅希望关闭输出流或输入流之一。此时可以采用Socket类提供的半关闭方法:nshutdownInput():关闭输入流。nshutdownOutput(): 关闭输出流。2.4 半关闭
24、Socketn先后调用Socket的shutdownInput()和shutdownOutput()方法,仅仅关闭了输入流和输出流,并不等价于调用Socket的close()方法。在通信结束后,仍然要调用Socket的close()方法,因为只有该方法才会释放Socket占用的资源,比如占用的本地端口等。nSocket类还提供了两个状态测试方法,用来判断输入流和输出流是否关闭:npublic boolean isInputShutdown()npublic boolean isOutputShutdown()2.5 设置Socket的选项nTCP_NODELAY:表示立即发送数据。nSO_RE
25、SUSEADDR:表示是否允许重用Socket所绑定的本地地址。nSO_TIMEOUT:表示接收数据时的等待超时时间。nSO_LINGER:表示当执行Socket的close()方法时,是否立即关闭底层的Socket。nSO_SNFBUF:表示发送数据的缓冲区的大小。nSO_RCVBUF:表示接收数据的缓冲区的大小。nSO_KEEPALIVE:表示对于长时间处于空闲状态的Socket,是否要自动把它关闭。nOOBINLINE:表示是否支持发送一个字节的TCP紧急数据。2.5.1 TCP_NODELAY选项n设置该选项:public void setTcpNoDelay(boolean on)
26、throws SocketExceptionn读取该选项:public boolean getTcpNoDelay() throws SocketExceptionnTCP_NODEALY的默认值为false,表示采用Negale算法。如果调用setTcpNoDelay(true)方法,就会关闭Socket的缓冲,确保数据及时发送:if(!socket.getTcpNoDelay()socket.setTcpNoDelay(true);n如果Socket的底层实现不支持TCP_NODELAY选项,那么getTcpNoDelay()和setTcpNoDelay()方法会抛出SocketExcep
27、tion。2.5.2 SO_RESUSEADDR选项n设置该选项:public void setResuseAddress(boolean on) throws SocketExceptionn读取该选项:public boolean getResuseAddress() throws SocketExceptionn为了确保一个进程关闭了Socket后,即使它还没释放端口,同一个主机上的其他进程还可以立刻重用该端口,可以调用Socket的setResuseAddress(true)方法:if(!socket.getResuseAddress()socket.setResuseAddress(
28、true);n值得注意的是socket.setResuseAddress(true)方法必须在Socket还没有绑定到一个本地端口之前调用,否则执行socket.setResuseAddress(true)方法无效。2.5.3 SO_TIMEOUT选项n设置该选项:public void setSoTimeout(int milliseconds) throws SocketExceptionn读取该选项:public int getSoTimeOut() throws SocketExceptionn当通过Socket的输入流读数据时,如果还没有数据,就会等待。例Socket类的SO_TIM
29、EOUT选项用于设定接收数据的等待超时时间,单位为毫秒,它的默认值为0,表示会无限等待,永远不会超时。2.5.4 SO_LINGER选项n设置该选项:public void setSoLinger(boolean on, int seconds) throws SocketExceptionn读取该选项:public int getSoLinger() throws SocketExceptionnSO_LINGER选项用来控制Socket关闭时的行为。nsocket.setSoLinger(true,0):执行Socket的close()方法时,该方法也会立即返回,但底层的Socket也会立
30、即关闭,所有未发送完的剩余数据被丢弃。nsocket.setSoLinger(true,3600):执行Socket的close()方法时,该方法不会立即返回,而进入阻塞状态,同时,底层的Socket会尝试发送剩余的数据。只有满足以下两个条件之一,close()方法才返回:n底层的Socket已经发送完所有的剩余数据。n尽管底层的Socket还没有发送完所有的剩余数据,但已经阻塞了3600秒。close()方法的阻塞时间超过3600秒,也会返回,剩余未发送的数据被丢弃。2.5.5 SO_RCVBUF选项n设置该选项:public void setReceiveBufferSize(int si
31、ze) throws SocketExceptionn读取该选项:public int getReceiveBufferSize() throws SocketExceptionnSO_RCVBUF表示Socket的用于输入数据的缓冲区的大小。n如果底层Socket不支持SO_RCVBUF选项,那么setReceiveBufferSize()方法会抛出SocketException。2.5.6 SO_SNDBUF选项n设置该选项:public void setSendBufferSize(int size) throws SocketExceptionn读取该选项:public int get
32、SendBufferSize() throws SocketExceptionnSO_SNDBUF表示Socket的用于输出数据的缓冲区的大小。n如果底层Socket不支持SO_SNDBUF选项,setSendBufferSize()方法会抛出SocketException。2.5.7 SO_KEEPALIVE选项n设置该选项:public void setKeepAlive(boolean on) throws SocketExceptionn读取该选项:public int getKeepAlive() throws SocketExceptionn当SO_KEEPALIVE选项为true
33、,表示底层的TCP实现会监视该连接是否有效。nSO_KEEPALIVE选项的默认值为false,表示TCP不会监视连接是否有效,不活动的客户端可能会永久存在下去,而不会注意到服务器已经崩溃。2.5.9 服务类型选项nIP规定了四种服务类型,用来定性的描述服务的质量:n低成本:发送成本低。n高可靠性:保证把数据可靠的送达目的地。n最高吞吐量:一次可以接收或发送大批量的数据。n最小延迟:传输数据的速度快,把数据快速送达目的地。2.5.9 服务类型选项n这四种服务类型还可以进行组合,例如,可以同时要求获得高可靠性和最小延迟。Socket类中提供了设置和读取服务类型的方法:n设置服务类型:public void setTrafficClass(int trafficClass) throws SocketExceptionn读取服务类型
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026年陕西省选调生招录(面向东南大学)考试笔试备考题库及答案解析
- 2025中国人民大学人事处商学院招聘1人考试笔试模拟试题及答案解析
- 《紫罗兰》阅读理解答案
- 《枣儿》教学设计
- 2025黑龙江双鸭山市煤炭生产安全管理局招聘急需紧缺事业单位工作人员25人考试笔试备考题库及答案解析
- 江苏省南京市七校联合体2025-2026学年高三上学期12月联合考试历史试题(含答案)
- 初二下册英语期末题库带答案与解析
- 酒店出入股合同协议书
- 铸件平台转让合同范本
- 集资合伙人合同协议书
- 2025年6月大学英语四级考试听力原文第1套(中英对照)
- 车辆出口物流合同范本
- 不锈钢行业的行业知识普及与面试指南书
- 地中海贫血饮食调理指导
- 2025年陕西建工集团工程八部招聘笔试参考题库附答案
- 小程序员工培训课件
- 大学英语口语教程课件
- 压缩空气检修课件
- 述职报告5分钟演讲
- 临床成人患者医用粘胶相关性皮肤损伤预防及护理
- 本质安全宣讲课件
评论
0/150
提交评论