Java网络编程基础
2016-05-08 16:19
465 查看
一、Java网络编程
网络编程在如今这样的网络时代是十分重要的,Java语言提供了丰富的类库来支持网络编程。这里将重点介绍Java.net中的类,充分了解认识Java网络编程的原理并深入学习各模块。在学习Java网络编程之前首先需要具备一定的网络知识:网络的层次结构,常见的网络协议(TCP/IP),IP地址端口号等等。需要学习了解这些内容,可以参考前面的文章。二、主机地址和IP地址
在进行网络访问时,每个主机都有IP地址,也有主机名(域名),为了便于处理与之相关的问题,Java.net包中提供了地址获取类InetAddress,当然还有对应的子类Inet4Address,Inet6Address,分别对应IPv4和IPv6。这里介绍InetAddress的基本用法。1、InetAddress对象
InetAddress类是没有显式的构造函数的,所以只能通过它的静态函数来获取对象,InetAddress主要就有两个重要的变量,一个是IP地址,一个就是对应的域名(主机名)。因此下面的函数都是通过这两个变量来实现对象建立的,几个函数分别为:
static InetAddress getByName(String host)
static InetAddress[] getAllByName(String host)
static InetAddress getByAddress(byte[] addr)
static InetAddress getByAddress(String host,byte[] addr)
static InetAddress getLocalHost()
对应的意思分别是:1、通过域名获取对象(的ip)2、通过域名获取对象(所有ip)3、通过ip获取对象(的域名)4、通过域名和ip对象5、获取本机对象。第二个与第一个区别就在于它会获取多个对象,因为有些域名是有多个IP地址的。
2、成员函数
InetAddress类中实现了一些常用的函数:
boolean isReachable(int timeout):地址是否可达,timeout为测试时间
String getHostName():获取此IP地址的主机名
byte[] getAddress():返回原始IP地址(字节数组形式)
String getHostAddress():返回IP地址(文本形式)
下面的部分代码测试了一些函数,可以更直观的了解这些函数的应用:
package net; import java.net.Inet4Address; import java.net.InetAddress; public class NetTest { public static void main(String[] args) throws Exception{ byte[] ip = {119,75,(byte) 218,70}; InetAddress ia = InetAddress.getByName("www.baidu.com"); InetAddress ia2 = InetAddress.getByAddress("www.baidu.com",ip); InetAddress[] ia3 = InetAddress.getAllByName("www.baidu.com"); System.out.println("ia ip:"+ia.getHostAddress()); System.out.println("ia name:"+ia.getHostName()); System.out.println("ia2 ip:"+ia2.getHostAddress()); System.out.println("ia2 name:"+ia2.getHostName()); System.out.println("ia3 length:"+ia3.length); System.out.println("ia3 byte[]:"+ia3[0].getAddress()); System.out.println("ia3 ip1:"+ia3[0].getHostAddress()); System.out.println("ia3 ip2: "+ia3[1].getHostAddress()); System.out.println("local name:"+InetAddress.getLocalHost().getHostName()); System.out.println("local ip:"+InetAddress.getLocalHost().getHostAddress()); } } //输出结果 ia ip:119.75.217.109 ia name:www.baidu.com ia2 ip:119.75.218.70 ia2 name:www.baidu.com ia3 length:2 ia3 byte[]:[B@79b7d13e ia3 ip1:119.75.217.109 ia3 ip2:119.75.218.70 local name:PC-201511271651 local ip:192.168.1.110
三、URLDecoder和URLEncoder
在URL中有时候会有参杂有中文,但是当把这个URL赋值到代码编辑窗口时,中文部分显示的又不是中文,而是类似于%E5%88%98%E8%AF的一个形式,其实这里涉及到一些字符的编码转换,URLDecoder和URLEncoder两个类就是用来做转换的,其中没有定义构造函数,分别包含静态的decode()方法和encode()方法,可以直接通过类名来调用。String decode(String s, String enc):s用enc解码方式解码
String encode(String s, String enc):s用enc编码方式编码
关于其中涉及的application/x-www-form-urlencoded等可以参考:
http://www.aikaiyuan.com/6324.html
package net; import java.net.*; public class NetTest { public static void main(String[] args) throws Exception{ //下面是一个完整的url,其中的中文被编码了,下面取出进行解码 String str = "http://image.baidu.com/search/index?tn=" + "baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-" + "1&fr=&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=" + "0&fb=0&width=&height=&face=0&istype=2&ie=utf-8" + "&word=%E5%88%98%E8%AF%97%E8%AF%97&oq=%E5%88%98" + "%E8%AF%97%E8%AF%97&rsp=-1"; String str0 = "%E5%88%98%E8%AF%97%E8%AF%97"; //中文部分 String str1 = URLDecoder.decode(str0,"utf-8"); //解码 String str2 = URLEncoder.encode(str1,"utf-8"); //编码 System.out.println("str1: "+str1); System.out.println("str2: "+str2); } } //结果 str1: 刘诗诗 str2: %E5%88%98%E8%AF%97%E8%AF%97
四、URL、URLConnection、HttpURLConnection
1、URLurl即统一资源定位器,它指向网络资源的目录或文件,可以简单的视为网址,url主要有协议名,主机名,端口号,资源等组成。例如:http://img.ivsky.com/img/tupian/t/201602/16/shiweiyan-004.jpg,它的协议是http,中间是主机路径,后面为文件名,没有端口号(默认80)。
Java中的URL类就是这样一个处理url的类,它的对象有协议,主机,端口,文件等多个变量。下面介绍它的构造函数,URL有很多个构造函数,可以通过传出相应的字段来创建,最常用的就是直接传入一个url了,下面给出两个基本的函数:
public URL(String spec)
public URL(String protocol, String host, String file)
在创建了对象之后,类中提供了许多函数来获取类成员,下面的函数看名字就知道什么意思了,都是获取url对象相应的字段:
String getQuery()
String getPath()
String getUserInfo()
int getPort()
String getProtocol()
String getHost()
通过例子看看就行了:
public class NetTest { public static void main(String[] args) throws Exception{ URL url1 = new URL("http://blog.csdn.net/anialy/article/details/8364652"); URL url2 = new URL("http","img.ivsky.com/img/tupian/t/201602/16/","shiweiyan-004.jpg"); System.out.println("url1.protocol: "+url1.getProtocol()); System.out.println("url1.host: "+url1.getHost()); System.out.println("url1.path: "+url1.getPath()); System.out.println("url1.port: "+url1.getPort()); System.out.println("url1.file: "+url1.getFile()); System.out.println("url1.query: "+url1.getQuery()); System.out.println("url1.userinfo: "+url1.getUserInfo()); System.out.println("url1.default protocol: "+url1.getDefaultPort()); System.out.println(url1); System.out.println(url2); //URLConnection; //HttpURLConnection } } //输出 url1.protocol: http url1.host: blog.csdn.net url1.path: /anialy/article/details/8364652 url1.port: -1 url1.file: /anialy/article/details/8364652 url1.query: null url1.userinfo: null url1.default protocol: 80 http://blog.csdn.net/anialy/article/details/8364652 http://img.ivsky.com/img/tupian/t/201602/16/shiweiyan-004.jpg
类URL中还有函数URLConnection openConnection()用来建立一个连接对象。openStream来打开一个输入流读取数据 ,实际上就是URLConnection中的getInputStream(),下面都会讲。
2、URLConnection
URLConnection类是一个抽象类,它是所有应用程序和URL通信连接类的超类,典型的一个就是HttpURLConnection类,它就是类 URLConnection的一个子类。常用的一种用法就是:URLConnection urlConnection = url.openConnection();建立一个连接,至于urlConnection是抽象类实例的解释:这是多态性的一种用法,也叫面向接口编程,urlConnection只是一个引用。具体可以参考这里。
类URLConnection中定义了许多连接通信方面的函数,主要在其子类中得到应用,这里介绍一下常见函数:
设置连接属性:
setDoOutput(true);// 使用 URL 连接进行输出
setDoInput(true);// 使用 URL 连接进行输入
setUseCaches(false);// 忽略缓存
setRequestMethod(“POST”);//设置URL请求方法 (属于子类HttpURLConnection)
设置请求属性:
setRequestProperty(String key, String value)
key:”Content-Type”,”Connection”,”Charset”,user-agent…..
其他:
connect():打开一个url对应的连接
OutputStream getOutputStream():返回连接输出流
InputStream getInputStream():返回连接输入流
3、HttpURLConnection
HttpURLConnection类是URLConnection的一个子类,用于支持有关http协议的连接。下面实现一个向服务器发送GET请求并获取响应信息的例子:
package net; import java.io.*; import java.net.*; import java.util.List; import java.util.Map; public class NetTest { public static void main(String[] args) throws Exception{ String urlstr = "http://www.csdn.net/"; //System.out.println(url.getProtocol()); URL url = new URL(urlstr); //建立URL对象 //建立一个http连接对象 HttpURLConnection huc = (HttpURLConnection) url.openConnection(); //设置请求头属性(字段可以参考浏览器,这个就是模拟浏览器向服务器发送请求) huc.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"); huc.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0"); huc.setRequestProperty("Connection", "Keep-Alive");// 维持长连接 huc.connect(); //获取连接 //输出获取到的响应头部信息(按字段) Map<String, List<String>> map = huc.getHeaderFields(); for(String key:map.keySet()) System.out.println(key+":"+map.get(key)); } } //输出 null:[HTTP/1.1 200 OK] ETag:["571c264a-18db2"] Vary:[Accept-Encoding, Accept-Encoding] Date:[Sun, 24 Apr 2016 01:55:40 GMT] Content-Length:[101810] Last-Modified:[Sun, 24 Apr 2016 01:50:02 GMT] Keep-Alive:[timeout=20] Accept-Ranges:[bytes] Connection:[keep-alive] Content-Type:[text/html; charset=utf-8] Server:[openresty]
有关相关函数或参数等应用说明可以参考这里参数详解。
下面实现下载网页源代码的例子,传入一个ULR,可以获取到该网页的源代码内容:
package net; import java.io.*; import java.net.*; public class NetTest { public static void main(String[] args) throws Exception{ String urlstr = "http://www.csdn.net/"; URL url = new URL(urlstr); //建立URL对象 //建立一个http连接对象 HttpURLConnection huc = (HttpURLConnection) url.openConnection(); huc.connect(); //获取连接(不重要,下面一般会隐式执行) //从连接返回一个输入流 InputStream is = huc.getInputStream(); /** * 这里必须添加"utf-8",不然网页中文部分是乱码的, * InputStreamReader就是将byte类型的is按照"utf-8"方式转换成字符类型 */ BufferedReader buffer = new BufferedReader(new InputStreamReader(is,"utf-8")); StringBuffer bs = new StringBuffer(); String str = null; while((str=buffer.readLine())!=null){ //读取响应信息 bs.append(str).append("\n"); } System.out.println(bs); } }
上面的输出结果就是网页的源代码了,和直接在浏览器打开的源代码是一样的。可以利用这个代码分析做一些爬虫之类的都可以。
五、SocketSever、Socket
这一节主要简答介绍有关tcp通信的内容,即socket编程,这是进行可靠通信的主要内容,用于建立客户端和服务器端的连接,因此也可以叫做客户端-服务器编程。1、Socket
Socket类是Java中用于建立连接端口的一个类,即通过Socket实例建立一个通信接口用于与服务器通信。多用于客户端,常见两种创建方式:
Socket(String host, int port)
Socket(InetAddress address, int port)
都是要输入主机名和端口号,第二种的主机名是通过InetAddress类对象传递的。在Socket中还有两个重要的流处理函数:
InputStream getInputStream()
OutputStream getOutputStream()
两个函数额作用用于给Socket对象返回一个输入/输出流对象,用于进行连接端的信息传输。在Socket中还封装了许多相关处理的函数,这里不再详述。
2、SeverSocket
这个类是用于服务器创建一个监听Socket,用来监听来自客户端的请求信息。创建方式:
ServerSocket(int port) //针对特定端口的Socket
当服务器创建了一个Socket之后,需要开始工作,即监听来自客户端的信息并响应,这里应用到的函数就是accept(),它用来监听来自客户端的连接并返回一个Socket对象来处理该连接。
3、Server-Client
下面代码通过创建Socket实现客户端和服务器端的连接并实现互相发送信息的功能:
//客户端 import java.io.*; import java.net.*; public class Client { public static void main(String[] args) throws IOException{ //获取本机地址 InetAddress ip = InetAddress.getLocalHost(); System.out.println(ip.getHostName()); System.out.println(ip.getHostAddress()); //利用本机地址和端口号20000创建一个socket访问服务器 Socket socket = new Socket(ip,20000); //接收服务器信息(处理流) BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = br.readLine(); System.out.println("服务器的数据:"+line); //向服务器发送数据 PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println("你好,这里是客户端"); ps.close(); br.close(); } }
//服务器端 import java.io.*; import java.net.*; public class Server { public static void main(String[] args) throws IOException{ //创建一个serversocket,端口号20000 ServerSocket sever = new ServerSocket(20000); while(true){ System.out.println("waiting!"); //等待连接 Socket socket = sever.accept(); //获取到连接返回一个socket //获取客户端地址 InetAddress address = socket.getInetAddress(); System.out.println("主机名:"+address.getHostName()); System.out.println("ip地址:"+address.getHostAddress()); //向客户端发送数据(应用处理流) PrintStream ps = new PrintStream(socket.getOutputStream()); ps.println("你好,这里是服务器"); //接收客户端数据 BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = br.readLine(); System.out.println("客户端的数据:"+line); br.close(); //这里会关闭socket ps.close(); } } }
上面就是实现Socket通信的简单代码,客户端和服务器端相互独立。这里再介绍如何在eclipse中测试这个代码,这里建立两个工程,分别为客户端和服务器端工程,在eclipse中都为打开状态,首先点击到服务器工程所在页面,运行,这时服务器就开始监听连接了,然后打开客户端页面,运行,这时客户端就会运行并向服务器发送数据。虽然在同一台电脑上操作,但是地址等都是真实的,因此可以很好的模拟出实际的运行效果。通过控制台窗口可以看到各自的输出信息:
//服务器端 waiting! 主机名:PC-201511271651.lan ip地址:192.168.1.110 客户端的数据:你好,这里是客户端 waiting! //客户端 PC-201511271651 192.168.1.110 服务器的数据:你好,这里是服务器
这里分别输出了各自收到对方发送的信息,并且显示的地址和主机名也是一样的,可见数据的传输通道是建立且正确的。需要注意的是上面的代码中并没有直接关闭socket,因为在对应socket的处理流执行关闭(close)的过程中,sockct是会随之关闭的,因此在数据没有完全传输完之前不要将流关闭,不然socket也会关闭。如在上面的客户端若是在读取完服务器信息后马上关闭流br,那么流ps就不能再向服务器发送数据了,因为这时socket已经关闭,连接断开了是不能发送的。
上面我们分别看了客户端和服务器端控制台窗口消息,在eclipse中这两个消息是显示在不同的控制台窗口的,在eclipse中可以切换窗口(或者可以这样理解:在eclipse中可以同时运行多个工程,每个工程是独立的,有各自的控制台),方式:
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Linux socket 初步
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序