日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 网络

發布時間:2025/7/25 java 53 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 网络 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

網絡基礎知識

1、計算機網絡

計算機網絡的概念:把分布在不同地理區域的計算機通過專門的通信線路連接在一起形成的規模龐大的、功能強大的網絡系統,一個非常著名的網絡萬維網( World Wide Web , 即www )。

計算機網絡的作用:

  • 資源共享
  • 信息傳輸和集中處理
  • 均衡負荷與分布處理
  • 綜合信息服務

計算機網絡的分類:

  • 按照網絡結構劃分

    星型網絡、總線型網絡、環線型網絡、樹形網絡、星型環線網絡

  • 按照介質來分

    雙絞線網絡、同軸電纜網絡、光纖網、無線網、電力線網

  • 按照規模來劃分

    局域網( LAN )、城域網( MAN )、廣域網( WAN )

2、通信網絡協議

通信網絡協議的概念:網絡通信協議是一種網絡通用語言,為連接不同操作系統和不同硬件體系結構的互聯網絡引提供通信支持,是一種網絡通用語言。

常見協議:

  • OSI

    OSI是Open System Interconnect的縮寫,意為開放式系統互聯。
    國際標準組織(國際標準化組織)制定了OSI模型,這個模型把網絡通信的工作分為7層,分別是物理層、數據鏈路層、網絡層、傳輸層、會話層、表示層和應用層。

  • TCP/IP

    IP是英文Internet Protocol(網絡之間互連的協議)的縮寫中,文簡稱為“網協”,是為計算機網絡相互連接進行通信而設計的協議。
    TCP:Transmission Control Protocol 傳輸控制協議,是一種面向連接(連接導向)的、可靠的、基于字節流的運輸層(Transport layer)通信協議,由IETF的RFC 793說明。 ?     在簡化的計算機網絡OSI模型中,它完成第四層傳輸層所指定的功能。
    UDP是同一層內另一個重要的傳輸協議。

3、IP地址

IP 地址是根據IP 協議為某個通信實體分配的地址

  • 這個通信實體,有可能是計算機、打印機、路由器的某個端口。

IP地址是數字型的,是個32 位( 32bit ) 的整數

  • 通常為了方便記憶,把這32 位分成4 個部分,每個部分存放8 位。
  • 因此我們實際上看到的ip 地址形式為:192.168.95.27。

NIC 負責全球的IP 地址的規劃、管理

  • NIC : Internet Network Information Center。
  • NIC 下屬Inter NIC 、APNIC、PIPE 機構負責美國及其他地區的IP 地址分配。
  • APNIC 總部在日本東京大學,負責亞太地區的IP地址分配。

IP地址被分成A、B、C、D、E 五類

  • A類: 10.0.0.0 ~ 10.255.255.255
  • B類: 172.16.0.0 ~ 172.31.255.255
  • C類: 192.168.0.0 ~ 192.168.255.255

一個特殊的IP 地址

  • 127.0.0.1 : 代表當前計算機本身。

查詢IP地址的命令:

  • ?Windows :? ipconfig? /all
  • ?Unix / Linux / Mac OS :? ifconfig? -a

?IP v4 :

  • 采用 32 bit 的數字表示一個地址??? ------->? java.net.Inet4Address
  • 通常看到的 192.168.100.100 形式是將 32bit 拆分成 4 各部分,每個部分 8bit
  • 不同的部分之間 用 圓點 進行分隔

IP v6 :

  • 采用 128bit 的數字表示一個地址??? ------->? java.net.Inet6Address
  • 通常看到的 FEC0:0:0:ffff::1
  • 每個部分由 4 位 十六進制 表示的 整數 組成,比如 FEC0 , 每部分占 16 bit
  • 不同的部分之間 用 冒號 進行分隔 ,( 分成 8 個部分 )
  • ?如果 某個部分 的 4 個十六進制數字都是 0 ,可以只寫一個 ,比如? 0000 可以寫成 0
  • ?FEC0:0:0:ffff::1 ------>? FEC0:0000:0000:FFFF:0000:0000:0000:0001

4、端口

端口的作用:一個IP 地址可以唯一地確定一個通信實體,一個通信實體上可以有多個程序提供服務比如一臺服務器上可以有多個DBMS,如MySQL 、DB2、Oracle,為了區別同一個通信實體上的不同服務(程序),還要使用端口。

端口的概念:

  • 端口是一個16 bit的整數,用于表示數據交給哪個通信程序處理。
  • 端口是應用程序與外界交流的出入口,是種抽象的軟件結構。

端口的分類:

  • 不同的應用程序處理不同端口上的數據同一個計算機上,不允許有兩個以上程序使用同一個端口。
  • 我們自己在使用端口時,盡量使用1024 以上的端口,同時還要注意避開已經被已有的服務占用的端口。
  • 端口的范圍從0 到65535 ,被分成三類

    公認端口: 從0 到1023
      他們緊密綁定一些特定服務,如80 端口、23端口、21端口等等
    注冊端口: 從1024 到49151
      松散地綁定一些服務,比如
        ? Oracle 數據庫默認的端口是1521
        ? MySQL 數據庫默認的端口是3306
        ? Tomcat 默認的端口是8080
    動態或私有端口: 從49152 到65535
      應用程序使用的動態端口,應用程序一般不會主動去使用這些端口

InetAddress

?1、InetAddress 用來代表IP 地址

它有兩個子類

  • Inet4Address : 對應IPv4 地址
  • Inet6Address : 對應IPv6 地址

沒有構造,通過以下靜態方法獲取該類的實例

  • getByName( String hostName ) :根據指定主機名稱得到對應的InetAddress 實例
  • getByAddress( byte[] address ) :根據指定的IP 地址獲取對應的InetAddress 實例

常用方法

  • String getCanonicalHostName()獲取此IP 地址的完全限定域名
  • String getHostAddress()返回IP 地址字符串(以文本表現形式)
  • String getHostName()獲取此IP 地址的主機名
  • static InetAddress getLocalHost()返回本地主機對應的InetAddress 實例
  • boolean isReachable(int timeout)測試是否可以達到該地址

InetAddress測試案例一:

package ecut.network;import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Arrays; public class InetAddressTest1 { public static void main(String[] args) throws UnknownHostException { // 構造方法私有,通過靜態方法獲得 當前主機的 一個 IP 地址 對應的 InetAddress 實例 InetAddress local = InetAddress.getLocalHost() ; System.out.println( local ); System.out.println( "主機名稱: " + local.getHostName() ); System.out.println( "主機地址: " + local.getHostAddress() ); byte[] address = local.getAddress(); // 以 byte 數組形式表示的 IP 地址 System.out.println( address.length ); System.out.println( Arrays.toString( address ) ); } }

InetAddress測試案例二:

package ecut.network;import java.net.InetAddress; import java.net.UnknownHostException;public class InetAddressTest2 {public static void main(String[] args) throws UnknownHostException {System.out.println( (byte)172 );// byte[] address = { 1 , 0 , 0 , 100 };byte[] address = { (byte)172 , 26 , 28 , 55 };InetAddress remote = InetAddress.getByAddress( address );System.out.println( remote.getHostAddress() );}}

InetAddress測試案例三:

package ecut.network;import java.net.InetAddress; import java.net.UnknownHostException;public class InetAddressTest3 {public static void main(String[] args) throws UnknownHostException {InetAddress ia = InetAddress.getByName( "V-AIMEIZHENGX" );System.out.println( ia.getHostAddress() );System.out.println( "~~~~~~~~~~~~~~~~~~" );InetAddress[] addresses = InetAddress.getAllByName( "V-AIMEIZHENGX" );for( int i = 0 , n = addresses.length ; i < n ;i++){InetAddress a = addresses[ i ] ;System.out.println( a.getHostAddress() );}}}

InetSocketAddress

1、java.net.InetSocketAddress 類型的實例表示 ( IP + Port )

構造方法

  • ?InetSocketAddress(InetAddress addr, int port)根據 IP 地址和端口號創建套接字地址。
  • InetSocketAddress(String hostname, int port)根據主機名和端口號創建套接字地址。

?InetSocketAddress 測試案例一:

package ecut.network;import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.UnknownHostException;public class InetSocketAddressTest1 {public static void main(String[] args) throws UnknownHostException {InetAddress address = InetAddress.getByName( "1.0.0.2" );//傳ip地址和主機名都可以 System.out.println( address.getHostName() );int port = 9527 ;InetSocketAddress isa = new InetSocketAddress( address , port );System.out.println( isa );System.out.println( isa.getHostName() );System.out.println( isa.getAddress().getHostAddress() );System.out.println( isa.getPort() );}}

??InetSocketAddress 測試案例二:

package ecut.network;import java.net.InetSocketAddress; import java.net.UnknownHostException;public class InetSocketAddressTest2 {public static void main(String[] args) throws UnknownHostException {String hostname = "1.0.0.2";//傳ip地址和主機名都可以int port = 9527 ;InetSocketAddress isa = new InetSocketAddress( hostname , port );System.out.println( isa );System.out.println( isa.getHostName() );System.out.println( isa.getAddress().getHostAddress() );System.out.println( isa.getPort() );}}

?URL

1、URL 對象代表Uniform Resource Locator 統一資源定位符(協議://主機:端口/資源路徑和名稱)
它是指向互聯網"資源"的指針

  • 這里的資源可以是簡單的文件或目錄。
  • 也可以是更為復雜的對象(比如數據庫對象)。

URL 通常由協議名、主機名、端口和資源組成,格式如下:

  • protocol : // host : port / resourceName。
  • 常見的URL 如:http://www.baidu.com:80/index.html。
  • ftp://ftp.baidu.com:xx/金剛.mkv 、 jdbc:mysql://localhost:3306/ecut?useUnicode=true&characterEncoding=utf8、jdbc:oracle:thin:@localhost:1521:ecut

2、URL 類的構造
該類有很多重載的構造

  • 但不外乎就是指定協議名、主機名、端口、資源名等參數

可以根據已有的URL 創建全新的URL 對象

  • URL(URL context, String spec)
  • URL(URL context, String spec, URLStreamHandler handler)

3、URL 類中常用方法

String getFile() 獲取此URL 的文件名。

String getHost() 獲取此URL 的主機名(如果適用)。

String getPath() 獲取此URL 的路徑部分。

int getPort() 獲取此URL 的端口號。

String getProtocol() 獲取此URL 的協議名稱。

String getQuery() 獲取此URL 的查詢部分。

URLConnection openConnection()返回一個URLConnection 對象,它表示到URL 所引用的遠程對象的連接。

InputStream openStream()打開到此URL 的連接并返回一個用于從該連接讀入的InputStream。

?URL 測試案例:

package ecut.network;import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL;public class URLTest {public static void main(String[] args) throws IOException {// http://www.baidu.com:80/index.html//MalformedURLException 如果指定了未知協議。URL u = new URL( "http", "www.baidu.com", 80, "/customer/account/change/password.do?date=20170506" );System.out.println( u );System.out.println( "協議: " + u.getProtocol() );System.out.println( "主機: " + u.getHost() );System.out.println( "端口: " + u.getPort() );System.out.println( "File :" + u.getFile() );System.out.println( "Path : " + u.getPath() );System.out.println( "Query : " + u.getQuery() );System.out.println( "~~~~~~~~~~~~~~~~~~~~~~~~~" );InputStream in = u.openStream() ; System.out.println( in );}}

運行結果如下:

http://www.baidu.com:80/customer/account/change/password.do?date=20170506 協議: http 主機: www.baidu.com 端口: 80 File :/customer/account/change/password.do?date=20170506 Path : /customer/account/change/password.do Query : date=20170506 ~~~~~~~~~~~~~~~~~~~~~~~~~ sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@3e3abc88

TCP 協議

1、TCP 協議
使用IP 協議可以將一個消息從一個通信主體發送到另一個通信主體,消息在傳輸過程中被分割成一個一個的小數據包。
雖然解決了數據發送和接受問題,但是不能解決數據分組在傳輸過程中可能出現的問題。
為了解決以上問題,需要提供一整套保障無差錯通信的措施或協議,這就是目前使用廣泛的TCP 協議。
TCP 協議被稱作端對端協議,通過該協議建立了兩個通信實體之間用于發送和收取數據的虛擬鏈路。

2、TCP 協議的可靠性
TCP 協議負責收集被分割的數據分組,并將其按照適當的次序發送;對方在接受到數據分組后再將其正確還原。
為了保證數據包傳送中準確無誤,TCP 協議使用重發機制。

  • 通信實體A發送一個消息給通信實體B后,會等待通信實體B返回的確認信息,如果A沒有收到B的確認信息,則A會再次發送該消息
  • 這種重發機制,保證了數據傳輸的可靠性和完整性。

ServerSocket

1、使用ServerSocket 創建TCP 服務器端
ServerSocket 類的對象用于監聽來自其它通信實體的連接

  • 該類的accept() 方法用于監聽來自外部的連接。
  • 如果沒有任何通信實體連接該ServerSocket 對象,它將永遠等待下去。

獲得ServerSocket 對象

  • 該類中提供了許多重載的構造方法,可以用于實例化ServerSocket。
  • 一般而言需要指定IP 和port。

Socket

1、獲得Socket 進行通信
ServerSocket 實例只負責監聽來自其它通信實體的連接

  • 如果accept() 方法監聽到來自外部的通信實體的連接,它將返回一個Socket。
  • Socket accept() : 返回監聽到的連接對應的Socket 的實例。

使用Socket 類的實例才能實現通信,該類中有兩個非常重要的方法

  • InputStream getInputStream()返回當前的Socket 對應的輸入流,讓程序通過該流從Socket 中讀取數據。
  • OutputStream getOutputStream()返回當前的Socket 對應的輸出流,讓程序通過該流向Socket 中寫入數據。

使用Socket 創建另外一個通信實體

  • 構造一個Socket 實例,讓它去連接前面建好的ServerSocket
  • Socket 類構造有多種重載形式,但一般需要指定連接哪個主機或哪個ip,另外還要指定端口號,比如:Socket s = new Socket("127.0.0.1" , 8888 );

服務端監聽一次測試案例:

package ecut.network;import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress;public class ServerV1 {public static void main(String[] args) throws Exception {// 創建一個 ServerSocket 對象,用來對外提供服務ServerSocket server = new ServerSocket();System.out.println( server );System.out.println( server.isBound() );SocketAddress endpoint = new InetSocketAddress( "10.10.12.72", 5555 );server.bind( endpoint );System.out.println( "server ip : " + server.getInetAddress().getHostAddress());System.out.println( "server port : " +server.getLocalPort() );// 監聽來自客戶端的連接 ( 會阻塞當前線程 )Socket socketFromClient = server.accept();System.out.println( "socket : " + socketFromClient );System.out.println( "server ip ( local ) : " + socketFromClient.getLocalAddress().getHostAddress() );System.out.println( "server port ( local ) : " + socketFromClient.getLocalPort() );InetSocketAddress sa = (InetSocketAddress) socketFromClient.getRemoteSocketAddress();System.out.println( "client ip : " + sa.getHostString() );System.out.println( "client port : " + sa.getPort() );server.close();}} package ecut.network;import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress;public class ClientV1 {public static void main(String[] args) throws IOException {// 創建一個 Socket 對象,充當客戶端程序Socket client = new Socket();SocketAddress bindpoint = new InetSocketAddress( "10.10.12.72", 3333 );// 為客戶端綁定本地的IP地址和端口 client.bind( bindpoint );System.out.println( client );System.out.println( client.getLocalAddress().getHostAddress() );System.out.println( client.getLocalPort() );SocketAddress remote = new InetSocketAddress( "10.10.12.72", 5555 );// 連接 "遠程" 服務 client.connect( remote );System.out.println( client );}}

運行結果如下:

ServerSocket[unbound] false server ip : 10.10.12.72 server port : 5555 socket : Socket[addr=/10.10.12.72,port=3333,localport=5555] server ip ( local ) : 10.10.12.72 server port ( local ) : 5555 client ip : 10.10.12.72 client port : 3333 Socket[unconnected] 10.10.12.72 3333 Socket[addr=/10.10.12.72,port=5555,localport=3333]

服務端持續監聽測試案例:

package ecut.network;import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress;public class ServerV2 {@SuppressWarnings("resource")public static void main(String[] args) throws Exception {// 創建一個 ServerSocket 對象ServerSocket server = new ServerSocket();SocketAddress endpoint = new InetSocketAddress( "10.10.12.72", 6666 );server.bind( endpoint );while( true ) {// 監聽來自客戶端的連接 ( 會阻塞當前線程 )Socket socketFromClient = server.accept();InetSocketAddress sa = (InetSocketAddress) socketFromClient.getRemoteSocketAddress();System.out.print( "client ip : " + sa.getHostString() );System.out.println( " , client port : " + sa.getPort() );}}} package ecut.network;import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress;public class ClientV2 {public static void main(String[] args) throws IOException {// 創建一個 Socket 對象,充當客戶端程序Socket client = new Socket();//默認指定為當地的IP地址,將一個空閑的端口號用于使用 SocketAddress remote = new InetSocketAddress( "10.10.12.72", 6666 );// 連接 "遠程" 服務 client.connect( remote );System.out.println( client );}}

運行結果如下:

Socket[addr=/10.10.12.72,port=6666,localport=50688] Socket[addr=/10.10.12.72,port=6666,localport=50699] client ip : 10.10.12.72 , client port : 50688 client ip : 10.10.12.72 , client port : 50699

?服務端持續監聽測試案例:

package ecut.network;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException;public class ServerV3 {@SuppressWarnings("resource")public static void main(String[] args) throws IOException {// 創建一個 ServerSocket 對象System.out.println("服務器啟動中...");ServerSocket server = new ServerSocket();SocketAddress endpoint = new InetSocketAddress("10.10.12.72", 6666);System.out.println("服務器正在初始化...");server.bind(endpoint);System.out.println("服務器初始化完成,準備對外提供服務");while (true) {System.out.println("服務器正在監聽來自客戶端的連接..."); // ( 會阻塞當前線程 )Socket socket = server.accept();try {// 獲得 可以從 當前監聽到的 客戶端連接 中 讀取數據的 字節輸入流InputStream in = socket.getInputStream();Reader reader = new InputStreamReader(in);BufferedReader br = new BufferedReader(reader);while (true) {String s = br.readLine();System.out.println("來自客戶端的信息: [ " + s + " ]");if ("byebyebye".equalsIgnoreCase(s)) {break;}}} catch (IOException e) {if (e instanceof SocketException) {SocketException se = (SocketException) e;String message = se.getMessage();System.out.print("message"+message);if ("Connection reset".equalsIgnoreCase(message)) {System.out.println("客戶端斷開");} else {se.printStackTrace();}} else {e.printStackTrace();}}}}} package ecut.network;import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.util.Scanner;public class ClientV3 {public static void main(String[] args) throws IOException {final Scanner scanner = new Scanner( System.in );// 1、創建一個可以連接遠程服務器的一個 Socket 對象 ( 充當客戶端 )Socket client = new Socket();SocketAddress remote = new InetSocketAddress( "10.10.12.72", 6666 );// 2、連接 "遠程" 服務器上的指定程序 client.connect( remote );// 3、獲得可以向服務器輸出數據的 字節輸出流OutputStream out = client.getOutputStream();PrintStream ps = new PrintStream( out );while( true ){System.out.println( "請輸入你要向服務器發送的信息:" );String s = scanner.nextLine();ps.println( s );if( "byebyebye".equalsIgnoreCase( s ) ){break ;}}// end client.close();scanner.close();}}

?實現群聊測試案例:

package ecut.network;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.Reader; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.util.HashMap; import java.util.Map;public class ServerV4 {private static final Map<String,Socket> SOCKETS = new HashMap<>() ;@SuppressWarnings("resource")public static void main(String[] args) throws IOException {// 創建一個 ServerSocket 對象System.out.println( "服務器啟動中..." );ServerSocket server = new ServerSocket();SocketAddress endpoint = new InetSocketAddress( "192.168.0.106", 6666 );System.out.println( "服務器正在初始化..." );server.bind( endpoint );System.out.println( "服務器初始化完成,準備對外提供服務" );while( true ) {System.out.println( "服務器正在監聽來自客戶端的連接..."); // ( 會阻塞當前線程 )Socket socket = server.accept();InetSocketAddress remote = (InetSocketAddress) socket.getRemoteSocketAddress();String name = remote.getHostString() + ":" + remote.getPort() ;// 將當前監聽到的 客戶端 name ( ip:port ) 跟 響應的 Socket 對象建立 "映射" SOCKETS.put( name , socket ) ;System.out.println( "創建為[ " + name + " ]提供服務的線程" );ServerThread t = new ServerThread( socket , name ) ;System.out.println( "啟動為[ " + name + " ]提供服務的線程" );t.start();}}public static class ServerThread extends Thread {private String name ;private Socket socket ;public ServerThread(Socket socket , String name ) {super( name );this.name = name ;if( socket == null ) {throw new RuntimeException( "Socket不能是null" );}this.socket = socket;}@Overridepublic void run() {try {// 獲得 可以從 當前監聽到的 客戶端連接 中 讀取數據的 字節輸入流InputStream in = socket.getInputStream();Reader reader = new InputStreamReader( in ) ; BufferedReader br = new BufferedReader( reader );while( true ) {String message = br.readLine();String msg = message ;message = "[ " + name +" ] 說 : [ " + message + " ]";System.out.println( message );for( Socket s :SOCKETS.values() ){OutputStream out = s.getOutputStream();PrintStream ps = new PrintStream( out );ps.println( message ) ;}if( "byebyebye".equalsIgnoreCase( msg ) ){SOCKETS.remove( name );break ;}}} catch (IOException e) {if( e instanceof SocketException ){SocketException se = (SocketException)e ;String message = se.getMessage() ;if( "Connection reset".equalsIgnoreCase( message ) ) {System.out.println( "客戶端斷開" );// 將已經廢棄的 Socket 對象從 Map 集合中移除 SOCKETS.remove( name );} else {se.printStackTrace();}} else {e.printStackTrace();}}}}} package ecut.network;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.PrintStream; import java.io.Reader; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.net.SocketException; import java.util.Scanner;public class ClientV4 {public static void main(String[] args) throws IOException {final Scanner scanner = new Scanner( System.in );// 1、創建一個可以連接遠程服務器的一個 Socket 對象 ( 充當客戶端 )Socket client = new Socket();SocketAddress remote = new InetSocketAddress( "192.168.0.106", 6666 );// 2、連接 "遠程" 服務器上的指定程序 client.connect( remote );// 3、創建一個獨立的線程,專門用來讀取服務器發送的數據ClientThread t = new ClientThread( client );t.start();// 4、獲得可以向服務器輸出數據的 字節輸出流OutputStream out = client.getOutputStream();PrintStream ps = new PrintStream( out );while( true ){System.out.println( "請輸入你要向服務器發送的信息:" );String s = scanner.nextLine();ps.println( s );if( "byebyebye".equalsIgnoreCase( s ) ){break ;}}// end client.close();scanner.close();}public static class ClientThread extends Thread {private Socket socket ;public ClientThread(Socket socket) {super();this.setDaemon( true );//應該設置為精靈線程this.socket = socket;}@Overridepublic void run() {try {// 獲得 可以從 當前監聽到的 客戶端連接 中 讀取數據的 字節輸入流InputStream in = socket.getInputStream();Reader reader = new InputStreamReader( in ) ; BufferedReader br = new BufferedReader( reader );while( true ) {String s = br.readLine();System.out.println( s );}} catch (IOException e) {if( e instanceof SocketException ){SocketException se = (SocketException)e ;String message = se.getMessage() ;if( "Connection reset".equalsIgnoreCase( message ) ) {System.out.println( "服務器已關閉" );} else {se.printStackTrace();}} else {e.printStackTrace();}}}}}

ServerSocket / Socket
?? ??? ?Socket 插板
?? ??? ?服務器:被動地、對外提供某種服務或多種服務
?? ??? ?
?? ??? ?ServerV4 監聽客戶端連接、將監聽到的客戶端加入集合、啟動服務線程
?? ??? ?
?? ??? ?ClientV4 連接遠程服務器、啟動接受數據的線程、向服務器發送數據

運行結果如下:

服務器啟動中... 服務器正在初始化... 服務器初始化完成,準備對外提供服務 服務器正在監聽來自客戶端的連接... 創建為[ 192.168.0.106:52916 ]提供服務的線程 啟動為[ 192.168.0.106:52916 ]提供服務的線程 服務器正在監聽來自客戶端的連接... 創建為[ 192.168.0.106:52917 ]提供服務的線程 啟動為[ 192.168.0.106:52917 ]提供服務的線程 服務器正在監聽來自客戶端的連接... [ 192.168.0.106:52916 ] 說 : [ hello ] [ 192.168.0.106:52917 ] 說 : [ hi ] [ 192.168.0.106:52916 ] 說 : [ nice to meet you ] [ 192.168.0.106:52917 ] 說 : [ nice to meet you too ] [ 192.168.0.106:52916 ] 說 : [ i have someting to do ,so see you later ] [ 192.168.0.106:52917 ] 說 : [ ok, ] [ 192.168.0.106:52916 ] 說 : [ byebyebye ] [ 192.168.0.106:52917 ] 說 : [ byebyebye ] 請輸入你要向服務器發送的信息: hello 請輸入你要向服務器發送的信息: [ 192.168.0.106:52916 ] 說 : [ hello ] [ 192.168.0.106:52917 ] 說 : [ hi ] nice to meet you 請輸入你要向服務器發送的信息: [ 192.168.0.106:52916 ] 說 : [ nice to meet you ] [ 192.168.0.106:52917 ] 說 : [ nice to meet you too ] i have someting to do ,so see you later 請輸入你要向服務器發送的信息: [ 192.168.0.106:52916 ] 說 : [ i have someting to do ,so see you later ] [ 192.168.0.106:52917 ] 說 : [ ok, ] byebyebye 請輸入你要向服務器發送的信息: [ 192.168.0.106:52916 ] 說 : [ hello ] hi 請輸入你要向服務器發送的信息: [ 192.168.0.106:52917 ] 說 : [ hi ] [ 192.168.0.106:52916 ] 說 : [ nice to meet you ] nice to meet you too 請輸入你要向服務器發送的信息: [ 192.168.0.106:52917 ] 說 : [ nice to meet you too ] [ 192.168.0.106:52916 ] 說 : [ i have someting to do ,so see you later ] ok, 請輸入你要向服務器發送的信息: [ 192.168.0.106:52917 ] 說 : [ ok, ] [ 192.168.0.106:52916 ] 說 : [ byebyebye ] byebyebye

?基于ServerSocket / Socket 的聊天室圖解:

?UDP

1、UDP : 解決數據傳輸問題 ,非面向連接、不可靠的數據傳輸協議? ( 代價較小 ),突發性的對數據傳輸要求較低的。

2、數據報(Datagrama):

通過網絡傳輸的數據的基本單元

  • 包含一個報頭(header)和數據本身。
  • 其中報頭描述了數據的目的地以及和其它數據之間的關系。

數據報工作方式的特點

  • 同一報文的不同分組可以由不同的傳輸路徑通過通信子網。
  • 同一報文的不同分組到達目的結點時可能出現亂序、重復與丟失現象。
  • 每一個分組在傳輸過程中都必須帶有目的地址與源地址。
  • 數據報方式報文傳輸延遲較大,適用于突發性通信,不適用于長報文、會話式通信。

3、IP數據報( IP Datagram )
TCP/IP 協議定義的在因特網上傳輸的包

  • 這是一個與硬件無關的虛擬包, 由首部和數據兩部分組成。
  • 首部的前一部分是固定長度,共20字節,是所有IP數據報必須具有的。
  • 在首部的固定部分的后面是一些可選字段,其長度是可變的。
  • 首部中的源地址和目的地址都是IP協議地址。

4、用戶數據報( User Datagram )
基于UDP 在因特網上傳輸的數據包

  • UDP在IP數據報的頭部僅僅加入了復用和數據校驗。
  • UDP首部字段由4個部分組成,其中兩個是可選的。

    來源端口和目的端口用來標記發送和接受的應用進程
      ? 因UDP不需要應答,故來源端口是可選的,若來源端口不用,那么置為零
    在目的端口后面是長度固定的以字節為單位的長度域
      ? 用來指定UDP數據報包括數據部分的長度,長度最小值為8byte。
    首部剩下的部分是用來對首部和數據部分一起做校驗和(Checksum)的
      ? 這部分是可選的,但在實際應用中一般都使用這一功能

用戶數據報協議在網絡中的地位

數據報:報頭(header)+報文。
IP數據報:首部(做出了明確劃分和規定)+數據。
用戶數據報:首部+數據(首部+數據)。

5、TCP 與UDP 的對比
面向連接的TCP :可靠,傳輸大小無限制,但是需要連接建立時間,差錯控制開銷大。
面向非連接的UDP :不可靠,差錯控制開銷較小,傳輸大小限制在64K以下,不需要建立連接(虛擬數
據鏈路)。

6、Java 中的UDP 通信技術核心api

DatagramPacket ( 數據報包)

  • 該類的構造都需要接受一個字節數組做參數: byte[] buff
  • 該字節數組即為需要傳送的數據
  • 該類中有很多重載的構造,可以根據實際情況來調用

DatagramSocket

  • 重載的構造比較多,根據實際情況來調用。
  • 常用方法:

    bind(SocketAddress addr) 將此DatagramSocket綁定到特定的地址和端口。
    close() 關閉此DatagramSocket。
    InetAddress getLocalAddress() 獲取DatagramSocket 綁定的本地地址。
    int getLocalPort() 返回此DatagramSocket 綁定的本地主機上的端口號。
    void receive(DatagramPacket p) 從此DatagramSocket 接收數據報包。
    void send(DatagramPacket p) 從此DatagramSocket 發送數據報包。

DatagramChannel : UDP 的NIO 支持

  • 該類是抽象類,因此構造不能被用來創建對象。
  • 常用方法:

    open() : 靜態方法,用于打開一個數據報通道。
    receive(ByteBuffer dst) 通過此通道接收數據報。
    send(ByteBuffer src, SocketAddress target) 通過此通道發送數據報。
    三個重載的write() 用于將數據報寫入此通道。
    socket() 獲取與此通道關聯的數據報套接字。

  • 繼承的方法:

    該類繼承了java.nio.channels.spi.AbstractSelectableChannel 和java.nio.channels.SelectableChannel ,這兩個類中的方法均可使用。

  • DatagramChannel 也可以注冊于Selector 實例。

基于UDP協議的收發測試案例:

package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress;public class Receiver1 {public static void main(String[] args) throws IOException {// 指定本地的 IP 地址和 端口SocketAddress local = new InetSocketAddress( "192.168.0.106" , 5555 ) ;// 創建一個可以基于UDP 協議進行 收、發 數據的 DatagramSocket 對象DatagramSocket receiver = new DatagramSocket( local );byte[] buffer = new byte[ 1024 ];// 創建一個用來接受數據的數據報包 對象DatagramPacket dp = new DatagramPacket( buffer , buffer.length );// 接受數據 ( 接受時,依然是以數據報包形式接受 ) receiver.receive( dp );byte[] data =dp.getData() ; // 從數據報包 中獲取接受到的數據 ( 長度可能超出實際數據的長度 ) System.out.println( buffer == data ); // true 說明 buffer 和 data 是同一個數組對象int n = dp.getLength() ; // 接受到的字節數組的實際長度 System.out.println( new String( data , 0 , n ) );receiver.close();}} package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress;public class Sender1 {public static void main(String[] args) throws IOException {// 指定本地的 IP 地址和 端口SocketAddress local = new InetSocketAddress( "192.168.0.106" , 2222 ) ;// 創建一個可以基于UDP 協議進行 收、發 數據的 DatagramSocket 對象DatagramSocket sender = new DatagramSocket( local );// 指定遠程IP地址和端口 ( 就是 數據報包 的目的地址 )SocketAddress remote = new InetSocketAddress( "192.168.0.106" , 5555 );// 確定要發送的數據byte[] buffer = "今天天氣不好?好?".getBytes() ;// 構造數據報包 ( 并指定發送的數據 )DatagramPacket dp = new DatagramPacket( buffer, buffer.length );// 為數據報包 指定目的地址 dp.setSocketAddress( remote );// 發送數據報包 sender.send( dp );sender.close();}}

運行結果如下:

true 今天天氣不好?好?

基于UDP協議的多次收發測試案例一:

package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress;public class Receiver2 {public static void main(String[] args) throws IOException {// 指定本地的 IP 地址和 端口SocketAddress local = new InetSocketAddress( "192.168.0.106" , 5555 ) ;// 創建一個可以基于UDP 協議進行 收、發 數據的 DatagramSocket 對象DatagramSocket receiver = new DatagramSocket( local );final byte[] buffer = new byte[ 1024 ];// 創建一個用來接受數據的數據報包 對象DatagramPacket dp = new DatagramPacket( buffer , buffer.length );while( true ) {// 接受數據 ( 接受時,依然是以數據報包形式接受 ) receiver.receive( dp );//byte[] data =dp.getData() ; // 從數據報包 中獲取接受到的數據 ( 長度可能超出實際數據的長度 )int n = dp.getLength() ; // 接受到的字節數組的實際長度String s = new String( buffer , 0 , n );System.out.println( s );if( "byebyebye".equalsIgnoreCase( s ) ){break ;}}receiver.close();}} package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Scanner;public class Sender2 {public static void main(String[] args) throws IOException {Scanner scan = new Scanner( System.in );// 指定本地的 IP 地址和 端口SocketAddress local = new InetSocketAddress( "192.168.0.106" , 2222 ) ;// 創建一個可以基于UDP 協議進行 收、發 數據的 DatagramSocket 對象DatagramSocket sender = new DatagramSocket( local );// 指定遠程IP地址和端口 ( 就是 數據報包 的目的地址 )SocketAddress remote = new InetSocketAddress( "192.168.0.106" , 5555 );final byte[] buffer = { };DatagramPacket dp = new DatagramPacket( buffer, buffer.length );// 為數據報包 指定目的地址 dp.setSocketAddress( remote );String s ;System.out.println( "請輸入你要發送的數據:" );while( ( s = scan.nextLine() ) != null ){byte[] data = s.getBytes() ;// 每次發送之前都將要發送的數據設置到 數據報包 中 dp.setData( data );// 發送數據報包 sender.send( dp );if( "byebyebye".equalsIgnoreCase( s ) ){break ;}System.out.println( "請輸入你要發送的數據:" );}sender.close();scan.close();}}

運行結果如下:

world hello hi hello byebyebye 請輸入你要發送的數據: world 請輸入你要發送的數據: hello 請輸入你要發送的數據: byebyebye 請輸入你要發送的數據: hi 請輸入你要發送的數據: hello 請輸入你要發送的數據: byebyebye

基于UDP協議的多次收發測試案例二:

package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetSocketAddress; import java.net.SocketAddress;public class Receiver3 {public static void main(String[] args) throws IOException {// 指定本地的 IP 地址和 端口SocketAddress local = new InetSocketAddress( "192.168.0.106" , 5555 ) ;// 創建一個可以基于UDP 協議進行 收、發 數據的 DatagramSocket 對象DatagramSocket receiver = new DatagramSocket( local );final byte[] buffer = new byte[ 1024 ];// 創建一個用來接受數據的數據報包 對象DatagramPacket dp = new DatagramPacket( buffer , buffer.length );while( true ) {// 接受數據 ( 接受時,依然是以數據報包形式接受 ) receiver.receive( dp );InetSocketAddress remote = (InetSocketAddress)dp.getSocketAddress(); // 作為接收者,獲得發送者對應的 IP 地址 和 端口String sender = remote.getHostString() + ":" + remote.getPort() ;int n = dp.getLength() ; // 接受到的字節數組的實際長度String s = new String( buffer , 0 , n );System.out.println( sender + "說: " + s );if( "byebyebye".equalsIgnoreCase( s ) ){break ;}}receiver.close();}}

運行結果如下:

192.168.0.106:2222說: hello 192.168.0.106:6666說: hi 192.168.0.106:6666說: byebye 192.168.0.106:2222說: byebyebye hello 請輸入你要發送的數據: byebyebye 請輸入你要發送的數據: hi 請輸入你要發送的數據: byebye 請輸入你要發送的數據: byebyebye

?MulticastSocket

1、多播數據報套接字類用于發送和接收 IP 多播包

MulticastSocket 是一種(UDP) DatagramSocket。
它具有加入Internet 上其他多播主機的“組”的附加功能。
多播組通過D 類IP 地址和標準UDP 端口號指定。

  • D 類IP 地址在224.0.0.0 和239.255.255.255 的范圍內(包括兩者)。
  • 地址224.0.0.0 被保留,不應使用。

構造方法:

  • MulticastSocket()使用本機默認地址、隨機端口來創建MulticastSocket 對象。
  • MulticastSocket(int port)使用本機默認地址和指定端口號來創建MulticastSocket 對象。
  • MulticastSocket( SocketAddress bindaddr )創建綁定到指SocketAddress 的MulticastSocket 對象該SocketAddress 中包含了IP 地址和端口號。

常用方法:

  • void joinGroup(InetAddress mcastaddr)加入多播組。
  • void joinGroup( SocketAddress sa, NetworkInterface ni )加入指定接口上的指定多播組。
  • void leaveGroup( InetAddress ia )離開多播組。
  • void leaveGroup( SocketAddress sa, NetworkInterface ni )離開指定本地接口上的多播組。
  • int getTimeToLive()獲取在套接字上發出的多播數據包的默認生存時間。
  • void setTimeToLive(int ttl)設置所發出的多播數據包的默認生存時間(用以控制多播的范圍)。
    ttl = 0 , 表示指定數據報應停留在本地主機。
    ttl = 1 , 表示指定數據報發送到本地局域網(這是默認值)。
    ttl = 32 , 表示指定數據報只能發送到本站的的網絡上。
    ttl = 64 , 表示指定數據報應保留在本地區。
    ttl = 128 , 表示指定數據報應保留在本大洲。
    ttl = 255 , 表示指定數據報可以發送到Internet 的所有地方。
  • boolean getLoopbackMode()獲取多播數據報的本地回送的設置。
  • void setLoopbackMode(boolean disable)啟用/禁用多播數據報的本地回送。
  • NetworkInterface getNetworkInterface()獲取多播網絡接口集合。
  • void setNetworkInterface(NetworkInterface netIf)指定在此套接字上發送的輸出多播數據報的網絡接口。
  • InetAddress getInterface()獲取用于多播數據包的網絡接口的地址。
  • void setInterface(InetAddress inf)設置多播網絡接口,供其行為將受網絡接口值影響的方法使用。

MulticastSocket測試案例:

package ecut.network;import java.io.IOException; import java.net.DatagramPacket; import java.net.InetAddress; import java.net.MulticastSocket; import java.util.Scanner;public class MulticastSocketTest {public static void main(String[] args) throws IOException {byte[] addr = { (byte)224, 0, 0 , 1 };// 創建 多播組 對應的 IP 地址 ( 224.0.0.0 ~ 239.255.255.255 )final InetAddress group = InetAddress.getByAddress( addr );final int port = 445 ;// 創建可以實現多點廣播的 MulticastSocket 對象MulticastSocket node = new MulticastSocket( port );// 讓當前的 "節點" 加入指定的 多播組 node.joinGroup( group );// 創建一個獨立的接受數據的線程ReceiveThread t = new ReceiveThread( node );t.start(); // 啟動線程// 創建一個數據報包對象 ( 其中 "沒有" 要發送的數據 )DatagramPacket dp = new DatagramPacket( new byte[0] , 0 );// 指定數據報包的目的地址 dp.setAddress( group );// 指定數據報包的目的端口 dp.setPort( port );Scanner scanner = new Scanner( System.in );while( true ){System.out.println( "請輸入你要發送的信息: " );String s = scanner.nextLine();byte[] data = s.getBytes() ; // 將 字符串 根據當前默認平臺編碼編碼為字節數組 ( String ---> byte[] )dp.setData( data ); // 設置將要發送的數據node.send( dp ); // 發送數據if( "byebyebye".equalsIgnoreCase( s ) ){break;}}scanner.close();node.leaveGroup( group );node.close();}public static class ReceiveThread extends Thread {private MulticastSocket currentNode ;public ReceiveThread(MulticastSocket currentNode) {super();this.currentNode = currentNode;this.setDaemon( true ); // 守護線程 }@Overridepublic void run() {final byte[] buffer = new byte[ 1 << 16 ] ;DatagramPacket dp = new DatagramPacket( buffer , buffer.length );while( true ) {try {System.out.println( "接受數據" );currentNode.receive( dp );String sender = dp.getAddress().getHostAddress() + ":" + dp.getPort() ;int len = dp.getLength();String message = new String( buffer , 0 , len ) ;System.out.println( "[" + sender +"] 說 :[ " + message + " ]" );} catch (IOException e) {System.err.println( e.getMessage() );}}}} }

DatagramSocket僅僅同意數據報發送給指定的目標地址,而MulticastSocket能夠將數據報以廣播的方式發送到多個client。

若要使用多點廣播,則須要讓一個數據報標有一組目標主機地址,當數據報發出后,整個組的全部主機都能收到該數據報。IP多點廣播(或多點發送)實現了將單一信息發送到多個接受者的廣播,其思想是設置一組特殊網絡地址作為多點廣播地址,每個多點廣播地址都被看做一個組,當client須要發送、接收廣播信息時,增加到改組就可以。

MulticastSocket既能夠將數據報發送到多點廣播地址,也能夠接收其它主機的廣播信息。

待解決問題

MulticastSocket

轉載請于明顯處標明出處

http://www.cnblogs.com/AmyZheng/p/8616135.html

轉載于:https://www.cnblogs.com/AmyZheng/p/8616135.html

總結

以上是生活随笔為你收集整理的Java 网络的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。