当前位置: 首页 > 图灵资讯 > 技术篇> 利用Java实现网络通信

利用Java实现网络通信

来源:图灵教育
时间:2024-02-25 13:53:30

  过TCP/UDP协议在网络上通信,基于以下四层模型:

  在编写JAVA应用程序时,主要是在第四层,即应用层。一般来说,TCP/UDP层不用担心,因为java.net包提供了系统无关的底层实现。然而,有必要了解TCP和UDP来决定使用哪种java类型。  TCP协议是基于连接的协议。通信前,必须先建立连接,然后才能通信。因此,通信可以同步、准确地进行。如果应用程序需要可靠的点对点通信,一般采用TCP协议。比如:HTTP,ftp,确保telnet等应用程序的可靠性对程序运行至关重要。另一方面,一些应用程序对通信的要求并不一定那么严格。比如ping命令。我们也可以考虑这样一个例子:服务器提供定期发送时间数据的时钟服务;客户不断提取时间数据;如果我们也为这样的应用程序建立可靠的连接,那么如果数据包丢失,客户要求重新发送包,重新发送的数据就失去了意义。因此,降低了服务程序的效率和适用性。  最后,我们阐述了以下另一个重要概念:端口。众所周知,通过IP地址实现数据通过网络到达主机(或者准确地说是主机的网卡)。但是当主机运行多个程序时,如何识别数据属于哪个程序呢?这就是端口。端口只能绑定一个应用程序。通过TCP/UDP通信的应用程序必须知道对方的IP地址和端口号才能通信。端口号可以从0开始-65535,其中,0-1023为保留端口提供一些众所周知的服务。下图说明了端口的使用情况。

  以下是对两个java程序的具体分析,以加深对上述概念的理解。

  一、 socket和TCP

  以下是服务程序和客户程序的源代码。具体分析见代码中的注释。  该程序只能建立一对连接,但根据其原理,可以编写复杂的多线程多对连接网络程序。该应用程序的客户端程序是一个独立的应用程序,但它可以通过Applet实现相同的功能。  在IE4.0的环境下,作者通过关闭一些安全选项,实现了浏览器中的Applet和服务器程序的轻松通信。然而,在IE5.0的环境中,情况发生了变化。IE5.0的安全选项不同于IE4.0。不管怎样设置,在IE4.0中都无法达到效果,显示出“xxx.xxx.xxx.xxx:4444 can not access"这样的错误信息。通过分析,我认为这可能是IE5.0加强网络安全考虑的原因。通过分析,我认为applet程序只应该与其服务器上的应用程序通信,该服务器应该是WEB服务器。所以,我把这个应用程序的服务器程序放在WEB 运行在SERVER上,结果成功。我使用的环境是,WEB SERVER:IIS (Option pack 3);MS VJ++6.0。///以下KKState类实现了一个有趣的对话过程的主要过程:用户启动服务程序,服务程序监控来自网络的连接请求,//如果有客户连接,建立连接。然后,在客户终端上显示″knock!knock!″,客户端如″Who′s there?″,则//回答″Turnip″。客户输入″Turnip who?″,回答″Turnip the heat,it′s cold in here! Want another?(y/n)″。假如客户///输入″y″,下一轮新对话,否则就结束了。对话的内容提前存储在两个字符串数组中。import java.net.*;import java.io.*;class KKState{  private static final int WAITING=0;  private static final int SENTKNOCKKNOCK=1;  private static final int SENTCLUE=2;  private static final int ANOTHER=3;  private static final int NUMJOKES=5;  private int state=WAITING;  private int currentJoke=0;  private Stringclues={″Tumip″,″Little Old Lady″,″Atch″,″Who″;″Who″};  private Stringanswers={″Turnip the heat,it′s cold in here!″,     ″I didn′t know you could yodel!″,     ″I didn′t know you could yodel!″,     ″Bless you!″,     ″Is there an owl in here?″,     ″Is there an echo in here?″};String processInput(String theInput){String theOutput=null;if(state==WAITING){   theOutput=″Knock!Knock!″;   state=SENTKNOCKKNOCK;  } else if(state==SENTKNOCKKNOCK){   if(theInput.equalsIgnoreCase(″Who′s there?″)){    theOutput=clues[currentJoke];    state=SENTCLUE;  } else{    theOutput=″You′re supposed to say\″Who′s there?\″!Try again.Knock!Knock!″;   }  }else if(state==SENTCLUE){     if(theInput.equalsIgnoreCase(clues[currentJoke]+″who?″)){     theOutput=answers[currentJoke]+″Want another?(y/n)″;     state=ANOTHER;   } else{     theOutput=″You′re supposed to say\″″+clues[currentJoke]+″who?\″″+″!Try again.Knock!Knock!″;   state=SENTKNOCKKNOCK;   }  } else if(state==ANOTHER){   if(theInput.equalsIgnoreCase(″y″)){    theOutput=″Knock!Knock!″;    if(currentJoke==(NUMJOKES-1))       currentJoke=0    else     currentJoke++;    state=SENTKNOCKKNOCK;   } else{    theOutput=″Bye.″;   state=WAITING;   }  }  return theOutput; }}//服务器程序classclasss服务器程序 KnockKnockServer{public static void main(String[]args){   ServerSocket serverSocket=null;   try {      serverSocket=new ServerSocket(4444);// 创建服务器端socketetet   }catch(IOException e){   System.out.println(″Could not listen on port:″+4444+″,″+e;   System.exit(1);   }  Socket clientSocket=null;  try{  clientSocket=serverSocket.accept();///监听申请连接到socket的要求,并建立连接  }catch(IOException e){  System.out.println(″Accept failed:″+4444+″,″+e);  System.exit(1);  }  try{  ///通过客户端socket获取输入数据流对象,可以读取客户端输入的信息  ///通过客户端socket获取输出数据流对象,通过它可以输入到客户端的信息  DataInputStream is=new DataInputStream(new BufferedInputStream(clientSocket.getInputStream()));  PrintStream os=new PrintStream(new BufferedOutputStream(clientSocket.getOutputStream(),1024),false);  ///KKState类用于处理输入的会话信息,然后返回设定的答案  KKState kks=new KKState():  String inputLine,outputLine;  outputLine=kks.processInput(null);  os.println(outputLine);//第一次运行,输入参数为null,kks返回:″Knock!Knock!Knock!″;然后写入客户端。  0s.flush();  ///如果客户端没有输入,readLine将被阻塞;如果客户端关闭,readLine将返回null。  ///在下面的循环句中,通过阅读一行,然后写一行与客户互动。  while((inputLine=is.readLine())!=null){  outputLine=kks.processInput(inputLine);     os.println(outputLine);     os.flush();     if(outputLine.equals(″Bye.″))break;  }  //完成以下清除工作。  os.close();  is.close();  clientSocket.close();  serverSocket.close();  } catch(IOException e){  e.printStackTrace();  }}}  //客户端程序import java.io.*;import java.net.*;public class EchoTest{  public static void main(Stringargs){  Socket echoSocket=null;  DataOutputStream os-null;  DataInputsStream is=null;  DataInputStream stdIn=new DataInputStream(System.in);  try{ echoSocket=new Socket(″myHost″,4444);   os=new DataOutputStream(echoSocket.getOutputStream());   is=newDataInputStream(echoSocket.getInputStream());  } catch(UnknownHostException e){  System.err.println(″Don`t know about host:myHost″);  } catch(IOException e){  System.err.println(″Couldn`t get I/O for the connection to:myHost″);  }  if(echoSocket!=null && os!=null && os!=null&& is!=null){  try{   String userInput;    while((userInput=stdin.readLine())!=null){   os.writeBytes(userInput);   os.writeByte(″\n′);   System.out.println(″echo:″+is.readLine()); }   os.close();   is.close();   echoSocket.close();   } catch (IOException e){    System.err.println(″I/O failed on the connection to:myHost″);   }  }}}

  二、 UDP

  UDP的使用与TCP大不相同。TCP必须在服务器端创建socket,然后在客户端创建socket,向服务器端发出连接请求,然后在服务器端创建与客户端socket对应的socket,并通过socket获得输入输出流。这样,网络通信就变成了类似文件I/O的方式,socket机制掩盖了所有网络通信的复杂性(见图2);使用UDP比较简单。在通信中,客户和服务端只涉及两个主要类别:DatagramSocket和DatagramPacket。Datagrampacket类可视为信息的载体,必须为其建立数据缓冲区,以容纳发送或接受的具体信息;Datagramsocket可视为Datagrampacket的发送或接受装置,发送Packet必须知道发送的主机地址和端口,接受只有一个Packet对象作为容器(见图3)。

  //本程序说明:首先,服务器端生成Datagramsocket,监控端口,并准备截获发送到端口的数据报告。一旦客户端发送服务器端机器和端口的数据报告,服务器将接收数据报告,获取数据报告的发送地址和发送端口,并向发送地址和端口发送响应报告。报告内容是服务器端的一个文件one-liners.如果txt中的一行文本不存在,则发送服务器端的当前时间。  //服务器端程序:import java.io.*;import java.net.*;import java.util.*;//QuoteServer只是提供服务程序的一个入口,主要程序流程包含在QuoteServer中。 在Thread中。class QuoteServer{   public static void main(Stringargs){   new QuoteServerThread().start();  }}class QuoteServerThread extends Thread{  private DatagramSocket socket=null;/用于发送和接收数据报告  private DataInputStream qfs=null; ///用于读取one-liners.txt文件  QuoteServerThread(){   super(″QuoteServer″);   try{   socket=new DatagramSocket();   System.out.println(″QuoteServer listening on port:″+socket.getLocalPort());///显示服务器端DatagramSocket的端口号(供客户端使用)   } catch(java.net.SocketExceptione){   System.err.println(″Could not create datagram socket.″);   }   this.openInputFile();  }  public void run(){   if(socket==null)returnm;   while(true){    try{    byte[]buf=new byte[256]; ///为DatagramPacket建立内存缓冲区    DatagramPacket packet;    InetAddress address;   int port;   String dString=null;   packet=new DatagramPacket(buf,256);   socket.receive(packet); //接收发送到地址和端口的数据报告   address=packet.getAddress(); ///获取数据报告的源发送地址   port=packet.getPort();获取数据报告的源发送端口   if(qfs==null)    dString=new Date().toString();   else   dString=getNextQuote();   dString.getBytes(0,dString.length(),buf,0);   packet=new DatagramPacket(buf,buf.length,address,port);   socket.send(packet); ///发回服务器端响应数据报告   } catch(IOExceptione){   System.err.println(″IOException:″+e);   e.printStackTrace();  } }}protected void finalize(){  if(socket!=null){   socket.close();   socket=null;   System.out.println(″Closing datagram socket.″);  }}private void openInputFile(){  try{   qfs=new DataInputStream(new FileInputStream(″one-liners.txt″));  }catch(java.io.FileNotFoundException e){   System.err.println(″Could not open quote file.Serving time instead.″); }}private String getNextQuote(){  String returnValue-null;  try{   if((returnValue=qfs.readiine())==null){   qfs.close();   this.openInputFile();   returnValue=qfs.readLine(); //文件应至少有一行!   }  }catch(IOException e){    returnValue=″IOException occurred in server.″;  }  return returnValue;}}//客户端必须输入java Quoteclient主机名称 以端口号的形式运行客户程序import java.io*;impor tjava.net.*;impor tjava.util.*;class QuoteClient{  public static void main(Stringargs){   int port;   InetAddress address;   DatagramSocket socket=null;   DatagramPacket packet;   bytesendBuf=new byte[256];   if(args.length!=2){     System.out.println(″Usage:java QuoteClient ″); return;}try{   socket=new DatagramSocket(); ///建立Datagramsocket发送数据报} catch(java.net.SocketException e){  System.err.println(″Could not create datagram socket.″);}if(socket!=null){  try{   ///发送数据   por=Integer.parseInt(args[1];   address=InetAddress.getByName(args[0]);   packet=new DatagramPacket(sendBuf,256,address,port);   socket.send(packet);   //获得应答   packet=new DatagramPacket(sendBuf,256);   socket.receive(packet);   String received=new String(packet.getData(),0);   System.out.println(″Quote of the Moment:″+received);   socket.close();  }catch(IOException e){   System.err.println(″IOException;″+e);   e.printStackTrace();   }  } }}