关于JAVA网络编程的技术非常繁多,如:SOCKET、RMI、EJB、WEBSERVICE、MQ、中间数据等等方法,但是万变都是源于基础中通信原理,有些是轻量级的、有重量级的;有实时调用、有异步调用;这么多的技术可以说什么都可以用,关键在什么场合用什么最适合你,这些技术主要用于多个子系统之间相互通信的方法,如一个大型的软件应用分多个子系统,它们可能由不同的厂商来完成,这些子系统最终需要整合为一个系统,那么整合的基础就是交互,要么是通过数据交互,要么是通过接口调用,要么通过中间数据等等。本文从最基本的网络编程开始说起,逐步引入SOCKET的编程,其余的后续逐步加入。
付:学SCOKET一定要学会流,但是流也是JAVA语言上最难的其中之一,不过不用畏惧,因为JAVA语言本身比较简单,再难也难不倒那里去,JAVA最好的是设计和架构的思想,当然语言本身也具有一定的魅力,但语言本身我个人认为他不是JAVA长久不衰的资本。
1、JAVA读网页流文件
2、IP地址解析
3、最简单的SCOKET程序
4、通过SCOKET传送对象
5、SCOKET多线程交互或服务
6、广播方法
下面写入正文:
1、JAVA读网页流文件
//下面的代码是用于将百度首页的HTML内容读取到本地
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; public class URLConnectTest { public static void main(String []agrs) { URLConnection conn = null; BufferedReader reader = null; try { URL url = new URL("http://www.baidu.com"); conn = url.openConnection(); conn.connect(); String contentType = conn.getContentType(); System.out.println("类型&字符集:"+contentType); System.out.println("文本长度:"+conn.getContentLength()); //System.out.println(conn.getDate()); //System.out.println(conn.getLastModified()); //System.out.println(conn.getExpiration()); reader = new BufferedReader(new InputStreamReader(conn.getInputStream(),contentType.substring(contentType.indexOf("charset=")+8))); String str = null; System.out.println("资源文件内容如下:"); while((str = reader.readLine())!=null) { System.out.println(str); } reader.close(); } catch (MalformedURLException e) { e.printStackTrace(); } catch(IOException e) { e.printStackTrace(); }finally { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } }
这段代码运行后将会输出百度首页的HTML代码,你可以通过这些方法去挖掘一些网络资源信息,将其通过一定的规则解析后,得到相应可用数据到本地的数据库或者参数文件中,为你本地的系统提供一些辅助性的数据(如:天气预报、相关新闻等等作为本地系统的一种友情提示)。
这段应该很容看懂,不用多说,红色部分稍微有点点晕,这部分主要是为了保证字符集统一,方便在输出时解析为对应字符集进行输出,如:网站输出是UTF-8,通过通过conn.getContentType()获取到字符集为:text/html;charset=utf-8 ,此时是将utf-8这部分截取出来说明是需要解析的对应字符集,所以在这里使用了一个substring操作。
至于细节,这部分代码就不用多说,非常简单。
2、IP地址解析
IP地址解析,首先基础获取INTERNET对象的一种方法:
InetAddress.getLocalHost() 获取本地主机的相关信息
InetAddress.getByName("www.baidu.com") 通过名称获取相应域名的相关信息的对象
其获取到的对象类型为:java.net.InetAddress类型,该类型的对象可以通过方法:getAddress()可以获取到相应地址的byte信息以及getHostAddress直接获取到IP地址、getHostName获取到主机名或域名。
下面先直接给出一段测试代码,方便查看:
import java.net.InetAddress; import java.net.UnknownHostException; public class InetAddressTest { public static void main(String[] args) { try { displayOneAddress(InetAddress.getLocalHost(), "通过方法获取本机信息"); displayOneAddress(InetAddress.getByName("localhost"), "通过名称本机信息"); displaySomeAddress(InetAddress.getAllByName("www.baidu.com"), "通过名称获取百度的信息"); } catch (UnknownHostException e) { e.printStackTrace(); } } private static void displaySomeAddress(InetAddress[] address, String file) { for (int i = 0, size = address.length; i < size; i++) { displayOneAddress(address[i], file + "第" + (i + 1) + "个主机。"); } } private static void displayOneAddress(InetAddress address, String title) { System.out.print("/n" + title + "/t"); System.out.println(address); byte[] byte1 = address.getAddress(); if (byte1.length == 4) { System.out.print("IPV4协议。IP地址为:"); } else { System.out.print("IPV6协议。IP地址为:"); } for (int i = 0, size = byte1.length; i < size; i++) { int tmp = (byte1[i] >= 0) ? byte1[i] : (256 + byte1[i]); System.out.print(tmp + "."); } System.out.println("/n"+address.getHostAddress()); System.out.println("主机名:" + address.getHostName()); } }
在我本机运行后将会输出:
通过方法获取本机信息 xieyu/192.168.0.111
IPV4协议。IP地址为:192.168.0.111.
192.168.0.111
主机名:xieyu
通过名称本机信息 localhost/127.0.0.1
IPV4协议。IP地址为:127.0.0.1.
127.0.0.1
主机名:localhost
通过名称获取百度的信息第1个主机。 www.baidu.com/119.75.218.45
IPV4协议。IP地址为:119.75.218.45.
119.75.218.45
主机名:www.baidu.com
通过名称获取百度的信息第2个主机。 www.baidu.com/119.75.217.56
IPV4协议。IP地址为:119.75.217.56.
119.75.217.56
主机名:www.baidu.com
这里使用displayOneAddress方法主要就是用于查看一个主机对象下面的相关信息,以及分别使用那一种解析方法进行解析,即获取到的地址和实际的地址与256之间的关系;另外使用displaySomeAddress主要为了显示多个主机信息的情况上面分别显示了本机和通过主机名获取本机、百度(直接对外的,内部负载无法得知)主机信息。
3、最简单的SCOKET程序
socket编程也是非常古老但是一直没有过时的一种技术,因为它真的很不错,现在很多通信协议也都是基于SOCKET为基础编写的,尤其是胖客户端的平台或C/S结构,很多时候需要一种长连接机制来完成,使用SOCKET的确是很好的选择,这里首先给一个最简单的SOCKET程序开个头吧:
要写一个SCOKET程序最少要写两段代码来实现,即一个服务端、一个客户端,而且两段代码都要一起运行才能使得运行成功(所谓一起运行就是开两个窗口别分JAVA两个JAVA文件或者有集成工具也有其它的办法,启动一般是先启动服务器端,然后再启动客户端)。
此时首先构造服务器端的一段简单代码:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.ServerSocket; import java.net.Socket; public class NormalServer { public static void main(String []agrs) { ServerSocket server = null; try { server = new ServerSocket(8080); System.out.println("服务器信息为:"+server.getInetAddress().getHostAddress()+"/t"+server.getLocalPort()); while(true) { Socket socket = server.accept();//等待接收一个请求 System.out.println("接收到一个请求:"+socket.getInetAddress()); BufferedReader sin = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(),true); String str; System.out.println("开始读取数据。"); while(!"baibai".equals(str = sin.readLine())) { System.out.println("/t"+str); } System.out.println("服务器端读取数据完毕。"); writer.println("服务器端读取完毕!!!!!!!!!!"); writer.flush(); writer.close(); sin.close(); } } catch (IOException e) { e.printStackTrace(); }finally { if(server != null) { try { server.close(); } catch (IOException e) { e.printStackTrace(); } } } } }
这里在服务器端开辟了一个8080端口,如果你的8080端口被占用,可以换用其它端口即可,服务端读取数据并输出客户端发送的数据,待客户端有结束符号“baibai”的时候,就终止读取,并向客户端输出读取完毕的标志。
此时来编写一个客户端向服务器端发送数据:
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.Socket; import java.net.UnknownHostException; public class NoramlClient { public static void main(String []agrs) { try { Socket socket = new Socket("localhost",8080); //BufferedReader pin = new BufferedReader(new InputStreamReader(System.in)); BufferedReader sin = new BufferedReader(new InputStreamReader(socket.getInputStream())); PrintWriter writer = new PrintWriter(socket.getOutputStream(),true); String line = "谢宇"; writer.println(line); writer.println("baibai"); writer.flush(); System.out.println(sin.readLine()); sin.close(); //pin.close(); writer.close(); socket.close(); } catch (UnknownHostException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
此时创建一个和服务器端的链接,我这里使用的localhost代表我本地,具体情况可以具体修改,端口也是这样,在这个SCOKET基础上开通一个输入流和输出流,此时向服务器端发送数据,并得到服务器端返回的数据。
此时将两个JAVA文件分别编译成class文件,然后开启两个终端,第一个终端先将服务器端的class运行起来,然后再运行第二个class,第二个class可以反复执行。
可能大家代码都看得懂,估计就是这个“流”有点点晕,在这里先不提及流的细节,因为这个可能提及起来专门写几十页也写不完,而就SOCKET这部分首先明确一点,就是这是服务器端还是客户端,SCOKET对象是谁,好了,分两种情况说明:
1、服务器端得到的scoket对象是客户端发送过来的,这个套接字包含了客户端的相关信息以及连接信息,这个对象客户创建输出输出流,这个输入流就是输入到本机内存的意思,而输出流是输出到终端的意思,所以服务器端使用输入流来读取客户端的信息,因为输入流的信息就是读入到本机内存的,而通过输出流向客户端发送信息,就是向一个终端发送信息,这个终端我相信大家用的最多的就是屏幕,而屏幕输出用得最多的就是System.out.println(),自己看看这段代码的源码你会发现它也是由输出流来完成的,所谓输出就是输出到终端(终端可以是网络、可以是屏幕、可以是外围设备、可以磁盘文件等等),而他们在很多情况下都有一些默认值,如在WEB编程中的内置对象out,就是向网络客户端输出信息,它也是基于流去实现的。
2、客户端发送socket也是同样的道理,相对客户端,此时的输出流就是向服务器端输出了,而输出流就是 从服务器端获取到的信息。
不知道我这样解释是否能够听明白,不过我自己是这样理解的,对于流的概念还很多,这里只是开个头而已,如上面提及的System.out.print你可以让他不输出到屏幕,只需要你做一个相应的PringStream对象(假如叫做outer对象),它可以指向其他地方,如一个文件,此时通过设置:System.setOut(outer)来完成设置过程,此时当你使用System.out.println()的时候,它将不会再输出到屏幕,而是输出到文件,其余输入流也可以;流也有很多种,很多流之间存在一种规则性的转换方法,用好了有些时候如鱼得水,用不好则到处是问题。
4、通过SCOKET传送对象
未完待续。。。。。。。。。。。
5、SCOKET多线程交互或服务
6、广播方法