目錄
網絡編程
網絡編程概述
計算機網絡
是指將地理位置不同的具有獨立功能的多臺計算機及其外部設備,通過通信線路連接起來,在網絡操作系統,網絡管理軟件及網絡通信協議的管理和協調下,實現資源共享和信息傳遞的計算機系統
網絡編程
在網絡通信協議下,實現網絡互連的不同計算機上運行的程序間可以進行數據交換
具體概述可以去看看
https://blog.csdn.net/qq_36171287/article/details/95670584
https://blog.csdn.net/qq_36171287/article/details/99580141
網絡編程三要素
IP地址
要想讓網絡中的計算機能夠互相通信,必須爲每臺計算機指定一個標識號, 通過這個標識號來指定要接收數據的計算機和識別發送的計算機,而IP地址就是這個標識號。也就是設備的標識
Java中有InetAddress類
public class InetAddress
extends Object
implements Serializable
此類表示Internet協議(IP)地址。
IP地址是由IP使用的32位或128位無符號數字,構建UDP和TCP協議的低級協議。 IP地址結構由定義RFC 790: Assigned Numbers , RFC 1918: Address Allocation for Private Internets , RFC 2365: Administratively Scoped IP Multicast和RFC 2373: IP Version 6 Addressing Architecture 。 InetAddress的一個實例由一個IP地址和可能的相應主機名組成(取決於它是用主機名構造還是已經完成了反向主機名解析)。
例子:
public class InetAddressDemo {
public static void main(String[] args) throws UnknownHostException {
//確定主機名稱的IP地址
InetAddress address = InetAddress.getByName("192.168.0.101");
//獲取IP地址主機名
String name = address.getHostName();
//返回文本顯示中的IP地址字符串
String ip = address.getHostAddress();
System.out.println("主機名:" + ip);
System.out.println("IP地址:" + ip);
}
}
端口
網絡的通信,本質上是兩個應用程序的通信。每臺計算機都有很多的應用程序,那麼在網絡通信時,如何區分這些應用程序呢?如果說IP地址可以唯一標識網絡中的設備, 那麼端口號就可以唯標識設備中的應用程序了。也就是應用程序的標識
協議
通過計算機網絡可以使多 臺計算機實現連接,位於同一個網絡中的計算機在進行連接和通信時需要遵守一定的規則,這就好比在道路中行駛的汽車一定要遵守交通規則- 樣。在計算機網絡中,這些連接和通信的規則被稱爲網絡通信協議,它對數據的傳輸格式、傳輸速率、傳輸步驟等做了統-規定, 通信雙方必須同時遵守才能完成數據交換。常見的協議有UDP協議和TCP協議
TCP協議
- 傳輸控制協議 (Transmission Control Protocol)
- TCP協議是面向連接的通信協議,即傳輸數據之前,在發送端和接收端建立邏輯連接,然後再傳輸數據,
- 它提供了兩臺計算機之間可靠無差錯的數據傳輸。在TCP連接中必須要明確客戶端與服務器端,由客戶端
- 向服務端發出連接請求,每次連接的創建都需要經過“三次握手"
- 三次握手: TCP協議中,在發送數據的準備階段,客戶端與服務器之間的三次交互,以保證連接的可靠
- 第一次握手,客戶端向服務器端發出連接請求,等待服務器確認
- 第二次握手,服務器端向客戶端回送-一個響應, 通知客戶端收到了連接請求
- 第三次握手,客戶端再次向服務器端發送確認信息,確認連接
TCP通信協議是一種可靠的網絡協議,它在通信的兩端各建立一一個Socket對象,從而在通信的兩端形成網絡虛擬鏈路,一旦建立了虛擬的網絡鏈路,兩端的程序就可以通過虛擬鏈路進行通信
Java對基於TCP協議的的網絡提供了良好的封裝,使用Socket對象來代表兩端的通信端口, 並通過Socket產生流來進行網絡通信
Java爲客戶端提供了Socket類,爲服務 器端提供了ServerSocket類
發送端代碼:
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
public class TCPsend {
public static void main(String[] args) throws IOException {
//創建socket對象
// Socket sc = new Socket(InetAddress.getByName("127.0.0.1"),123456);
Socket s = new Socket("127.0.0.1",12345);
//獲取輸出流,寫數據
OutputStream os = s.getOutputStream();
os.write("hello,TCP".getBytes());
//釋放資源
s.close();
}
}
接收端:
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPreceive {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(12345);
//accept():偵聽要連接到此套接字並接受它
Socket s = ss.accept();
//獲取輸入流,讀數據
InputStream is = s.getInputStream();
byte[] bys = new byte[1024];
int len = is.read(bys);
String data = new String(bys,0,len);
System.out.println("數據是:"+data);
s.close();
}
}
運行結果:
UDP協議
- UDP協議是一種不可靠的網絡協議,它在通信的兩端各建立-個Socket對象,但是這兩個Socket只是發送,接收數據的對象
- 因此對於基於UDP協議的通信雙方而言,沒有所謂的客戶端和服務器的概念
- Java提供了DatagramSocket類作爲基於UDP協議的Socket
發送數據的步驟
- ①創建發送端的Socket對象(DatagramSocket)
- ②創建數據, 並把數據打包
- ③調用DatagramSocke對象的方法發送數據
- ④關閉發送端
import java.io.IOException;
import java.net.*;
public class UDPdemo {
public static void main(String[] args) throws IOException {
//創建發送端的Socket對象(DatagramSocket)
DatagramSocket ds = new DatagramSocket();
//創建數據,把數據打包
//構造一個數據包,發送程度爲len的數據包到指定主機的指定端口號
byte[] bys = "hello world,我來了".getBytes();
int len = bys.length;
InetAddress address = InetAddress.getByName("127.0.0.1");
int port = 10086;
DatagramPacket dp = new DatagramPacket(bys,len,address,port);
//調用DatagramSocke對象的方法發送數據
ds.send(dp);
//關閉發送端
ds.close();
}
}
UDP接收數據
接收數據的步驟
- ①創建接收端的Socket對象(DatagramSocket)
- ②創建一個數據包, 用於接收數據
- ③調用DatagramSocket對象的方法接收數據
- ④解析數據包,並把數據在控制檯顯示
- ⑤關閉接收端
代碼:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
public class UDPreceive {
public static void main(String[] args) throws IOException {
//創建socket接收端對象,參數是制定的端口
DatagramSocket ds = new DatagramSocket(10086);
byte[] bys = new byte[1024];
DatagramPacket dp = new DatagramPacket(bys,bys.length);
ds.receive(dp);
//解析數據包,並把數據在控制檯顯示
int len = dp.getLength();
byte[] data = dp.getData();
System.out.println("數據是:" + new String(data,0,len));
ds.close();
}
}
運行接收端,然後再運行發送端,這樣接收端控制檯中就能夠接收到發送端發送過來的數據了
Lambda表達式
函數式編程思想概述
在數學中,函數就是有輸入量輸出量的一套計算方案,也就是“拿數據做操作”
面向對象思想強調“必須通過對象的形式來做事情”
函數式思想則儘量忽略面向對象的複雜語法:“強調做什麼, 而不是以什麼形式去做”
而我們要學習的Lambda表達式就是函數式思想的體現
例子:很像JavaScript中的箭頭函數
public class LambdaDemo {
public static void main(String[] args) {
//實現類的方式實現需求
// MyRunnable my = new MyRunnable();
// Thread t = new Thread(my);
// t.start();
//匿名內部類的方式改進
// new Thread(new Runnable() {
// @Override
// public void run() {
// System.out.println("多線程程序啓動了");
// }
// }).start();
//Lambda表達式方式改進
new Thread( ()->{
System.out.println("多線程程序啓動了");
} ).start();
}
}
Lambda表達式標準格式
匿名內部類中重寫run()方法的代碼分析
- 方法形式參數爲空,說明調用方法時不需要傳遞參數
- 方法返回值類型爲void, 說明方法執行沒有結果返回
- 方法體中的內容, 是我們具體要做的事情
Lambda表達式的代碼分析
- (): 裏面沒有內容,可以看成是方法形式參數爲空
- ->:用箭頭指向後面要做的事情
- {}: 包含一段代碼, 我們稱之爲代碼塊,可以看成是方法體中的內容
JavaScript中箭頭函數例子:
var fun = function(a,b){ return a+b; }
var f = (a,b) => a+b
Lambda表達式的格式
格式: (形式參數)-> {代碼塊}
- 形式參數:如果有多個參數,參數之間用逗號隔開;如果沒有參數,留空即可
- ->:由英文中畫線和大於符號組成,固定寫法。代表指向動作
- 代碼塊:是我們具體要做的事情,也就是以前我們寫的方法體內容
其只能有一個抽象方法,否則就不是函數時接口,就無法用Lambda表達式。
函數式接口
概述
函數式接口:有且僅有一個抽象方法的接口
Java中的函數式編程體現就是Lambda表達式,所以函數式接口就是可以適用於Lambda使用的接口
只有確保接口中有且僅有一個抽象方法,Java中的Lambda才能順利地進行推導
如何檢測一個接口是不是函數式接口呢?
- @Functionallnterface
- 放在接口定義的上方:如果接口是函數式接口,編譯通過;如果不是,編譯失敗
注意
- 我們自己定義函數式接口的時候,@FunctionalInterface是可選的, 就算我不寫這個註解,只要保證滿足函數式接口定義的條件,也照樣是函數式接口。但是,建議加上該註解
函數式接口作爲方法的參數
定義一個類(RunnableDemo),在類中提供兩個方法
- 一個方法是: startThread(Runnable r)方法 參數Runnable是一個函數式接口
- 一個方法是主方法,在主方法中調用start Thread方法
例子:
public class RunnableDemo {
public static void main(String[] args) {
//匿名內部類方式
startThread(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+"線程啓動了");
}
});
startThread(()-> System.out.println(Thread.currentThread().getName()+"線程啓動了"));
}
private static void startThread(Runnable r){
// Thread t = new Thread(r);
// t.start();
new Thread(r).start();
}
}
Supplier接口
Supplier<T>:包含一個無參的方法
- T get():獲得結果
- 該方法不需要參數, 它會按照某種實現邏輯(由Lambda表達式實現)返回一個數據
例子:
public class SupplierDemo {
public static void main(String[] args) {
String s = getString(()->{
return "寶可夢";
});
System.out.println(s);
}
//定義一個方法,返回一個字符串數據
private static String getString(Supplier<String> sup){
return sup.get();
}
}
Stream流
public interface Stream<T> extends BaseStream<T,Stream<T>>
使用Stream流的方式完成過濾操作
直接閱讀代碼的字面意思即可完美展示無關邏輯方式的語義:生成流、過濾、逐一打印
Stream流把真正的函數式編程風格引入到ava中
Stream流生成方式
Stream流的使用
- 生成流
- 通過數據源(集合,數組等)生成流
- list.stream()
- 中間操作
- 一個流後面可以跟隨零個或多箇中間操作,其目的主要是打開流,做出某種程度的數據過濾映射,然後返回一個新的流,交給下一個操作使用
- filter()
- 終結操作
- 一個流只能有一個終結操作, 當這個操作執行後,流就被使用“光” 了,無法再被操作。所以這必定是流的最後一個操作
- forEach()
Stream流的常見生成方式
- Collection體 系的集合可以使用默認方法stream()生成流
- default Stream<E> stream()
- Map體系的集合間接的生成流
- 數組可以通過Stream接口的靜態方法of(T... values)生成流
例子:
public class CreateStream {
public static void main(String[] args) {
// Collection體 系的集合可以使用默認方法stream()生成流
// default Stream<E> stream()
List<String> list = new ArrayList<>();
Stream<String> liststream = list.stream();
Set<String> set = new HashSet<>();
Stream<String> setstream = set.stream();
// Map體系的集合間接的生成流
Map<Integer,String> map = new HashMap<>();
Stream<Integer> keystream = map.keySet().stream();
Stream<String> valuestream = map.values().stream();
Stream<Map.Entry<Integer,String>> mapstream = map.entrySet().stream();
// 數組可以通過Stream接口的靜態方法of(T... values)生成流
String[] strarray = {"hello","hi","thank","you"};
Stream<String> strstream = Stream.of(strarray);
Stream<String> strstream2 = Stream.of("hello","hi","thank","you");
}
}
一起學習,一起進步 -.- ,如有錯誤,可以發評論