java學習day20--網路程式設計
一.網路模型與協議:
OSI 七層模式 : 應用層,表示層,會話層,傳輸層,網路層,鏈路層,物理層
五層模型: 應用層, 傳輸層,網路層,鏈路層,物理層
四層模型 : 應用層, 傳輸層,網路層,鏈路層
應用層:http(超文字傳輸協議) ftp(檔案傳輸協議) stmp (郵件傳送協議) pop3(郵件接收協議), ssh ( 安全shell,用於遠端登入)
傳輸層: tcp(安全可靠的協議) udp(不可靠)
網路層:ip
關於ip地址,作用是用來定位到網路上的另一臺計算機
查詢: windows下可以使用 ipconfig來檢視ip地址
linux 下可以使用 ifconfig來檢視ip地址
關於埠:作用是用來標記,要訪問對方的哪個程式
常用的埠號:
mysql 3306
oracle 1521
sqlserver 1433
redis 6379
tomcat 8080
apache(http的服務) 80
ftp 21
ssh 22
二.傳輸層協議:
tcp協議:
TCP 協議的特點是: TCP 協議是一個有連線、可靠的協議。所謂有連線,指的是在進行 TCP通訊之前,兩個需要通訊的主機之間要首先建立一條資料通道,就好像打電話進行交流之前,首先要讓電話接通一樣。所謂可靠,指的是 TCP 協議能夠保證: 1、傳送端傳送的資料不會丟失; 2、接收端接受的資料包的順序,會按照發送端傳送的包的順序接受。也就是說, TCP協議能夠保證資料能夠完整無誤的傳輸。
udp協議:
與 TCP 協議相比, UDP 是一個無連線,不可靠的協議。 即:資料的傳送方只負責將資料傳送出去,資料的接受方只負責接受資料。傳送方和接收方不會相互確認資料的傳輸是否成功。
相對於 TCP 而言, UDP 有一個優點:效率較高。因此,當我們在對資料傳輸的正確率
不太關心,但是對傳輸效率要求較高的情況下,可以採用 UDP 協議。典型的使用 UDP 協議的是網路語音以及視訊聊天應用
三.java中的網路程式設計
Socket API 對tcp,udp協議做了封裝,能夠連線到對方主機,收發資料
tcp的例子:建立連線
伺服器端
import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; public class ServerTest { public static void main(String[] args) throws IOException { //傳一個埠號與客戶端進行連線,埠號一般使用4位以上的數字 ServerSocket ss = new ServerSocket(12345); System.out.println("等待客戶端連線"); //等待客戶端連線伺服器方法,直到有客戶端連線 Socket socket = ss.accept(); //將接收到的資料讀入 InputStream is = socket.getInputStream(); byte[] by = new byte[1024]; while(true) { int len = is.read(by); if(-1 == len) { break; } System.out.println(new String(by, 0, len)); } //關閉 socket.close(); } }
客戶端
import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;
public class UserTest {
public static void main(String[] args) throws IOException {
//因為連線的是本機,所以將本機地址以及要連線的伺服器埠號傳入
Socket socket = new Socket("localhost", 12345);
Scanner sc = new Scanner(System.in);
while(true) {
String line = sc.nextLine();
socket.getOutputStream().write(line.getBytes());
}
}
}
上述程式只是進行一個伺服器和一個客戶端進行一次性對話,接下來實現支援多個客戶端連線的伺服器
只需要將伺服器端進行重寫
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class ServerTest {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(12345);
//建立一個執行緒池
ExecutorService threadPool = Executors.newCachedThreadPool();
System.out.println("等待客戶端連線");
while(true) {
Socket socket = ss.accept(); //每連線一個新使用者呼叫一次accept()
//讓執行緒池中的執行緒來處理
threadPool.submit(() -> {
try {
InputStream is = socket.getInputStream(); //讀取接收的資訊
InetAddress add = socket.getInetAddress(); //獲取資訊源的地址
byte[] by = new byte[1024];
while(true) {
int len = is.read(by);
if(-1 == len) {
break;
}
System.out.println(add + " " + new String(by, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
}
上面的方式實現了多個客戶端向服務端傳送訊息的功能,但是隻有服務端自己能看到訊息,所以要進行改進,讓聊天室內所有的使用者都能看到訊息,即將伺服器端接收的訊息給所有客戶端傳送一份
伺服器端
import java.io.*;
import java.net.*;
import java.util.concurrent.*;
public class ServerTest {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(12345);
//建立一個執行緒池
ExecutorService threadPool = Executors.newCachedThreadPool();
//建立一個集合用來儲存所有的客戶端socket
ConcurrentHashMap<Socket, InetAddress> map = new ConcurrentHashMap<>();
System.out.println("等待客戶端連線");
while(true) {
//每接收一個新使用者呼叫一次accept()
Socket socket = ss.accept();
InetAddress add = socket.getInetAddress();
//將新使用者新增到集合中
map.put(socket, add);
threadPool.submit(() -> {
try {
InputStream is = socket.getInputStream();
byte[] by = new byte[1024];
while(true) {
int len = is.read(by);
if(-1 == len) {
break;
}
System.out.println(add + " " + new String(by, 0, len));
String content = add + " " + new String(by, 0, len);
//遍歷map集合,將內容寫到每個使用者中
for(Socket userSocket : map.keySet()) {
OutputStream os = userSocket.getOutputStream();
os.write(content.getBytes());
}
}
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
}
客戶端
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.Scanner;
public class UserTest {
public static void main(String[] args) throws IOException {
//因為連線的是本機,所以將本機地址以及要連線的伺服器埠號傳入
Socket socket = new Socket("localhost", 12345);
Scanner sc = new Scanner(System.in);
//建立一個執行緒,讀入傳送過來的訊息,並進行輸出
new Thread(() -> {
try {
InputStream is = socket.getInputStream();
byte[] by = new byte[1024];
while(true) {
int len = is.read(by);
if(-1 == len) {
break;
}
System.out.println(new String(by, 0, len));
}
} catch (Exception e) {
e.printStackTrace();
}
}).start();
while(true) {
String line = sc.nextLine();
socket.getOutputStream().write(line.getBytes());
}
}
}