概述
網(wǎng)絡(luò)編程是指編寫運(yùn)行在多個(gè)設(shè)備(計(jì)算機(jī))的程序,這些設(shè)備都通過網(wǎng)絡(luò)連接起來。
java.net 包中 J2SE 的 API 包含有類和接口,它們提供低層次的通信細(xì)節(jié)。你可以直接使用這些類和接口,來專注于解決問題,而不用關(guān)注通信細(xì)節(jié)。
Java支持下列常用網(wǎng)絡(luò)操作:
- InetAddress:用于表示網(wǎng)絡(luò)上的硬件資源,即 IP 地址;
- URL:統(tǒng)一資源定位符;
- Socket:使用 TCP 協(xié)議實(shí)現(xiàn)網(wǎng)絡(luò)通信。TCP 是傳輸控制協(xié)議的縮寫,它保障了兩個(gè)應(yīng)用程序之間的可靠通信。通常用于互聯(lián)網(wǎng)協(xié)議,被稱 TCP / IP。
- Datagram:使用 UDP 協(xié)議實(shí)現(xiàn)網(wǎng)絡(luò)通信。UDP 是用戶數(shù)據(jù)報(bào)協(xié)議的縮寫,一個(gè)無連接的協(xié)議。提供了應(yīng)用程序之間要發(fā)送的數(shù)據(jù)的數(shù)據(jù)包。
下面我們分別來學(xué)習(xí):
InetAddress
java.net.InetAddress類是Java對(duì)IP地址(包括IPv4和IPv6)的高層表示。大多數(shù)其他網(wǎng)絡(luò)類都要用到這個(gè)類,包括Socket,ServerSocket,URL,DatagramSocket,DatagramPacket等。一般地講,它包括一個(gè)主機(jī)名和一個(gè)IP地址。
主機(jī)名到 IP 地址的解析 通過使用本地機(jī)器配置信息和網(wǎng)絡(luò)命名服務(wù)(如域名系統(tǒng)(Domain Name System,DNS)和網(wǎng)絡(luò)信息服務(wù)(Network Information Service,NIS))來實(shí)現(xiàn)。
反向名稱解析 意味著對(duì)于任何 IP 地址,都返回與 IP 地址關(guān)聯(lián)的主機(jī)。
InetAddress 類提供將主機(jī)名解析為其 IP 地址(或反之)的方法。
-
static InetAddress[] getAllByName(String host)
在給定主機(jī)名的情況下,根據(jù)系統(tǒng)上配置的名稱服務(wù)返回所有的 IP 地址。 -
static InetAddress getByAddress(byte[] addr)
在給定原始 IP 地址的情況下,返回 InetAddress 對(duì)象。 -
static InetAddress getByAddress(String host, byte[] addr)
根據(jù)提供的主機(jī)名和 IP 地址創(chuàng)建 InetAddress。 -
static InetAddress getByName(String host)
在給定主機(jī)名的情況下確定主機(jī)的 IP 地址。 -
String getCanonicalHostName()
獲取此 IP 地址的完全限定域名。 -
String getHostAddress()
返回 IP 地址字符串,比如192.168.1.1 -
String getHostName()
獲取此 IP 地址的主機(jī)名。比如 www.baidu.com -
static InetAddress getLocalHost()
返回本地主機(jī)。 -
boolean isReachable(int timeout)
測(cè)試是否可以達(dá)到該地址。
URL
URL(Uniform Resource Locator)中文名為統(tǒng)一資源定位符,有時(shí)也被俗稱為網(wǎng)頁(yè)地址。表示為互聯(lián)網(wǎng)上的資源,如網(wǎng)頁(yè)或者FTP地址。
URL可以分為如下幾個(gè)部分:
protocol://host:port/path?query#fragment
實(shí)例:http://www.runoob.com/index.html?language=cn#j2se
URL 各部分解析:
protocol(協(xié)議):可以是 http、https、ftp 、file等,上面例子是http
host(主機(jī)):www.runoob.com
port(端口號(hào)):80 ,以上URL實(shí)例并未指定端口,因?yàn)?HTTP 協(xié)議默認(rèn)的端口號(hào)為 80。
path(文件路徑):/index.html
query(請(qǐng)求參數(shù)):language=cn
fragment(定位位置):j2se,定位到網(wǎng)頁(yè)中 id 屬性為 j2se 的 HTML 元素位置 。
URL 類方法
在java.net包中定義了URL類,該類用來處理有關(guān)URL的內(nèi)容。對(duì)于URL類的創(chuàng)建和使用,下面分別進(jìn)行介紹。
java.net.URL提供了豐富的URL構(gòu)建方式,并可以通過java.net.URL來獲取資源。

URL類中包含了很多方法用于訪問URL的各個(gè)部分,具體方法及描述如下:


以上實(shí)例演示了使用java.net的URL類獲取URL的各個(gè)部分參數(shù):
URLDemo.java
import java.net.*;
import java.io.*;
public class URLDemo
{
public static void main(String [] args)
{
try
{
URL url = new URL("http://www.runoob.com/index.html?language=cn#j2se");
System.out.println("URL 為:" + url.toString());
System.out.println("協(xié)議為:" + url.getProtocol());
System.out.println("驗(yàn)證信息:" + url.getAuthority());
System.out.println("文件名及請(qǐng)求參數(shù):" + url.getFile());
System.out.println("主機(jī)名:" + url.getHost());
System.out.println("路徑:" + url.getPath());
System.out.println("端口:" + url.getPort());
System.out.println("默認(rèn)端口:" + url.getDefaultPort());
System.out.println("請(qǐng)求參數(shù):" + url.getQuery());
System.out.println("定位位置:" + url.getRef());
}catch(IOException e)
{
e.printStackTrace();
}
}
}
結(jié)果如下:
URL 為:http://www.runoob.com/index.html?language=cn#j2se
協(xié)議為:http
驗(yàn)證信息:www.runoob.com
文件名及請(qǐng)求參數(shù):/index.html?language=cn
主機(jī)名:www.runoob.com
路徑:/index.html
端口:-1
默認(rèn)端口:80
請(qǐng)求參數(shù):language=cn
定位位置:j2se
URLConnections 類方法
openConnection() 返回一個(gè) java.net.URLConnection。
例如:
- 如果你連接HTTP協(xié)議的URL, openConnection() 方法返回 HttpURLConnection 對(duì)象。
- 如果你連接的URL為一個(gè) JAR 文件, openConnection() 方法將返回 JarURLConnection 對(duì)象。
URLConnection 方法列表如下:


以下實(shí)例中URL采用了HTTP 協(xié)議。 openConnection 返回HttpURLConnection對(duì)象,并通過該對(duì)象得到URL的輸入流,讀取字節(jié)流數(shù)據(jù):
public static void main(String[] args) throws IOException {
URL url = new URL("http://www.baidu.com");
/* 字節(jié)流 */
InputStream is = url.openStream();
/* 字符流 */
InputStreamReader isr = new InputStreamReader(is, "utf-8");
/* 提供緩存功能 */
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
br.close();
}
Socket 編程
套接字使用TCP提供了兩臺(tái)計(jì)算機(jī)之間的通信機(jī)制。 客戶端程序創(chuàng)建一個(gè)套接字,并嘗試連接服務(wù)器的套接字。
當(dāng)連接建立時(shí),服務(wù)器會(huì)創(chuàng)建一個(gè) Socket 對(duì)象??蛻舳撕头?wù)器現(xiàn)在可以通過對(duì) Socket 對(duì)象的寫入和讀取來進(jìn)行通信。
java.net.Socket 類代表一個(gè)套接字,并且 java.net.ServerSocket 類為服務(wù)器程序提供了一種來監(jiān)聽客戶端,并與他們建立連接的機(jī)制。
以下步驟在兩臺(tái)計(jì)算機(jī)之間使用套接字建立TCP連接時(shí)會(huì)出現(xiàn):
服務(wù)器實(shí)例化一個(gè) ServerSocket 對(duì)象,表示通過服務(wù)器上的端口通信。
服務(wù)器調(diào)用 ServerSocket 類的 accept() 方法,該方法將一直等待,直到客戶端連接到服務(wù)器上給定的端口。
服務(wù)器正在等待時(shí),一個(gè)客戶端實(shí)例化一個(gè) Socket 對(duì)象,指定服務(wù)器名稱和端口號(hào)來請(qǐng)求連接。
Socket 類的構(gòu)造函數(shù)試圖將客戶端連接到指定的服務(wù)器和端口號(hào)。如果通信被建立,則在客戶端創(chuàng)建一個(gè) Socket 對(duì)象能夠與服務(wù)器進(jìn)行通信。
在服務(wù)器端,accept() 方法返回服務(wù)器上一個(gè)新的 socket 引用,該 socket 連接到客戶端的 socket。
連接建立后,通過使用 I/O 流在進(jìn)行通信,每一個(gè)socket都有一個(gè)輸出流和一個(gè)輸入流,客戶端的輸出流連接到服務(wù)器端的輸入流,而客戶端的輸入流連接到服務(wù)器端的輸出流。
TCP 是一個(gè)全雙工的通信協(xié)議,因此數(shù)據(jù)可以通過兩個(gè)數(shù)據(jù)流在同一時(shí)間發(fā)送。以下是一些類提供的一套完整的有用的方法來實(shí)現(xiàn) socket。
ServerSocket 類的方法
服務(wù)器應(yīng)用程序通過使用 java.net.ServerSocket 類以獲取一個(gè)端口,并且偵聽客戶端請(qǐng)求。
ServerSocket 類有四個(gè)構(gòu)造方法:

如果 ServerSocket 構(gòu)造方法沒有拋出異常,就意味著你的應(yīng)用程序已經(jīng)成功綁定到指定的端口,并且偵聽客戶端請(qǐng)求。
這里有一些 ServerSocket 類的常用方法:

Socket 類的方法
java.net.Socket 類代表客戶端和服務(wù)器都用來互相溝通的套接字。客戶端要獲取一個(gè) Socket 對(duì)象通過實(shí)例化 ,而服務(wù)器獲得一個(gè) Socket 對(duì)象則通過 accept() 方法的返回值。
Socket 類有五個(gè)構(gòu)造方法:

當(dāng) Socket 構(gòu)造方法返回,并沒有簡(jiǎn)單的實(shí)例化了一個(gè) Socket 對(duì)象,它實(shí)際上會(huì)嘗試連接到指定的服務(wù)器和端口。
下面列出了一些感興趣的方法,注意客戶端和服務(wù)器端都有一個(gè) Socket 對(duì)象,所以無論客戶端還是服務(wù)端都能夠調(diào)用這些方法:

Socket 客戶端實(shí)例
如下的 GreetingClient 是一個(gè)客戶端程序,該程序通過 socket 連接到服務(wù)器并發(fā)送一個(gè)請(qǐng)求,然后等待一個(gè)響應(yīng)。
GreetingClient.java
import java.net.*;
import java.io.*;
public class GreetingClient
{
public static void main(String [] args)
{
String serverName = args[0];
int port = Integer.parseInt(args[1]);
try
{
System.out.println("連接到主機(jī):" + serverName + " ,端口號(hào):" + port);
Socket client = new Socket(serverName, port);
System.out.println("遠(yuǎn)程主機(jī)地址:" + client.getRemoteSocketAddress());
OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.writeUTF("Hello from " + client.getLocalSocketAddress());
InputStream inFromServer = client.getInputStream();
DataInputStream in = new DataInputStream(inFromServer);
System.out.println("服務(wù)器響應(yīng): " + in.readUTF());
client.close();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
Socket 服務(wù)端實(shí)例
如下的GreetingServer 程序是一個(gè)服務(wù)器端應(yīng)用程序,使用 Socket 來監(jiān)聽一個(gè)指定的端口。
GreetingServer.java
import java.net.*;
import java.io.*;
public class GreetingServer extends Thread
{
private ServerSocket serverSocket;
public GreetingServer(int port) throws IOException
{
serverSocket = new ServerSocket(port);
serverSocket.setSoTimeout(10000);
}
public void run()
{
while(true)
{
try
{
System.out.println("等待遠(yuǎn)程連接,端口號(hào)為:" + serverSocket.getLocalPort() + "...");
Socket server = serverSocket.accept();
System.out.println("遠(yuǎn)程主機(jī)地址:" + server.getRemoteSocketAddress());
DataInputStream in = new DataInputStream(server.getInputStream());
System.out.println(in.readUTF());
DataOutputStream out = new DataOutputStream(server.getOutputStream());
out.writeUTF("謝謝連接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
server.close();
}catch(SocketTimeoutException s)
{
System.out.println("Socket timed out!");
break;
}catch(IOException e)
{
e.printStackTrace();
break;
}
}
}
public static void main(String [] args)
{
int port = Integer.parseInt(args[0]);
try
{
Thread t = new GreetingServer(port);
t.run();
}catch(IOException e)
{
e.printStackTrace();
}
}
}
編譯以上兩個(gè) java 文件代碼,并執(zhí)行以下命令來啟動(dòng)服務(wù),使用端口號(hào)為 6066:
$ javac GreetingServer.java
$ java GreetingServer 6066
等待遠(yuǎn)程連接,端口號(hào)為:6066...
新開一個(gè)命令窗口,執(zhí)行以上命令來開啟客戶端:
$ javac GreetingClient.java
$ java GreetingClient localhost 6066
連接到主機(jī):localhost ,端口號(hào):6066
遠(yuǎn)程主機(jī)地址:localhost/127.0.0.1:6066
服務(wù)器響應(yīng): 謝謝連接我:/127.0.0.1:6066
Goodbye!
Datagram
UDP和TCP的特點(diǎn)
用戶數(shù)據(jù)報(bào)協(xié)議 UDP(User Datagram Protocol)是無連接的,盡最大可能交付,沒有擁塞控制,面向報(bào)文(對(duì)于應(yīng)用程序傳下來的報(bào)文不合并也不拆分,只是添加 UDP 首部),支持一對(duì)一、一對(duì)多、多對(duì)一和多對(duì)多的交互通信,效率高但不可靠。事實(shí)上,可以用UDP實(shí)現(xiàn)一個(gè)可靠的文件傳輸協(xié)議,而且很多人確實(shí)是這樣做的:網(wǎng)絡(luò)文件系統(tǒng),簡(jiǎn)單FTP都使用了UDP協(xié)議。在這些協(xié)議中由應(yīng)用程序來負(fù)責(zé)可靠性。
傳輸控制協(xié)議 TCP(Transmission Control Protocol)是面向連接的,提供可靠交付,有流量控制,擁塞控制,提供全雙工通信,面向字節(jié)流(把應(yīng)用層傳下來的報(bào)文看成字節(jié)流,把字節(jié)流組織成大小不等的數(shù)據(jù)塊),每一條 TCP 連接只能是點(diǎn)對(duì)點(diǎn)的(一對(duì)一),效率低但安全可靠。
java中對(duì)UDP編程的支持
java中的UDP實(shí)現(xiàn)分為兩個(gè)類:DatagramPacket和 DatagramSocket。DatagramPacket類將數(shù)據(jù)字節(jié)填充到UDP包中,這稱為數(shù)據(jù)報(bào)。 DatagramSocket來發(fā)送這個(gè)包。要接受數(shù)據(jù),可以從DatagramSocket中接受一個(gè) DatagramPack對(duì)象,然后從該包中讀取數(shù)據(jù)的內(nèi)容。
這種職責(zé)的劃分與TCP使用的Socket和ServerSocket有所不同。首先,UDP沒有兩臺(tái)主機(jī)間唯一連接的概念,它不需要知道對(duì)方是哪個(gè)遠(yuǎn)程主機(jī)。它可以從一個(gè)端口往多個(gè)主機(jī)發(fā)送信息,但是TCP是無法做到的。其次,TCP socket把網(wǎng)絡(luò)連接看作是流:通過從Socket得到的輸入和輸出流來收發(fā)數(shù)據(jù)。UDP不支持這一點(diǎn),你處理總是單個(gè)數(shù)據(jù)包。填充在一個(gè)數(shù)據(jù)報(bào)中的所有數(shù)據(jù)會(huì)以包的形式進(jìn)行發(fā)送,這些數(shù)據(jù)要么作為一個(gè)組要么全部接收,要么全部丟棄。一個(gè)包不一定與下一個(gè)包相關(guān)。給定兩個(gè)包,沒有辦法知道哪個(gè)先發(fā)哪個(gè)后發(fā)。對(duì)于流來說,必須提供數(shù)據(jù)的有序隊(duì)列,與之不同,數(shù)據(jù)報(bào)會(huì)盡可能快的蜂擁到接收方。
DatagramSocket類
java.net.DatagramSocket 此類表示用來發(fā)送和接收數(shù)據(jù)報(bào)包的套接字
該類主要有下列構(gòu)造方法:
- DatagramSocket() 構(gòu)造數(shù)據(jù)報(bào)套接字并將其綁定到本地主機(jī)上任何可用的端口。
- DatagramSocket(int port, InetAddress laddr) 創(chuàng)建數(shù)據(jù)報(bào)套接字,將其綁定到指定的地址。
常用的方法:
- send(DatagramPacket p) 從此套接字發(fā)送數(shù)據(jù)報(bào)包。
- receive(DatagramPacket p)從此套接字接收數(shù)據(jù)報(bào)包。
- close() 關(guān)閉此數(shù)據(jù)報(bào)套接字。
DatagramPacket類
此類表示數(shù)據(jù)報(bào)包。
構(gòu)造方法(因?yàn)閁DP是無連接的,所以在用于發(fā)送的數(shù)據(jù)包中附加目的地址,而用于接收的數(shù)據(jù)包不用加地址信息):
-
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
構(gòu)造數(shù)據(jù)報(bào)包,用來將長(zhǎng)度為 length 偏移量為 offset 的包發(fā)送到指定主機(jī)上的指定端口號(hào)。 -
DatagramPacket(byte[] buf, int length, InetAddress address, int port)
構(gòu)造數(shù)據(jù)報(bào)包,用來將長(zhǎng)度為 length 的包發(fā)送到指定主機(jī)上的指定端口號(hào)。 -
DatagramPacket(byte[] buf, int length)
構(gòu)造 DatagramPacket,用來接收長(zhǎng)度為 length 的數(shù)據(jù)包。
DatagramSocket 客戶端實(shí)例
UDPClient.java
public class UDPClient {
public static void main(String[] args) {
try {
//1.創(chuàng)建數(shù)據(jù)報(bào)套接字
DatagramSocket datagramSocket = new DatagramSocket(6666);
//2.創(chuàng)建數(shù)據(jù)報(bào)包用于封裝數(shù)據(jù)和目標(biāo)地址
String str="hello world!";
byte[] content = str.getBytes();//將字符串轉(zhuǎn)換為字節(jié)的數(shù)組
DatagramPacket datagramPacket = new DatagramPacket(content, content.length,InetAddress.getLocalHost(), 9999);
//3.調(diào)用send方法進(jìn)行發(fā)送數(shù)據(jù)
datagramSocket.send(datagramPacket);
//4.釋放資源
datagramSocket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
DatagramSocket 服務(wù)端實(shí)例
UDPServer.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
* DatagramSocket(int port)
* DatagramPacket(byte[] buf, int length) 構(gòu)造 DatagramPacket,用來接收長(zhǎng)度為 length 的數(shù)據(jù)包。
* DataPacket類中方法:
* getData() 返回?cái)?shù)據(jù)緩沖區(qū)。
* getLength()返回將要發(fā)送或接收到的數(shù)據(jù)的長(zhǎng)度。
* getPort() 返回某臺(tái)遠(yuǎn)程主機(jī)的端口號(hào),此數(shù)據(jù)報(bào)將要發(fā)往該主機(jī)或者是從該主機(jī)接收到的
* getAddress()返回某臺(tái)機(jī)器的 IP 地址,此數(shù)據(jù)報(bào)將要發(fā)往該機(jī)器或者是從該機(jī)器接收到的。
*
*/
public class UDPServer {
public static void main(String[] args) {
try {
//1.創(chuàng)建數(shù)據(jù)報(bào)套接字
DatagramSocket socket = new DatagramSocket(9999);
//2.創(chuàng)建一個(gè)數(shù)據(jù)報(bào)包
byte[] content = new byte[1024];
DatagramPacket datagramPacket = new DatagramPacket(content,content.length);
//3.調(diào)用receive方法接收數(shù)據(jù)包
socket.receive(datagramPacket);
//4.從數(shù)據(jù)報(bào)包中獲取數(shù)據(jù)
byte[] data= datagramPacket.getData();//獲取數(shù)據(jù)報(bào)包中的數(shù)據(jù)
int length = datagramPacket.getLength();//
InetAddress ip = datagramPacket.getAddress();
int port = datagramPacket.getPort();
System.out.println("內(nèi)容:"+new String(data,0,length));
System.out.println("數(shù)據(jù)長(zhǎng)度:"+length);
System.out.println("發(fā)送方的IP地址:"+ip);
System.out.println("發(fā)送方的端口號(hào):"+port);
//5.釋放資源
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
利用UDP實(shí)現(xiàn)聊天功能
UdpChatClient.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 利用UDP實(shí)現(xiàn)聊天功能
* @author Administrator
*
*/
public class UdpChatClient {
public static void main(String[] args) {
System.out.println("---------顧客---------");
try {
//1.創(chuàng)建數(shù)據(jù)報(bào)套接字
DatagramSocket socket = new DatagramSocket(6666);
Scanner input = new Scanner(System.in);
while(true){
//2.獲取用戶輸入
String message = input.next();
byte[] bs = message.getBytes();
//3.創(chuàng)建數(shù)據(jù)報(bào)包
DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),8888);
//4.發(fā)送數(shù)據(jù)
socket.send(packet);
//接收數(shù)據(jù)
byte[] bs2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
socket.receive(packet2);//接收數(shù)據(jù)
byte[] serverMesage = packet2.getData();
String str=new String(serverMesage,0,serverMesage.length);
System.out.println("客服說:"+str);
if(message.equals("bye")){
break;
}
}
//釋放資源
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UdpChatServer.java
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
* 利用UDP實(shí)現(xiàn)聊天功能
* @author Administrator
*
*/
public class UdpChatServer {
public static void main(String[] args) {
System.out.println("---------客服---------");
try {
//1.創(chuàng)建數(shù)據(jù)報(bào)套接字
DatagramSocket socket = new DatagramSocket(8888);
Scanner input = new Scanner(System.in);
while(true){
//接收數(shù)據(jù)
byte[] bs2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
socket.receive(packet2);//接收數(shù)據(jù)
byte[] serverMesage = packet2.getData();
String str=new String(serverMesage,0,serverMesage.length);
System.out.println("顧客說:"+str);
//2.獲取用戶輸入
String message = input.next();
byte[] bs = message.getBytes();
//3.創(chuàng)建數(shù)據(jù)報(bào)包
DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),6666);
//4.發(fā)送數(shù)據(jù)
socket.send(packet);
if(message.equals("bye")){
break;
}
}
//釋放資源
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}