网络编程(接口socket)_第1页
网络编程(接口socket)_第2页
网络编程(接口socket)_第3页
网络编程(接口socket)_第4页
网络编程(接口socket)_第5页
已阅读5页,还剩10页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、使用Java语言还可以编写底层的网络通信程序,这是通过包中提供的Socket类以及ServerSocket等类实现的。本章讨论如何通过socket使用TCP/IP或UDP协议实现在网络上两个程序间建立连接并交换数据。 Java套接字编程 机器标识连接到Internet上的计算机使用IP地址或域名来唯一标识一台计算机,在局域网上的计算机则可以使用名称标识。要实现网络通信,首先需要知道计算机的地址。在包中提供了InetAddress类对象来表示计算机地址。InetAddress类没有提供构造方法,要得到一个InetAddress类对象,需要使用该类的静态方法。· public stati

2、c InetAddress getByName(String host) 返回给定主机名或点分十进制表示的主机的IP地址。· public static InetAddress getAllByName(String host) 返回给定主机名或点分十进制表示的主机的所有IP地址数组。· public static InetAddress getLocalHost() 返回本地主机的IP地址。上述方法在指定的主机未知时将抛出UnknownHostException异常。InetAddress类其他方法:· public String getHostName() 返

3、回该IP地址的主机名字符串。· public String getHostAddress() 返回主机IP地址的字符串。· public byte getAddress() 返回四个元素的表示IP地址的字节数组。下面程序通过命令行给出一台主机的域名,程序将输出该机器的网络地址。程序 GetIPAddress.java import .*;public class GetIPAddresspublic static void main(String args) throws Exceptionif(args.length!=1) System.out.println(&quo

4、t;Usage:GetIPAddress DomainName"); System.exit(1); InetAddress address = InetAddress.getByName(args0); System.out.println(address); System.out.println("Name:"+address.getHostName(); System.out.println("Address:"+address.getHostAddress(); _要运行该程序,机器必须连到网络上。下面是程序运行的一个结果:图 GetI

5、PAddress程序的运行结果套接字通信在网络上,很多应用都是采用客户/服务器(C/S)结构的。实现网络通信必须将两台机器连接起来建立一个双向通信链路,这个双向通信链路的每一端称为一个套接字(socket)。1. 套接字的构成我们知道,在Internet上可以使用IP地址唯一标识一台主机。但一台主机可能提供多种服务,而仅用IP地址还不能唯一标识一个服务。因此通常使用一个整数来标识该机器上的某个服务,这个整数就是端口号(port)。端口号是用16位整数标识,共有65536个端口号。端口号并不是机器上实际存在的物理位置,而是一种软件上的抽象。端口号分为两类。一类是由因特网名字和号码指派公司ICAN

6、N分配给一些常用的应用层程序固定使用的熟知端口(well-known port),其数值为11024。例如HTTP服务的端口号为80,FTP服务的端口号为21。表1列出了几种常用的熟知端口号。表1 常用服务的端口号服务FTPTelnetSMTPDNSHTTPSNMP端口号2123255380161另一类端口为一般端口,用来随时分配给请求通信的客户进程。为了在通信时不致发生混乱,就必须把端口号和主机的IP地址结合在一起使用。一个TCP连接由它的两个端点来标识,而每一个端点又是由IP地址和端口号决定的。TCP连接的端点称为套接字(socket),套接字是由IP地址和端口号构成的,如图2所示:131

7、.6.23.1315003 , 1500IP地址端口号套接字图2 套接字的构成这里,3为IP地址,1500为端口号,因此套接字为3,1500。2. 套接字通信与套接字类一般来说,运行在一台特定机器上的某个服务器(如HTTP服务器)都有一个套接字绑定到该服务器上。服务器只是等待、监听客户的连接请求。在客户端,客户机需要知道运行服务器的主机名和端口号。为了建立连接请求,客户机试图与服务器机器上的指定端口号上的服务连接,这个请求过程如图3所示:图3 客户向服务器请求连接如果正常,服务器将接受连接请求。一旦接受了请求,服务器将创建一个新的绑定

8、到另一个端口号的套接字,然后使用该套接字与客户通信。这样,服务器可以使用原来的套接字继续监听连接请求,如图4所示。图4 服务器接受客户的连接在客户端,如果连接被接受,就会创建一个套接字(socket),客户就可以使用该套接字与服务器通信。注意,客户端的套接字并没有绑定到与服务器连接的端口号上,相反客户被指定客户程序所在机器上的一个端口号上。现在客户与服务器就可以读写套接字进行通信了。 为了实现套接字通信,在包中提供了两个类:Socket和ServerSocket。它们分别实现连接的客户端和服务器端的套接字。Socket类的常用构造方法:· public Socket (String

9、host, int port) throws UnknownHostException , IOException创建一个流式套接字对象并将其连接到命名主机的指定端口上。host为主机名,port为端口号。· public Socket (InetAddress address, int port) throws IOException 创建一个流式套接字对象并将其连接到指定IP地址的指定端口上。address为主机的IP地址,port为端口号。· public Socket (String host, int port, InetAddress localAddr, in

10、t localPort) throws IOException · public Socket (InetAddress address, int port, InetAddress localAddr, int localPort) throws IOExceptionSocket类提供的主要方法有:· public InetAddress getInetAddress() 返回该套接字所连接的IP地址。· public int getPort() 返回该套接字所连接的远程端口号。· public synchronized void close() t

11、hrows IOException关闭套接字对象。· public InputStrean getInputStream() throws IOException 获得套接字绑定的数据输入流。· public OutputStream getOutputStream() throws IOException 获得套接字绑定的数据输出流。ServerSocket类用在服务器端。客户与服务器通信,客户向服务器提出请求,服务器监听请求,一旦监听到客户请求,服务器也要建立一个套接字。这可通过ServerSocket类实现。ServerSocket类的构造方法如下:· Se

12、rverSocket(int port) 创建绑定到指定端口port上的服务器套接字。· ServerSocket(int port ,int backlog) 参数backlog指定最大的队列数,即服务器所能支持的最大连接数。· ServerSocket(int port ,int backlog, InetAddress bindAddr) 参数bindAddr为所绑定的地址。上面的构造方法都声明了抛出IOException异常,因此创建对象时应该捕获异常或声明抛出异常。注意,因为有些端口号已被特殊的服务占用,所以应该选择大于1024的端口号。ServerSocket类

13、提供的主要方法:· public Socket accept() throws IOException 该方法是ServerSocket类的重要方法,调用该方法将阻塞当前系统服务线程,直到有客户连接。当有客户连接时,该方法返回一个Socket对象。正是通过该Socket对象,服务器才可以与客户通信。· public void close() throws IOException 关闭ServerSocket对象。3. 一个简单的客户和服务器通信的实例无论一个套接字的通信功能多么齐全、程序多么复杂,其基本结构都是一样的,都包括以下四个基本步骤:(1)创建socket对象;(2

14、)打开连接到socket的输入输出流;(3)按照一定协议对socket进行读写操作;(4)关闭socket。图5说明了服务器和客户端所发生的动作。服务器端ServerSocket(port #)ss.accept()得到socket对象OutputStreamInputStreamclose()客户端Socket(host,port #)得到socket对象OutputStreamInputStreamclose()图5 通信双方建立连接的过程在服务器端,首先指定一个端口号,创建一个ServerSocket对象。然后调用accept()方法等待客户连接。如果客户请求一个连接,服务器使用acce

15、pt()方法将返回一个Socket对象。在客户端,用指定的服务器主机名或IP地址及端口号创建一个Socket对象,该对象试图连接到指定主机指定端口的服务。当两端都返回Socket对象后,就可以分别在Socket对象上调用getInputStream()和getOutputStream()方法,得到输入输出流对象。这里要注意,服务器端的输出流对应于客户端的输入流,服务器端的输入流对应于客户端的输出流。双方建立了输入输出流后就可以进行通信了。最后,通信结束应该调用close()方法关闭套接字,释放连接的资源。下面是一个简单的字符界面的聊天程序。在服务器端使用端口号4700创建服务器套接字。服务器端

16、程序如下:程序 ServerDemo.java import java.io.*;import .*;public class ServerDemo public static void main(String args) try ServerSocket server = new ServerSocket(4700); Socket socket = server.accept(); String line; BufferedReader is = new BufferedReader( new InputStreamReader(socket.getInputStream(); Print

17、Writer os = new PrintWriter(socket.getOutputStream(); BufferedReader sin = new BufferedReader( new InputStreamReader(System.in); System.out.println("Client:"+is.readLine(); System.out.print("Server:"); line=sin.readLine(); while(!line.equals("bye") os.println(line); os.

18、flush(); System.out.println("Client:"+is.readLine(); System.out.print("Server:"); line=sin.readLine(); sin.close(); os.close(); is.close(); socket.close(); server.close(); catch(Exception e) System.out.println("Error:"+e); _客户端端程序如下:程序 ClientDemo.java import java.io.*;i

19、mport .*;public class ClientDemo public static void main(String args) try Socket socket=new Socket("server",4700); BufferedReader is=new BufferedReader( new InputStreamReader(socket.getInputStream(); PrintWriter os=new PrintWriter(socket.getOutputStream(); BufferedReader sin=new BufferedRe

20、ader( new InputStreamReader(System.in); String readline; System.out.print("Client:"); readline=sin.readLine(); while(!readline.equals("bye") os.println(readline); os.flush(); System.out.println("Server:"+is.readLine(); System.out.print("Client:"); readline=sin

21、.readLine(); sin.close(); os.close(); is.close(); socket.close(); catch(Exception e) System.out.println("Error:"+e); _该程序首先建立一个Socket对象,其中“server”为服务器机器名,4700为服务器提供连接服务的端口号。如果在一个机器上测试该程序,可以将“server”改为所在机器的名称或使用“localhost”,也可以使用“”地址。要测试该程序,应该首先运行服务器程序,然后运行客户程序,并且客户程序先向服务器发送消息。图6和7分

22、别给出了该程序的运行效果。图6服务器端程序运行效果图7客户端程序运行效果4. 为多个客户提供服务在上面的例子中,服务器只能为一个客户提供服务。在实际应用中,往往是在服务器机器上运行一个服务器,它接收来自其他多个客户的请求,为多个客户提供服务。下面程序提供的功能是客户程序向服务器发送一个表示圆的半径的数,服务器为其计算圆的面积并将计算结果发送给客户。这里为实现服务器为多个客户服务,使用了多线程的机制。下面是服务器端程序:程序 MultiThreadServer.java import java.io.*;import .*;public class MultiThreadServer publi

23、c static void main(Stringargs) try ServerSocket serverSocket = new ServerSocket(8000); int clientNo=1; while(true) Socket connectToClient = serverSocket.accept(); System.out.println("Start thread for client "+clientNo); InetAddress clientInetAddress = connectToClient.getInetAddress(); Syst

24、em.out.println("Client "+clientNo+" 's host name is " +clientInetAddress.getHostName(); System.out.println("Client "+clientNo+" 's IP address is " +clientInetAddress.getHostAddress(); HandleClient thread = new HandleClient(connectToClient); thread.star

25、t(); clientNo+; catch(IOException ex) System.err.println(ex); class HandleClient extends Thread private Socket connectToClient; public HandleClient(Socket socket) connectToClient = socket; public void run() try DataInputStream isFromClient = new DataInputStream( connectToClient.getInputStream(); Dat

26、aOutputStream osToClient = new DataOutputStream( connectToClient.getOutputStream(); while(true) double radius = isFromClient.readDouble(); System.out.println("radius received from client:"+radius); double area = radius*radius*Math.PI; osToClient.writeDouble(area); osToClient.flush(); Syste

27、m.out.println("Area is:"+area); catch(IOException ex) System.err.println(ex); _下面是客户端程序:程序 Client.java import java.io.*;import .*;import java.util.*;public class Client public static void main(Stringargs) try Socket connectToServer = new Socket("localhost",8000); DataInputStream

28、isFromServer = new DataInputStream( connectToServer.getInputStream(); DataOutputStream osToServer = new DataOutputStream( connectToServer.getOutputStream(); while(true) System.out.print("Please input a radius:"); Scanner sc = new Scanner(System.in); double radius = sc.nextDouble(); osToSer

29、ver.writeDouble(radius); osToServer.flush(); double area = isFromServer.readDouble(); System.out.println("Area received from server:"+area); catch(IOException ex) System.err.println(ex); _该程序的运行结果如图6和7所示:图6服务器端程序运行效果图7客户端程序运行效果数据包通信上一节讲的socket通信是一种流式通信,本节讨论通过socket实现数据包通信。1 流式通信和数据包通信当编写网络

30、程序时,有两种通信可供选择:流式通信和数据包通信。流式通信使用TCP(Transfer Control Protocol) 协议,该协议是面向连接的协议。使用这种协议要求发送方和接收方都要建立socket连接,一旦两个socket建立起来,它们就可以进行双向通信,双方都可以发送和接收数据。数据包通信使用用户数据包协议UDP(User Datagram Protocol),该协议是一种无连接的协议。使用这种协议通信,每个数据包都是一个独立的信息单元,它包括完整的目的地址,数据包在网络上以任何可能的路径传往目的地,因此数据能否到达目的地、到达的时间以及内容的正确性都是不能保证的,该协议提供的是不可

31、靠的服务。在网络的传输层既然提供了两种协议,那么在实际的应用中到底应该使用哪种协议?这要取决于不同的应用情况,下面是两种协议的比较: 使用UDP时,每个数据包都给出了完整的地址信息,因此无需建立发送方和接收方的连接。对于TCP,由于它是一个面向连接的协议,在通信之前必须建立双方的连接,因此在TCP中多了一个建立连接的时间。 使用UDP传输数据时是有大小限制的,每个数据包必须不大于64KB。而使用TCP就没有这方面的限制,一旦连接建立起来,就可以传输大量的数据。 UDP是不可靠的协议,发送方发送的数据不一定以相同的次序到达接收方。而TCP是可靠的协议,它确保接收方完全正确地获取发送方所发送的数据

32、。 TCP使用较广泛,如TELNET远程登录、FTP文件传输都需要不定长度的数据可靠地传输,因此需要使用TCP协议。相比之下UDP比较简单,而且仅需要较少的监护,因此常用于局域网分散系统中的client/server应用程序。2 DatagramSocket和DatagramPacket包提供了DatagramSocket类和DatagramPacket类,DatagramSocket用于在程序之间建立传送数据包的通信连接,DatagramPacket则用来表示一个数据包。利用这两个类程序员可以很方便地编写使用UDP协议的socket客户和服务器通信程序。1. DatagramSocket类D

33、atagramSocket类的构造方法有:· public DatagramSocket(int port) throws SocketException 创建一个数据包套接字,并将它绑定在本地主机指定的的端口上。· public DatagramSocket() throws SocketException 创建一个数据包套接字,并将它绑定在本地主机一个可用的端口上。DatagramSocket类的常用方法有:· public void receive(DatagramPacket p) throws IOException该方法用来接收一个报文,参数p用来保存

34、接收的报文。该方法会阻塞接收者,直到有一个报文到达套接字。为了防止对方由于某种原因可能使接收者永远阻塞,一般接收者设置一个计时器,如果收不到对方报文,计时器结束,接收者会作出处理。· public void send(DatagramPacket p) throws IOException该方法用来发送一个报文,参数p保存了要发送的报文。报文包括数据、接收者的IP地址及其端口。2. DatagramPacket类DatagramPacket类的构造方法有:· public DatagramPacket(byte buf, int length)参数buf为数据包文缓冲区,l

35、ength为缓冲区的长度。该构造方法创建的对象用于接收数据包。在接受数据之前,应该使用该构造方法创建一个DatagramPacket对象,给出接收数据的缓冲区及长度。然后调用DatagramSocket的receive()方法等待数据包的到来,receive()方法将一直等待,直到有一个数据包到来。例如:DatagramPacket packet = new DatagramPacket(buf,1024);socket.receive(packet);· public DatagramPacket(byte buf, int length, InetAddress address,

36、 int port)参数buf为数据包文缓冲区,length为缓冲区的长度,address为接收方的地址,port为接收方数据包套接字绑定的端口号。该构造方法创建的对象用于发送数据包。在发送数据前,也要生成一个新的一个DatagramPacket对象,在给出发送方的数据缓冲区及长度的同时,还要给出完整的目标地址,包括IP地址和端口号。发送数据是通过DatagramSocket的send()方法实现的,send()方法根据目的地址选择路径,以传送数据包。例如:DatagramPacket packet = new DatagramPacket(msg, send.length(), client

37、IP, clientPort);socket.send(packet); DatagramPacket类的常用方法有:· public InetAddress getAddress() 获得报文发送者的IP地址。· public int getPort() 获得报文发送者的端口。· public int getLength() 返回发送或接收的数据长度。· public byte getData() 返回数据缓冲区。3 一个简单的数据包通信的例子用数据包编写客户/服务器程序时,无论是客户方还是服务器方,首先都要建立一个DatagramSocket对象,用

38、来接收或发送数据包,然后使用DatagramPacket类对象作为传输数据的载体。下面的实例通过UDP实现通信。该实例实现的功能是客户端向服务器端发送一个字符串,服务器端接收该字符串,然后将其转换成大写字母,再发送到客户端。1. 服务器方的实现程序 UDPServer.javaimport .*;import java.io.*;public class UDPServer public static void main(String args) byte buf = new byte1024; try DatagramSocket socket = new DatagramSocket(88

39、88); System.out.println("Server is waiting."); while(true) /用于接收数据的数据包 DatagramPacket packet = new DatagramPacket(buf,1024); socket.receive(packet); String data = new String(buf,0,packet.getLength(); if(data.equals("bye") break; System.out.println("Client said:"+data);

40、String send = data.toUpperCase(); InetAddress clientIP = packet.getAddress(); int clientPort = packet.getPort(); byte msg = send.getBytes(); /用于发送数据的数据包 DatagramPacket sendPacket = new DatagramPacket( msg,send.length(),clientIP,clientPort); socket.send(sendPacket); socket.close(); System.out.println

41、("Server is closed."); catch(Exception e) e.printStackTrace(); _2. 客户方的实现程序UDPClient.javaimport .*;import java.io.*;public class UDPClient public static void main(String args) byte bufsend = null; String sendMessage = null; try DatagramSocket socket = new DatagramSocket(); BufferedReader s

42、ysin = new BufferedReader( new InputStreamReader(System.in); while(true) System.out.println("Waiting for input a line text."); sendMessage = sysin.readLine(); bufsend = sendMessage.getBytes(); /用于发送数据的数据包DatagramPacket packet = new DatagramPacket( bufsend,sendMessage.length(),InetAddress.g

43、etLocalHost(),8888); socket.send(packet); if(sendMessage.equals("bye") break; byte bufrec=new byte1024; /用于接收数据的数据包 DatagramPacket receivePacket = new DatagramPacket(bufrec,1024); socket.receive(receivePacket); String received = new String(receivePacket.getData(); System.out.println("

44、From Server:"+received); socket.close(); catch(Exception e) e.printStackTrace(); _该程序的运行结果如图8和9所示:图8服务器端程序运行效果图9客户端程序运行效果作业:3. 简述什么是套接字?它由哪些部分组成?它有什么作用?4. 套接口是为下面哪一项编码?( )A. 端口号 B. IP地址 C. 端口号和IP地址 D.都不是5. 为了等待客户的一个连接请求,服务器应该使用下面哪个类?( )A. Socket B. SocketServer C. Server D. URL6. 当使用带一个主机地址参数的构

45、造方法创建一个新的Socket实例时:( )A. Java试图在Internet上建立一个与该主机的连接。 B. Java启动一个运行在该主机上的一个服务器。 C. 直到调用了Socket的accept()方法,否则什么也不会发生。7. 对一个给定的Socket对象sock,为了获得一个输出流,下面哪个语句是正确的?( )A. sock.accept(); B. sock.getDataOutputStream();C. sock.getOutputStream(); D. new DataOutputStream(sock);8. ServerSocket的accept()方法返回的类型是(

46、 )。A. Socket B.ServerSocketC. Server D.URL9. TCP主要用于( )。A. 在Internet上标识基于点分十进制的地址或域名。B. 保证数据包按照发送的顺序到达。C. A和B都正确 D. A和B都不正确12. 利用Java的JFrame类实现一个图形用户界面的程序,它的功能是接受用户输入的一个主机名,利用InetAddress类查找出它的IP地址并显示出来。14. 利用Socket类和ServerSocket类编写一对客户机/服务器程序,建立套接字通信管道,并将一个文件从一台机器传到另一台机器。17分析以下网络通信多线程程序功能。/SocketServer.javaimport .*;import java.io.*;public class SocketServer public

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论