首頁 > Java > java教程 > 主體

Java之網路程式設計的使用詳解

零下一度
發布: 2017-06-30 09:57:24
原創
1737 人瀏覽過
 
關鍵字:IP位址、、連接埠、UDP、DatagramPacket類別、DatagramSocket類別、TCP、ServerSocket類別、Socket類別、檔案上傳
一、基本概念
       1、基本概念
      ①MAC:MAC(Media Access Control或Medium Access Control)位址,意為媒體存取控制,或稱為實體位址、硬體位址,用來定義網路設備的位置。在OSI模型中,第三層網路層負責IP位址 ,第二層資料鏈結層則負責 MAC位址。因此一個主機會有一個MAC位址,而每個網路位址會有一個專屬於它的IP位址。
 
      ②IP位址:是指網際網路通訊協定位址(Internet Protocol Address,又翻譯為網路協定位址),是IP Address的縮寫。 IP位址是IP協定提供的一種統一的位址格式,它為網際網路上的每一個網路和每一台主機分配一個邏輯位址,以此來封鎖實體位址的差異。目前還有些ip代理軟​​體,但大部分都收費。
      
 
 
        ③連接埠:可視為裝置與外部通訊溝通的出口。
        連接埠號碼是用兩個位元組(16位元的二進位數)表示,它的取值範圍是0~65 535 ,其中0~1023之間的連接埠號碼用於以下知名的網路服務和應用,用戶的普通應用程式需要使用1024以上的連接埠號碼。連接埠分為實體連接埠和邏輯連接埠(軟體應用程式的數位識別)。

        ④TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)協定屬於傳輸層協定。

        TCP協定是連結導向的通訊協議,提供IP環境下的資料可靠傳輸,它提供的服務包括資料流傳送、可靠性、有效流控、全雙工操作和多路復用。透過面向連接、端到端和可靠的資料包發送。通俗說,它是事先為所發送的資料開闢出連接好的通道,然後再進行資料發送;

         ⑤UDP是無線通訊協議,不為IP提供可靠性、流控或錯誤恢復功能。

 

         2、常見InetAddress類別的常用方法範例:
 1 public class Example1 {
 2     public static void main(String[] args) throws Exception{
 3         //创建一个表示本地主机的InetAddress对象
 4         InetAddress localAddress = InetAddress.getLocalHost(); 
 5         //获得指定主机的InetAddress对象
 6         InetAddress remoteAddress = InetAddress.getByName("www.itcast.cn");
 7         //得到IP地址的主机名。
 8         System.out.println("本机的IP地址:"+localAddress.getHostName());
 9         //获得字符串格式的原始IP地址
10         System.out.println("itcast的IP地址:"+remoteAddress.getHostAddress());
11         //判断指定的时间内地址是否可以到达
12         System.out.println("3秒是否可达:"+remoteAddress.isReachable(3000));
13        
14         System.out.println("itcast的主机名为:"+remoteAddress.getHostName());
15     }
16 }
登入後複製

執行結果:

本机的IP地址:wrt.local
itcast的IP地址:123.57.45.99
3秒是否可达:false
itcast的主机名为:www.itcast.cn
登入後複製

 

 二、UDP通訊

      1、DatagramPacket

      此類別類似於貨櫃,在建立傳送端和接收端的DatagramPacket物件時,使用的建構方法有所不同,接收端的建構方法只需要接收一個字節數組來存放接收到的數據,而發送端的構造方法不但要接收存放了發送數據的字節數組還需要製定發送端IP地址和端口號。

      DatagramPacket建構方法:

##卷和數據大小。

       ②DatagramPacket(byte[] buf,int length,InetAddress addr,int port)

       用於傳送端, 建立DatagramPacket物件時,指定了封裝資料的位元組陣列、資料大小、位元組數組、資料大小封包的目標IP位址(addr)以及連接埠號碼(port)。

       ③DatagramPacket(byte[] buf,int offset,int length)

        用於接收端,建立DatagramPacket物件時,指定了封裝資料的位元組起始組、資料大小,以及為存取端,在建立DatagramPacket物件時,指定了封裝資料的位元組起始組、資料大小,以及為位元組數位置。 offset 參數用於指定接收的資料在放入buf緩衝數組時是從offset處開始的。

        ④DatagramPacket(byte[] buf,int offset,int length,InetAddress addr,int port)

       用於傳送端, 資料大小、資料包的目標IP位址(addr)以及連接埠號碼(port)。 offset 參數用於指定發送資料的偏移量為offset,即從offset位置開始傳送資料。

TCP/IP 網路模式

 

應用層

#如HTTP、FTP、DNS

##傳輸層

如TCP、UDP

#網路層

如IP、ICMP、IGMP

鏈鋸層

如驅動程式、介面

                                                                                              DatagramPacket類中的常用方法方法聲明功能描述InetAddress  getAddress()該方法用於返回發送端或接收端的IP位址,如果發送端的DatagramPacket對象,就返回接收端的IP位址,反之,就傳回發送端的IP位址int getPort()該方法用於返回發送端或接收端的連接埠號,如果發送端的DatagramPacket對象,就返回接收端的連接埠號,反之,就傳回發送端的連接埠號碼byte[] getData()該方法用於傳回將要接收或將要傳送的數據,如果是發送端的DatagramPacket對象,就傳回將要傳送的數據,反之,就傳回接收到的資料int getLength()該方法用於傳回將要接收或將要傳送資料的長度,如果是發送端的DatagramPacket對象,就傳回將要傳送的資料長度,反之,就回傳接收到資料的長度
##

      2、DatagramSocket

      DatagramSocket類似與碼頭,實例物件就可以傳送和接收DatagramPacket資料包,在建立傳送端和接收端的DatagramSocket物件時,所使用的建構方法有所不同。

      DatagramSocket建構方法:

       ①DatagramSocket()

      收到端的Data 用於建立物件時,在建立物件時,並沒有指定連接埠號碼,此時,系統會傳送端的DatagramSocket物件時,在建立物件時,並沒有指定連接埠號,此時,指派一個沒有被其他網路程式使用的連接埠號碼。

       ②DatagramSocket(int port)

       此方法可用於建立接收端的DatagramSocket對象,可建立傳送端的DatagramSocket對象,在建立接收端的DatagramSocket對象,可建立傳送端的DatagramSocket對象,在建立接收端的DatagramSocket一個連接埠號,這樣就可以監聽指定的連接埠。

       ③DatagramSocket(int port,InetAddress addr)

       使用此建構方法在DatagramSocket時,不僅指定連接埠號碼,也指定了相關的IP位址,此情況適用於計算上有多塊網路卡的情況。                                                                                               DatagramSocket類中的常用方法方法聲明功能描述void receive(DatagramPacket p)此方法用於將接收到的資料填入DatagramPacket資料包中,在接收到資料之前會一直處於阻塞狀態,只有當接收到資料包時,該方法才會回傳。 void  send(DatagramPacket p)#此方法用於傳送DatagramPacket封包,傳送的封包中包含將要傳送的資料、資料的長度、遠端主機的IP位址和連接埠號碼void close()#關閉目前的Socket,通知驅動程式釋放為這個Socket保留的資源。
###

3、UDP 网络程序

在通信时只有接收端程序先运行,才能避免因发送端发送的数据无法接收,而造成数据丢失。示例:

 1 import java.net.DatagramPacket;
 2 import java.net.DatagramSocket;
 3 
 4 //接收端程序
 5 public class Example2 {
 6     public static void main(String[] args) throws Exception{
 7         //创建一个长度为1024的字节数组,用于接收数据
 8         byte [] buf = new byte[1024];
 9         //定义一个DatagramSocket对象,监听的端口为8954
10         DatagramSocket ds = new DatagramSocket(8954);
11         //定义一个DatagramPacket对象,用于接收数据
12         DatagramPacket dp = new DatagramPacket(buf,1024);
13         System.out.println("等待接收数据");
14         ds.receive(dp);          //等待接收数据,如果没有数据则会阻塞
15         //调用DatagramPacket的方法获得接收的消息,包括内容、长度、IP地址和端口号
16         String str = new String(dp.getData(),0,dp.getLength())
17                 +"from"+dp.getAddress().getHostAddress()+":"+dp.getPort();
18         System.out.println(str); //打印收到的信息
19         ds.close();              //释放资源
20     }
21 }
22 
23 
24 import java.net.DatagramPacket;
25 import java.net.DatagramSocket;
26 import java.net.InetAddress;
27 
28 //发送端程序
29 public class Example3 {
30     public static void main(String[] args) throws Exception {
31         //创建一个DatagramSocket对象
32         DatagramSocket ds = new DatagramSocket(3000);
33         String str = "Hello World!";     //要发送的数据
34         /*
35          * 创建一个要发送的数据包,包括发送数据,数据长度,接收端IP地址以及端口号
36          */
37         DatagramPacket dp = new DatagramPacket(str.getBytes(),str.length(),
38                 InetAddress.getByName("localhost"),8954);
39         System.out.println("发送消息");
40         ds.send(dp);                     //发送数据
41         ds.close();                      //释放资源
42     }
登入後複製

运行结果

发送消息

等待接收数据
Hello World!from127.0.0.1:3000
登入後複製

解析:发送货物(数据)前,确定到货码头是否能接收。

创建空间(数据容器)接收货物(数据),创建码头【DatagramSocket(8954)】并实时监听发货码头发货通道(端口),创建集装箱并将空间加入用于接收货物,一直等待接收货物,接收码头将货物填充到集装箱中,获取到货物信息(数据等信息)。

发送货物需要建一个码头【DatagramSocket(3000)】,码头可指定发送通道即端口(也可以不指定发送通道),将要发送货物(数据)装进集装箱(DatagramPacket

)中,并指定发送到的码头名字(IP地址或主机名)及接收通道(端口),通过码头把集装箱发出去[send()],腾出空间(close)。

三、TCP通信

1、ServerSocket

在开发TCP程序时,首先需要创建服务器端程序,其构造方法如下:

①ServerSocket()

使用该构造方法在创建ServerSocket对象时并没有绑定端口号,不能直接使用,还需要继续调用bind(SocketAddress endpoint)方法将其绑定到指定的端口上,才能正常使用。

②ServerSocket(int port)【最常用】

使用用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上。

③ServerSocket(int port,int backlog)

backlog 参数用于指定在服务器忙时,可以与之保持连接请求的等待客户数量,如果没有指定这个参数默认为50 。

④ServerSocket(int port,int backlog,InetAddress bindAddr)

指定了相关的IP地址,适用于计算机上有多块网卡和多个IP的情况。

ServerSocket类中的常用方法
方法声明功能描述
Socket accept()该方法用于等待客户端的连接,在客户端连接之前一直处于阻塞状态,如果有客户端连接就会返回一个与之对应的Socket对象
InetAddress getInetAddress()该方法用于返回一个InetAddress对象,该对象封装了ServerSocket绑定的IP地址
boolean isClosed()该方法用于判断ServerSocket对象是否为关闭状态,如果是关闭状态则返回true,反之则返回false
void bind(SocketAddress endpoint)该方法用于判断ServerSocket对象绑定到指定的IP地址和端口号,其中参数endpoint封装了IP地址和端口号。

2、Socket

Socket类常用构造方法:
①Socket()
使用该构造方法在创建Socket对象时,并没指定IP地址和端口号,创建对象后还需调用connect(SocketAddress endpoint)方法,才能完成与指定服务器的连接,参数endpoint封装了IP地址和端口号。
②Socket(String host,int port)
使用该构造方法在创建Socket对象时,根据参数去连接在指定IP地址和端口上运行的服务器程序,其中参数host接收的一个字符类型的IP地址。
③Socket(InetAddress addres,int port)
与第二个构造方法类似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。
Socket类中的常用方法
方法声明功能描述
int getPort()该方法返回一个int类型对象,该对象时Socket对象与服务器端连接的端口号
InetAddress getLocalAddress()该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回
void close()该方法用于关闭Socket连接,结束本次通信。在关闭Socket之前,应将于Socket相关的所有的输入与输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源
IputStream getInputStream()该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据
OutputStream getOutputStream()该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据
3、简单的TCP网络程序
 1 import java.io.OutputStream;
 2 import java.net.ServerSocket;
 3 import java.net.Socket;
 4 
 5 public class Example4 {
 6     public static void main(String[] args) throws Exception {
 7         new TCPServer().listen();      //创建TCPServer对象,并调用listen()方法
 8     }
 9 }
10 //TCP服务器端
11 class TCPServer{
12     private static final int PORT= 7788;//定义一个端口号
13 
14     public void listen() throws Exception{ //定义一个listen()方法,抛出一个异常
15         ServerSocket serverSocket = new ServerSocket(PORT);//创建ServerSocket对象
16         Socket client=serverSocket.accept();  //调用ServerSocket的accept()方法接收数据
17         OutputStream os = client.getOutputStream(); //获取客户端的输出流
18         System.out.println("开始与客户端交换数据");
19         os.write(("Java欢迎你!").getBytes());
20         Thread.sleep(5000);      //模拟执行其他功能占用的时间
21         System.out.println("结束与客户端交互数据");
22         os.close();
23         client.close();
24     }
25 }
登入後複製

 1 import java.io.InputStream;
 2 import java.net.InetAddress;
 3 import java.net.Socket;
 4 
 5 public class Example5 {
 6     public static void main(String[] args) throws Exception{
 7         new TCPClient().connect();//创建TCPClient对象,并调用connect()方法
 8     }
 9 }
10 //TCP客户端
11 class TCPClient{
12     private static final int PORT=7788;//服务端的端口号
13     public void connect() throws Exception{
14         //创建一个Socket并连接到给出地址和端口号的计算机
15         Socket client = new Socket(InetAddress.getLocalHost(),PORT);
16         InputStream is = client.getInputStream(); //得到接收数据的流
17         byte[] buf = new byte[1024];  //定义1024个字节数组的缓冲区
18         int len=is.read(buf);    //将数据读取到缓冲区中
19         System.out.println(new String(buf,0,len));  //将缓冲区中的数据输出
20         client.close();       //关闭Socket对象,释放资源
21     }
22 }
登入後複製

Example4 运行结果:
开始与客户端交换数据
结束与客户端交互数据

Example5 运行结果:
Java欢迎你!
登入後複製

4、TCP案例——文件上传

实现图片上传到服务器的功能。

服务端程序:

 1 import java.io.File;
 2 import java.io.FileOutputStream;
 3 import java.io.InputStream;
 4 import java.io.OutputStream;
 5 import java.net.ServerSocket;
 6 import java.net.Socket;
 7 
 8 public class Example7 {
 9     public static void main(String[] args) throws Exception{
10         ServerSocket serverSocket = new ServerSocket(10001);//创建ServerSocket对象
11         while (true){
12             //调用accept()方法接收客户端请求,得到Socket对象
13             Socket s = serverSocket.accept();
14             //每当和客户端建立Socket连接后,单独开启一个线程处理和客户端的交互
15             new Thread(new ServerThread(s)).start();
16         }
17     }
18 }
19 class ServerThread implements Runnable{
20     private Socket socket ;     //持有一个Socket类型的属性
21     public ServerThread(Socket socket){   //构造方法中吧Socket对象作为实参传入
22         this.socket=socket;
23     }
24 
25     @Override
26     public void run() {
27         String ip = socket.getInetAddress().getHostAddress(); //获取客户端的IP地址
28         int count =1;        //上传图片个数
29         try{
30             InputStream in = socket.getInputStream();
31             //创建上传图片目录的File对象
32             File parentFile =new File("/Users/adims/Downloads/upload/");
33             if (!parentFile.exists()){  //如果不存在,就创建这个目录
34                 parentFile.mkdir();
35             }
36             //把客户端的IP地址作为上传出文件的文件名
37             File file = new File(parentFile,ip+"("+count+").jpeg");
38             while (file.exists()){
39                 //如果文件名存在,则把count++
40                 file=new File(parentFile,ip+"("+(count++)+").jpeg");
41             }
42             //创建FileOutputStream对象
43             FileOutputStream fos = new FileOutputStream(file);
44             byte[] buf=new byte[1024];  //定义一个字节数组
45             int len=0;     //定义一个int类型的变量len,初始值为0
46             while ((len=in.read(buf))!=-1){   //循环读取数据
47                 fos.write(buf,0,len);
48             }
49             OutputStream out = socket.getOutputStream();  //获取服务端的输出流
50             out.write(("上传成功").getBytes());    //上传成功后向客户端写出"上传成功"
51             fos.close();                          //关闭输出流对象
52             socket.close();                       //关闭Socket对象
53         }catch (Exception e){
54               throw new RuntimeException(e);
55         }
56     }
57 }
登入後複製

客户端程序:

 1 import java.io.FileInputStream;
 2 import java.io.InputStream;
 3 import java.io.OutputStream;
 4 import java.net.InetAddress;
 5 import java.net.Socket;
 6 
 7 public class Example8 {
 8     public static void main(String[] args) throws Exception{
 9         Socket socket= new Socket(InetAddress.getLocalHost(),10001);  //创建客户端Socket对象,指定IP地址和端口号
10         OutputStream out= socket.getOutputStream();  //获取Socket的输出流对象
11         //创建FileInputStream对象
12         FileInputStream fis = new FileInputStream("/Users/adims/Downloads/WechatIMG1.jpeg");
13         byte[] buf =new byte[1024]; //定义一个字节数组
14         int len;       //定义一个int类型的变量len
15         while ((len=fis.read(buf))!=-1){    //循环读取数据
16             out.write(buf,0,len);
17         }
18         socket.shutdownOutput();      //关闭客户端输出流
19         InputStream in = socket.getInputStream();   //获取Socket的输入流对象
20         byte[] bufMsg = new byte[1024];    //定义一个字节数组
21         int num =in.read(bufMsg);          //接收服务端的信息
22         String Msg = new String(bufMsg,0,num);
23         System.out.println(Msg);
24         fis.close();                   //关闭输入流对象
25         socket.close();                //关闭Socket对象
26     }
27 }
登入後複製

需注意:shutdownOutput()方法非常重要,因为服务器端程序在while循环中读取客户端发送的数据,当读取到-1时才会结束循环,如果客户端不调用shutdownOutput()方法关闭输出流,服务器端就不会读到-1,而会一直执行while循环,同时客户端服务器端的read(byte[])方法也是一个阻塞方法,这样客户端与服务器端进入一个“死锁”状态。

以上是Java之網路程式設計的使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板