Java网络编程基础


网络编程:
(1)计算机网络中实现同通信必须有一些约定,这些约定 被称为通信协议。通信协议负责对传输速率,传输代码,代码结构,传输控制步骤,出错控制等制定处理标准。为了能够让两个节点之间进行对话,必须在他们之间建立通信工具,使彼此之间能够进行信息交换。
(2)通信协议通常由三部分组成:一是语义部分,用于决定双方对话的类型;二是语法部分,用于决定双方对话的格式;三是变换规则,用于决定通信双方的应答关系
(3)IP地址用于唯一标识网络中的一个通信实体,IP地址是数字型的,IP地址shiyige32位(32bits)整数,为方便记忆,通常将其分为4个8位的二进制数,每个8位整数可以转换成一个0-255的十进制整数 。
(4)端口是一个16位的整数,用于表示数据交给通信程序处理,因此,端口就是应用程序与外界交流的出入口,他是一种抽象的软件结构,包括一些数据结构和I/O缓冲区。
(5)不同的应用程序处理不同端口上的数据,同一台机器上不能有两个程序使用同一个端口,端口号可以是0-65535,通常把他们分为三类:
公认端口(well known ports) 从0到1023,他们紧密绑定(Binding)一些特定的服务。
注册端口(Registered Ports) 从1024到49151,他们松散的绑定一些服务,应用程序通常使用这个范围内的端口
动态\私有端口(Dynamic\private ports)从49152到65535,这些端口是应用程序使用的动态端口,应用程序一般不会主动使用这些端口。

————————————————————————————————————————————

JAVA的基本网络支持:
(1)Java为网络支持提供了java.net包,该包下的URL和URLConnection等类提供了以编程方式访问web服务的功能,而URLDecoder和URLEncoder则提供了普通字符串和application/x-www-form-urlencoded MIME字符串相互转换的静态方法。
(2)java提供了InetAddress类来代表IP地址,InetAddress下还有两个子类:Inet4Address和Inet6Address,他们分别代表Internet Protocol version4(IPV4)和 IPV6地址。
(3)InetAddress类没有提供构造器,而是提供了如下两个静态方法来获取InetAddress实例
getByName(String host): 根据主机获取对应的InetAddress对象。
getByAddress(byte[] addr):根据原始IP地址来获取对应的InetAddress对象

(4)InetAddress还提供了如下三个方法来获取InetAddress实例对应的IP地址和主机名
String getCanonicaHostName():获取IP地址的全限定域名
String getHostAddress() 返回该InetAddress实例对应的IP地址字符串(以字符串形式)
String getHostName() 获取此IP地址的主机名。
(5)InetAddress还提供了一个getLocalHost()方法来获取本机IP地址对应的InetAddress实例
(6)InetAddress还提供了一个isReachable()方法,用于测试是否可以达到该地址。

netAddress用法:
import java.net.InetAddress;
public class InetAddressTest{
public static void main(String[] args)
throws Exception
{
//根据主机名来获取对应的InetAddress实例
InetAddress ip = InetAddress.getByName("www.baidu.com");
//判断是否可达
System.out.println("www.baidu.com是否可达"+ip.isReachable(2000));
//获取该InetAddress实例的IP字符串
System.out.println(ip.getHostAddress());

//根据原始IP来获取InetAddress实例
InetAddress local =InetAddress.getByAddress(new byte[] {127,0,0,1});
//本机是否可达
System.out.println("本机是否可达"+local.isReachable(5000));
//获取该InetAddress实例对应的全限定域名
System.out.println(local.getCanonicalHostName());

}
}


使用URLDecoder和URLEncoder
(1) URLDecoder和URLEncoder用于完成普通字符串和 application/x-www-form-urlencoded MIME字符串之间的相互转换。
当搜索的关键字包含中文时,这些关键字就会变成“乱码”,其实这些不是乱码,而是application/x-www-form-urlencoded MIME字符串。
(2)当URL地址里包含西欧字符时,系统会自动将非西欧字符转换成application/x-www-form-urlencoded MIME字符串。编程过程中可能涉及普通字符串和这种字符串之间的相关转换,这就需要URLDecoder和URLEncoder类
(3)URLDecoder类包含一个docode(String s,String enc)静态方法,它可以将看上去是乱码的特殊字符串转换成普通字符串。
(4)URLEncoder类包含一个encode(String s,String enc)静态方法,它可以将普通字符串转换成application/x-www-form-urlencoded MIME字符串字符串。
(5)示例程序:

import java.net.URLDecoder;
import java.net.URLEncoder;

public class URLDecoderTest{
public static void main(String[] args)
throws Exception
{
//application/x-www-form-urlencoded MIME字符串转换成普通字符串
String code=URLDecoder.decode("%C7%AE%D6%D3%CA%E9", "utf-8");
System.out.println(code);

//将普通字符串转换成application/x-www-form-urlencoded MIME字符串
String code2=URLEncoder.encode("钱钟书", "GBK");
System.out.println(code2);
}
}

URL URLConnection URLPermission

URL(Uniform Resource Locator)对象代表统一资源定位器。URL类提供了多个构造器用于创建URL对象,一旦获得URL对象之后,就可以调用如下方法来调用该URL对应的资源。
String getFile() 获取该URL的资源名
String getHost() 获取该URL的主机名
String getPath() 获取该URL的路径部分
String getPort() 获取该URL的端口号
String getProtocol() 获取该URL的协议名称
URLConnection openConnection() 返回一个URLConnection对象,它代表了与URL所引用的远程对象的连接。
InputStream openStream() 打开与此URL的连接,并返回一个用于读取该URL资源的InputStream

URL对象提供的openStream()可以非常方便的读取远程资源,甚至实现多线程下载。下面实现了一个多线程下载工具。

package com.zou;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.URL;
import javax.net.ssl.HttpsURLConnection;
public class DownUtil
{

//定义下载资源的路径
private String path;
//指定下载文件的保存位置
private String targetFile;
//定义需要使用多少个线程下载资源
private int threadNum;
//定义下载的线程对象
private DownThread[] threads;
//定义下载文件的总大小
private int fileSize;
private Object[] thread;

public DownUtil(String path,String targetFile,int threadNum)
{
this.path=path;
this.threadNum=threadNum;
//初始化threads数组
threads=new DownThread[threadNum];
this.targetFile=targetFile;
}


public void download() throws Exception
{
URL url =new URL(path);
HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
conn.setConnectTimeout(5 *1000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept",
"image/gif,image/jpeg,iamge/pjpg,image/pjpeg,"
+"application/x-shockware-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/x-ms-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*");

conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
conn.setRequestProperty("Connection", "Keep-Alive");

//得到文件的大小
fileSize=conn.getContentLength();
conn.disconnect();
int currentPartSize=fileSize / threadNum+1;
RandomAccessFile file=new RandomAccessFile(targetFile, "rw");

//设置本地文件的大小
file.setLength(fileSize);
file.close();

for(int i=0;i<threadNum;i++){
//计算每个线程下载的开始位置
int startPos =i*currentPartSize;
//每个线程使用一个RandomAccessFile进行下载
RandomAccessFile currentPart=new RandomAccessFile(targetFile, "rw");

//定位该线程的下载位置
currentPart.seek(startPos);
//创建下载线程
threads[i]=new DownThread(startPos,currentPartSize,currentPart);
//启动下载线程
threads[i].start();
}

}
//获取下载的百分比
public double GetCompleteRate(){
//统计多个线程已经下载的总大小
int sumSize=0;
for(int i=0;i<threadNum;i++){
sumSize+=threads[i].length;

}
//返回已经完成的百分比
return sumSize *1.0 /fileSize;
}

private class DownThread extends Thread{
//当前线程的下载位置
private int startPos;
//定义当前线程负责下载文件的大小
private int currentPartSize;
//当前线程需要下载的文件块
private RandomAccessFile currentPart;
//定义该线程已经下载的字节数
public int length;
public DownThread(int startPos,int currentPartSize,RandomAccessFile currentPart) {
this.startPos=startPos;
this.currentPartSize=currentPartSize;
this.currentPart=currentPart;

}

public void run(){
try{
URL url =new URL(path);
HttpsURLConnection conn=(HttpsURLConnection)url.openConnection();
conn.setConnectTimeout(5 *1000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept",
"image/gif,image/jpeg,iamge/pjpg,image/pjpeg,"
+"application/x-shockware-flash,application/xaml+xml"
+"application/vnd.ms-xpsdocument,application/x-ms-xbap"
+"application/x-ms-application,application/vnd.ms-excel"
+"application/vnd.ms-powerpoint,application/msword,*/*");

conn.setRequestProperty("Accept-Language", "zh-CN");
conn.setRequestProperty("Charset", "UTF-8");
InputStream isStream=conn.getInputStream();
//跳过startPos个字节,表明该线程只下载自己负责的把部分文件
isStream.skip(this.startPos);
byte [] buffer=new byte[1024];
int hasRead=0;
//读取网络数据,并且写入本地文件
while(length<currentPartSize && (hasRead = isStream.read(buffer))!=-1);
{
currentPart.write(buffer, 0, hasRead);
//累计该线程下载的总大小
length+=hasRead;
}

currentPart.close();
isStream.close();


}catch(Exception e){
e.printStackTrace();
}
}
}
}



package com.zou;
public class MutiThreadDown{
public static void main(String[] args) throws Exception{
//初始化DownLoad对象
final DownUtil downUtil =new DownUtil("http://www.crazyit.org/"+
"attachments/month_1403/14030202355ff6cc9a4fbf6f14a.png",
"ios.png", 4);
//开始下载

downUtil.download();
new Thread (()-> {
while(downUtil.GetCompleteRate()<1)
{
System.out.println("已完成"+downUtil.GetCompleteRate());
try{
Thread.sleep(1000);
}catch(Exception ex){}
}
}).start();

}
}

(1)上面程序还用到URLConnection和HttpURLConnection对象,其中前者表示应用程序和URL之间的通信连接,后者表示URL和HTTP之间的连接。程序可以通过URLConnection实例向该URL发送请求,读取URL引用的资源。
(2)Java8新增了一个URLPermission,用于管理HttpURLConnection的权限问题,如果在HttpURLConnection安装了安全管理器,通过该对象打开连接时就需要先获得权限。

(3)通过创建一个和URL的连接,并发送请求,,读取此URL引用的资源需要如下步骤:
通过调用URL对象的openConnection()方法来创建URLConnection对象
设置URLConnection的参数和普通请求属性
如果只是发送GET方式请求,则使用connect()方法建立和远程资源之间的实际连接即可;如果需要发送POST方式请求,则需要获取URLConnection实例对应的输出流来发送请求参数。
(4)远程资源变为可用,程序可以访问远程资源的头字段或通过获取输入流读取远程资源的数据。

程序实例:下面程序示范了如何向web站点发送GET请求、POST请求,并从web站点获得响应:

import java.io.*;
import java.net.*;
import java.util.*;
public class GetPostTest
{

/**
* 向指定URL发送GET方法的请求
* @param url 发送请求的URL
* @param param 请求参数,格式满足name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/

public static String sendGet(String url , String param)
{
String result = "";
String urlName = url + "?" + param;
try
{
URL realUrl = new URL(urlName);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent"
, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
// 建立实际的连接
conn.connect();
// 获取所有响应头字段
Map<String, List<String>> map = conn.getHeaderFields();
// 遍历所有的响应头字段
for (String key : map.keySet())
{
System.out.println(key + "--->" + map.get(key));
}
try(
// 定义BufferedReader输入流来读取URL的响应
BufferedReader in = new BufferedReader(
new InputStreamReader(conn.getInputStream() , "utf-8")))
{
String line;
while ((line = in.readLine())!= null)
{
result += "\n" + line;
}
}
}
catch(Exception e)
{
System.out.println("发送GET请求出现异常!" + e);
e.printStackTrace();
}
return result;
}
/**
* 向指定URL发送POST方法的请求
* @param url 发送请求的URL
* @param param 请求参数,格式应该满足name1=value1&name2=value2的形式。
* @return URL所代表远程资源的响应
*/

public static String sendPost(String url , String param)
{
String result = "";
try
{
URL realUrl = new URL(url);
// 打开和URL之间的连接
URLConnection conn = realUrl.openConnection();
// 设置通用的请求属性
conn.setRequestProperty("accept", "*/*");
conn.setRequestProperty("connection", "Keep-Alive");
conn.setRequestProperty("user-agent",
"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
// 发送POST请求必须设置如下两行
conn.setDoOutput(true);
conn.setDoInput(true);
try(
// 获取URLConnection对象对应的输出流
PrintWriter out = new PrintWriter(conn.getOutputStream()))
{
// 发送请求参数
out.print(param);
// flush输出流的缓冲
out.flush();
}
try(
// 定义BufferedReader输入流来读取URL的响应
BufferedReader in = new BufferedReader(new InputStreamReader
(conn.getInputStream() , "utf-8")))
{
String line;
while ((line = in.readLine())!= null)
{
result += "\n" + line;
}
}
}
catch(Exception e)
{
System.out.println("发送POST请求出现异常!" + e);
e.printStackTrace();
}
return result;
}
// 提供主方法,测试发送GET请求和POST请求
public static void main(String args[])
{
// 发送GET请求
String s = GetPostTest.sendGet("http://localhost:8080/Scuse/register.jsp"
, null);
System.out.println(s);
// 发送POST请求
String s1 = GetPostTest.sendPost("http://localhost:8080/Scuse/login.jsp"
, "name=crazyit.org&pass=leegang");
System.out.println(s1);
}
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
© 2014-2019 ITdaan.com 粤ICP备14056181号