现在的位置: 首页 > 综合 > 正文

Java程序员从笨鸟到菜鸟之(十三)java网络通信编程

2013年08月22日 ⁄ 综合 ⁄ 共 6491字 ⁄ 字号 评论关闭

 本文来自:曹胜欢博客专栏。转载请注明出处:http://blog.csdn.net/csh624366188

 

       首先声明一下,刚开始学习java网络通信编程就对他有一种畏惧感,因为自己对网络一窍不通,所以。。。呵呵。。你懂得,昨天又仔细的学习了一遍,感觉其实java网络编程也没想象的那么难,不信,咱一起看看。。。呵呵。。

     网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据。程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴。在发送和接收数据时,大部分的程序设计语言都设计了专门的API实现这些功能,程序员只需要调用即可。所以,基础的网络编程可以和打电话一样简单

一:首先看一下网络通讯的两种方式

1.TCP(传输控制协议)方式

TCP方式就类似于拨打电话,使用该种方式进行网络通讯时,需要建立专门的虚拟连接,然后进行可靠的数据传输,如果数据发送失败,则客户端会自动重发该数据

2. UDP(用户数据报协议)方式

     UDP方式就类似于发送短信,使用这种方式进行网络通讯时,不需要建立专门的虚拟连接,传输也不是很可靠,如果发送失败则客户端无法获得

 这两种传输方式都是实际的网络编程中进行使用,重要的数据一般使用TCP方式进行数据传输,而大量的非核心数据则都通过UDP方式进行传递,在一些程序中甚至结合使用这两种方式进行数据的传递。由于TCP需要建立专用的虚拟连接以及确认传输是否正确,所以使用TCP方式的速度稍微慢一些,而且传输时产生的数据量要比UDP稍微大一些。

总结一下UDPTCP协议的区别

-使用UDP时,每个数据报中都给出了完整的地址信息,因此无需要建立发送方和接收方的连接。 

–对于TCP协议,由于它是一个面向连接的协议,在socket之间进行数据传输之前必然要建立连接,所以在TCP中多了一个连接建立的时间 

–使用UDP传输数据时是有大小限制的,每个被传输的数据报必须限定在64KB之内。 

–TCP没有这方面的限制,一旦连接建立起来,双方的socket就可以按统一的格式传输大量的数据。 

–UDP是一个不可靠的协议,发送方所发送的数据报并不一定以相同的次序到达接收方。 

–TCP是一个可靠的协议,它确保接收方完全正确地获取发送方所发送的全部数据 

-TCP在网络通信上有极强的生命力,例如远程连接(Telnet)和文件传输(FTP)都需要不定长度的数据被可靠地传输。 

—相比之下UDP操作简单,而且仅需要较少的监护,因此通常用于局域网高可靠性的分散系统中client/server应用程序 

二:基于url的网络编程

1.创建一个URL

为了表示URL, java.net中实现了类URL。我们可以通过下面的构造方法来初始化一个URL对象:
  
(1) public URL (String spec);
     通过一个表示URL地址的字符串可以构造一个URL对象
     URL urlBase=new URL("http://www. 263.net/")
   (2) public URL(URL context, String spec);
     通过基URL和相对URL构造一个URL对象。
     URL net263=new URL ("http://www.263.net/");
     URL index263=new URL(net263, "index.html")
  (3) public URL(String protocol, String host, String file);
     new URL("http", "www.gamelan.com", "/pages/Gamelan.net. html");
  (4) public URL(String protocol, String host, int port, String file);
     URL gamelan=new URL("http", "www.gamelan.com", 80, "Pages/Gamelan.network.html");

  注意:类URL的构造方法都声明抛弃非运行时例外(MalformedURLException),因此生成URL对象时,我们必须要对这一例外进行处理,通常是用try-catch语句进行捕获。格式如下:

try{
     URL myURL= new URL()
  }catch (MalformedURLException e){
  …  }

2. 解析一个URL

一个URL对象生成后,其属性是不能被改变的,但是我们可以通过类URL所提供的方法来获取这些属性:
   public String getProtocol() 获取该URL的协议名。
   public String getHost() 获取该URL的主机名。
   public int getPort() 获取该URL的端口号,如果没有设置端口,返回-1。
   public String getFile() 获取该URL的文件名。
   public String getRef() 获取该URL在文件中的相对位置。
   public String getQuery() 获取该URL的查询信息。
   public String getPath() 获取该URL的路径
    public String getAuthority() 获取该URL的权限信息
   public String getUserInfo() 获得使用者的信息
    public String getRef()获得该URL的锚

3.从URL读取WWW网络资源

当我们得到一个URL对象后,就可以通过它读取指定的WWW资源。这时我们将使用URL的方法openStream(),其定义为:
InputStream openStream();
  
  方法openSteam()与指定的URL建立连接并返回InputStream类的对象以从这一连接中读取数据。
URL url = new URL("http://www.baidu.com");

//使用openStream得到一输入流并由此构造一个BufferedReader对象

BufferedReader br = new BufferedReader(new InputStreamReader( url.openStream()));

String line = null;

while(null != (line = br.readLine()))

{

System.out.println(line);

}

br.close();

三:客户端网络编程步骤

按照前面的基础知识介绍,无论使用TCP方式还是UDP方式进行网络通讯,网络编程都是由客户端和服务器端组成

1.客户端网络编程步骤

        客户端(Client)是指网络编程中首先发起连接的程序,客户端一般实现程序界面和基本逻辑实现,在进行实际的客户端编程时,无论客户端复杂还是简单,以及客户端实现的方式,客户端的编程主要由三个步骤实现:

1、 建立网络连接

客户端网络编程的第一步都是建立网络连接。在建立网络连接时需要指定连接到的服务器的IP地址和端口号,建立完成以后,会形成一条虚拟的连接,后续的操作就可以通过该连接实现数据交换了。

2、 交换数据

连接建立以后,就可以通过这个连接交换数据了。交换数据严格按照请求响应模型进行,由客户端发送一个请求数据到服务器,服务器反馈一个响应数据给客户端,如果客户端不发送请求则服务器端就不响应。

根据逻辑需要,可以多次交换数据,但是还是必须遵循请求响应模型。

3、 关闭网络连接

在数据交换完成以后,关闭网络连接,释放程序占用的端口、内存等系统资源,结束网络编程。

        最基本的步骤一般都是这三个步骤,在实际实现时,步骤2会出现重复,在进行代码组织时,由于网络编程是比较耗时的操作,所以一般开启专门的现场进行网络通讯。

2.服务器端网络编程步骤

        服务器端(Server)是指在网络编程中被动等待连接的程序,服务器端一般实现程序的核心逻辑以及数据存储等核心功能。服务器端的编程步骤和客户端不同,是由四个步骤实现,依次是:

1、 监听端口

服务器端属于被动等待连接,所以服务器端启动以后,不需要发起连接,而只需要监听本地计算机的某个固定端口即可。

这个端口就是服务器端开放给客户端的端口,服务器端程序运行的本地计算机的IP地址就是服务器端程序的IP地址。

2、 获得连接

当客户端连接到服务器端时,服务器端就可以获得一个连接,这个连接包含客户端的信息,例如客户端IP地址等等,服务器端和客户端也通过该连接进行数据交换。

一般在服务器端编程中,当获得连接时,需要开启专门的线程处理该连接,每个连接都由独立的线程实现。

3、 交换数据

服务器端通过获得的连接进行数据交换。服务器端的数据交换步骤是首先接收客户端发送过来的数据,然后进行逻辑处理,再把处理以后的结果数据发送给客户端。简单来说,就是先接收再发送,这个和客户端的数据交换数序不同。

其实,服务器端获得的连接和客户端连接是一样的,只是数据交换的步骤不同。

当然,服务器端的数据交换也是可以多次进行的。

在数据交换完成以后,关闭和客户端的连接。

4、 关闭连接

当服务器程序关闭时,需要关闭服务器端,通过关闭服务器端使得服务器监听的端口以及占用的内存可以释放出来,实现了连接的关闭。

四:一个基础的网络类——InetAddress类

    该类的功能是代表一个IP地址,并且将IP地址和域名相关的操作方法包含在该类的内部。

    关于该类的使用,下面通过一个基础的代码示例演示该类的使用,代码如下:

  1. <span style="BACKGROUND-COLOR: #333333">public class InetAddressDemo {  
  2.   
  3. public static void main(String[] args) {  
  4.   
  5. try {  
  6.   
  7. // 使用域名创建对象  
  8.   
  9. InetAddress inet1 = InetAddress.getByName("www.163.com");  
  10.   
  11. System.out.println(inet1);  
  12.   
  13. // 使用IP创建对象  
  14.   
  15. InetAddress inet2 = InetAddress.getByName("127.0.0.1");  
  16.   
  17. System.out.println(inet2);  
  18.   
  19. // 获得本机地址对象  
  20.   
  21. InetAddress inet3 = InetAddress.getLocalHost();  
  22.   
  23. System.out.println(inet3);  
  24.   
  25. // 获得对象中存储的域名  
  26.   
  27. String host = inet3.getHostName();  
  28.   
  29. System.out.println("域名:" + host);  
  30.   
  31. // 获得对象中存储的IP  
  32.   
  33. String ip = inet3.getHostAddress();  
  34.   
  35. System.out.println("IP:" + ip);  
  36.   
  37. catch (Exception e) {  
  38. }  
  39. }  
  40. }  
  41.   </span>  

注:InetAddress 类没有明显的构造函数。为生成一个InetAddress对象,必须运用一个可用的工厂方法。 

–工厂方法(factory method)仅是一个类中静态方法返回一个该类实例的约定。对于InetAddress,三个方法 getLocalHost( )、getByName( )以及getAllByName( )可以用来创建InetAddress的实例 

•如果这些方法不能解析主机名,它们引发一个UnknownHostException异常。 

五:TCP编程

在Java语言中,对于TCP方式的网络编程提供了良好的支持,在实际实现时,以java.net.Socket类代表客户端连接,以java.net.ServerSocket类代表服务器端连接。在进行网络编程时,底层网络通讯的细节已经实现了比较高的封装,所以在程序员实际编程时,只需要指定IP地址和端口号码就可以建立连接了。

在客户端网络编程中,首先需要建立连接,在Java API中以java.net.Socket类的对象代表网络连接

客户端

1) 建立Socket连接 

Socket socket2 = new Socket(www.sohu.com,80);

2)按照“请求-响应”模型进行网络数据交换

在Java语言中,数据传输功能由Java IO实现,也就是说只需要从连接中获得输入流和输出流即可,然后将需要发送的数据写入连接对象的输出流中,在发送完成以后从输入流中读取数据即可。示例代码如下:

 OutputStream os = socket1.getOutputStream(); //获得输出流

 InputStream is = socket1.getInputStream();     //获得输入流

这里获得的只是最基本的输出流和输入流对象,还可以根据前面学习到的IO知识,使用流的嵌套将这些获得到的基本流对象转换成需要的装饰流对象,从而方便数据的操作。

3关闭网络连接

 socket1.close();

服务器端

首先需要说明的是,客户端的步骤和服务器端的编写步骤不同,所以在学习服务器端编程时注意不要和客户端混淆起来。

1)监听端口

ServerSocket ss = new ServerSocket(10000);

2)获得连接

当有客户端连接到达时,建立一个和客户端连接对应的Socket连 接对象,从而释放客户端连接对于服务器端端口的占用

Socket socket = ss.accept();

该代码实现的功能是获得当前连接到服务器端的客户端连接。需要说明的是accept和前面IO部分介绍的read方法一样,都是一个阻塞方法,也就是当无连接时,该方法将阻塞程序的执行,直到连接到达时才执行该行代码。另外获得的连接会在服务器端的该端口注册,这样以后就可以通过在服务器端的注册信息直接通信,而注册以后服务器端的端口就被释放出来,又可以继续接受其它的连接了。

3)按照“请求-响应”模型进行网络数据交换

这里获得的Socket类型的连接就和客户端的网络连接一样了,只是服务器端需要首先读取发送过来的数据,然后进行逻辑处理以后再发送给客户端,也就是交换数据的顺序和客户端交换数据的步骤刚好相反

 InputStream is = ss.getInputStream();     //获得输入流

OutputStream os = ss.getOutputStream(); //获得输出流

4)关闭服务器端连接

ss.close();

以上就是基本的TCP类型的服务器和客户端代码实现的步骤,下面以一个简单的echo(回声)服务实现为例子,介绍综合使用示例,实现的代码如下:

  1. public class Constants {  
  2.   
  3.     public static void main(String[] args) {  
  4.         ServerSocket serverSocket = null;  
  5.         Socket socket = null;  
  6.         OutputStream os = null;  
  7.         InputStream is = null;  
  8.         // 监听端口号  
  9.         int

抱歉!评论已关闭.