- 网络编程
和多线程一样,网络编程在实际编码中并不会太多的写到,但是这块东西还是比较重要的。就在前几天去一家大公司面试,至于公司的名字我就不说了(我已经通过了但是我最后选择了别家),就问到了好多的关于socket的东西,好像tomcat里面也用到了socket,所以这里做一次整理。这也是JavaSe中最后一块,整理完socket以后开始整理数据库和JDBC。
- 几个比较重要的网络术语
2、端口:端口是一个软件抽象的概念。如果把Ip地址看作是一个电话号码的话,端口就相当于分机号。进程一定要和一个端口建立绑定监听关系。端口号占两个字节。
3、协议:通讯双方为了完成预先制定好的功能而达成的约定。说白了就是网络运输中的一种约束和规定。
4、TCP/IP协议。
IP协议:InternetProtocol协议又称互联网协议,是支持网间互联的数据报协议,它提供网间连接的完善功能,包括IP数据报规定互联网网络范围内的地址格式。
TCP协议:传输控制协议,它规定一种可靠的数据信息传递服务。关于上面这2种协议,他们是经常放在一起的,一般也叫TCP/IP协议,可以这么理解这2种协议:IP协议就是来决定2个机子的地址,他们之间可以相互发送和接受数据,TCP协议会为他们建立一个连接,这样子2者互补,就形成了一个整体,用来传送和接受数据。
5、TCP/IP网络七层模型:物理层Physical(硬件)、 数据链路层DataLink(二进制) 、网络层Network(IP协议:寻址和路由)、传输层Transport(TCP协议,UDP协议) 、会话层Session(端口)、表示层Presentation、应用层Application(HTTP,FTP,TELET,SMTP,POPS,DNS)。值得注意的是:层与层之间是单向依赖关系。对等层之间会有一条虚连接。Java中的网络编程就是针对传输层编程。网络通信的本质是进程间通信。
6、Tcp协议和UDP协议:
TCP:开销大,用于可靠性要求高的场合。TCP的过程相当于打电话的过程。面向连接,可靠,低效。TCP协议被称为一种端对端协议,当一台计算机需要和另一台远程计算机连接时,TCP协议会让他们建立一个连接,用于发送和接受数据的虚拟链路。TCP使用了重发机制,个人觉得这点是很好的,重发机制就是说2个实体在相互交互的过程中,要是发送数据的那一段没有接受到接受数据那一段发送到的确认信息后,就会重新在发一次。也真是因为这种协议,即使在Internet暂时出现堵塞的情况下,TCP也能保证通信的可靠。
UDP:用在对实时性要求比较高的场合。UDP的过程相当于写信的过程。无连接,不可靠,效率高。UDP协议是一种不可靠的网络协议,他在通信实体的2端各建立一个socket,但是这2个socket之间并没有虚拟链路,这2个socket只是发送,接受数据报的对象。Java提供了DatagramSocket对象作为基于UDP协议的socket,使用datapramPacket代表DatagramSocket发送和接受的数据报。
关于上面2种协议,在实际的编码过程中,第一种使用的是比较多的。我们这里的整理也是主要是关于第一种的,第2中的我会贴出相关的代码,作为了解好了。
- Java的基本网络支持
以下代码使用Java.net下常用的类,演示下这些类的常用用法。
import java.net.*; public class InetAddressTest { public static void main(String[] args) throws Exception { // 根据主机名来获取对应的InetAddress实例 InetAddress ip = InetAddress.getByName("127.0.0.1"); // 判断是否可达 System.out.println("是否可达:" + 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()); // 将application/x-www-form-urlencoded字符串,转换成普通字符串 // URLDecoder(解码) URLEncoder(编码) String keyWord = URLDecoder.decode("%C1%D6%BF%CF%B9%AB%D4%B0", "GBK"); System.out.println(keyWord); // 将普通字符串转换成,application/x-www-form-urlencoded字符串 String urlStr = URLEncoder.encode("林肯公园", "GBK"); System.out.println(urlStr); } }
import java.io.InputStream; import java.io.RandomAccessFile; import java.net.*; /** * * @version 1L * @author LinkinPark * @since 2015-2-11 * @motto 梦似烟花心似水,同学少年不言情 * @desc ^ 多线程下载的核心代码 */ public class DownUtil { // 定义下载资源的路径 private String path; // 指定所下载的文件的保存位置 private String targetFile; // 定义需要使用多少线程下载资源 private int threadNum; // 定义下载的线程对象 private DownThread[] threads; // 定义下载的文件的总大小 private int fileSize; 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); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, " + "application/x-shockwave-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; } @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setConnectTimeout(5 * 1000); conn.setRequestMethod("GET"); conn.setRequestProperty("Accept", "image/gif, image/jpeg, image/pjpeg, image/pjpeg, " + "application/x-shockwave-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 inStream = conn.getInputStream(); // 跳过startPos个字节,表明该线程只下载自己负责哪部分文件。 inStream.skip(this.startPos); byte[] buffer = new byte[1024]; int hasRead = 0; // 读取网络数据,并写入本地文件 while (length < currentPartSize && (hasRead = inStream.read(buffer)) != -1) { currentPart.write(buffer, 0, hasRead); // 累计该线程下载的总大小 length += hasRead; } currentPart.close(); inStream.close(); } catch (Exception e) { e.printStackTrace(); } } } }
import java.io.*; import java.net.*; import java.util.*; import org.apache.commons.lang.StringUtils; 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 = ""; if (StringUtils.isNotBlank(param)) { urlName = url + "?" + param; } else { urlName = url; } 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)); } // 定义BufferedReader输入流来读取URL的响应 BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); String line; while ((line = in.readLine()) != null) { result += "\n" + line; } } finally { if (in != null) { in.close(); } } } 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); // 获取URLConnection对象对应的输出流 PrintWriter out = null; // 定义BufferedReader输入流来读取URL的响应 BufferedReader in = null; try { out = new PrintWriter(conn.getOutputStream()); // 发送请求参数 out.print(param); // flush输出流的缓冲 out.flush(); } finally { if (out != null) { out.close(); } } try { in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8")); String line; while ((line = in.readLine()) != null) { result += "\n" + line; } } finally { if (in != null) { in.close(); } } } 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/tzTaskManage/login.jsp", null); System.out.println(s); // 发送POST请求 //String s1 = GetPostTest.sendPost("http://localhost:8080/tzTaskManage/login.jsp", "j_username=linyihua&j_password=1qaz2wsx"); //System.out.println(s1); } }