文章目錄
- 概述
- 網路編程三要素:IP、埠號、協議
- Socket通信
- UDP傳輸
- UDP傳輸優化
- UDP傳輸多執行緒
- UDP聊天圖形化界面
- TCP協議
- TCP協議代碼優化
- 服務端是多執行緒的
- 練習
概述
計算機網路
- 是指將地理位置不同的具有獨立功能的多臺計算機及其外部設備,通過通信線路連接起來,在網路作業系統,網路管理軟體及網路通信協議的管理和協調下,實作資源共享和資訊傳遞的計算機系統,
網路編程
- 就是用來實作網路互連的不同計算機上運行的程式間可以進行資料交換,
網路編程三要素:IP、埠號、協議
(1)IP
每個設備在網路中的唯一標識
每臺網路終端在網路中都有一個獨立的地址,我們在網路中傳輸資料就是使用這個地址,
- ipconfig:查看本機IP192.168.12.42
- ping:測驗連接192.168.40.62
- 本地回路地址:127.0.0.1
廣播地址:255.255.255.255- IPv4:4個位元組組成,4個0-255,大概42億,30億都在北美,亞洲4億,2011年初已經用盡,
- IPv6:8組,每組4個16進制數,
1a2b:0000:aaaa:0000:0000:0000:aabb:1f2f
1a2b::aaaa:0000:0000:0000:aabb:1f2f
1a2b:0000:aaaa::aabb:1f2f
1a2b:0000:aaaa::0000:aabb:1f2f
1a2b:0000:aaaa:0000::aabb:1f2f
(2)埠號
每個程式在設備上的唯一標識
每個網路程式都需要系結一個埠號,傳輸資料的時候除了確定發到哪臺機器上,還要明確發到哪個程式,
- 埠號范圍從0-65535
- 撰寫網路應用就需要系結一個埠號,盡量使用1024以上的,1024以下的基本上都被系統程式占用了,
- 常用埠
mysql: 3306
oracle: 1521
web: 80
tomcat: 8080
QQ: 4000
feiQ: 2425
(3)協議
為計算機網路中進行資料交換而建立的規則、標準或約定的集合,
- UDP:
面向無連接,資料不安全,速度快,不區分客戶端與服務端,- TCP:
面向連接(三次握手),資料安全,速度略低,分為客戶端和服務端,
三次握手: 客戶端先向服務端發起請求, 服務端回應請求, 傳輸資料
Socket通信
Socket套接字概述:
網路上具有唯一標識的IP地址和埠號組合在一起才能構成唯一能識別的識別符號套接字
- 通信的兩端都有Socket
- 網路通信其實就是Socket間的通信
- 資料在兩個Socket間通過IO流傳輸
- Socket在應用程式中創建,通過一種系結機制與驅動程式建立關系,告訴自己所對應的IP和port,
UDP傳輸
1.發送Send
(1)創建DatagramSocket, 隨機埠號
(2) 創建DatagramPacket, 指定資料, 長度, 地址, 埠
(3) 使用DatagramSocket發送DatagramPacket
(4) 關閉DatagramSocket
2.接收Receive
(1)創建DatagramSocket, 指定埠號
(2) 創建DatagramPacket, 指定陣列, 長度
(3) 使用DatagramSocket接收DatagramPacket
(4) 關閉DatagramSocket
(5) 從DatagramPacket中獲取資料
3.接收方獲取ip和埠號
- String ip = packet.getAddress().getHostAddress();
- int port = packet.getPort();
代碼示例:先開啟接收端,再開啟發送端
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
public class Demo1_Send {
/**
* 1.發送Send
* 創建DatagramSocket, 隨機埠號
* 創建DatagramPacket, 指定資料, 長度, 地址, 埠
* 使用DatagramSocket發送DatagramPacket
* 關閉DatagramSocket
* @throws SocketException
* @throws UnknownHostException
*/
public static void main(String[] args) throws Exception {
String str = "hello world";
//創建Socket相當于創建碼頭
DatagramSocket socket = new DatagramSocket();
//創建Packet相當于集裝箱
DatagramPacket packet = new DatagramPacket(str.getBytes(), str.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
socket.send(packet); //發貨,將資料發出去
socket.close(); //關閉碼頭
}
}
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class Demo1_Receive {
/**
* 2.接收Receive
* 創建DatagramSocket, 指定埠號
* 創建DatagramPacket, 指定陣列, 長度
* 使用DatagramSocket接收DatagramPacket
* 關閉DatagramSocket
* 從DatagramPacket中獲取資料
* @throws Exception
*/
public static void main(String[] args) throws Exception {
//創建Socket相當于創建碼頭
DatagramSocket socket = new DatagramSocket(6666);
//創建Packet相當于創建集裝箱
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
//接貨,接收資料
socket.receive(packet);
byte[] arr = packet.getData(); //獲取資料
int len = packet.getLength(); //獲取有效的位元組個數
System.out.println(new String(arr,0,len));
socket.close();
}
}
UDP傳輸優化
-
接收端Receive
import java.net.DatagramPacket; import java.net.DatagramSocket; public class Demo2_Receive { /** * 2.接收Receive * 創建DatagramSocket, 指定埠號 * 創建DatagramPacket, 指定陣列, 長度 * 使用DatagramSocket接收DatagramPacket * 關閉DatagramSocket * 從DatagramPacket中獲取資料 * @throws Exception */ public static void main(String[] args) throws Exception { //創建Socket相當于創建碼頭 DatagramSocket socket = new DatagramSocket(6666); //創建Packet相當于創建集裝箱 DatagramPacket packet = new DatagramPacket(new byte[1024], 1024); while(true) { socket.receive(packet); //接貨,接收資料 byte[] arr = packet.getData(); //獲取資料 int len = packet.getLength(); //獲取有效的位元組個數 String ip = packet.getAddress().getHostAddress(); //獲取ip地址 int port = packet.getPort(); //獲取埠號 System.out.println(ip + ":" + port + ":" + new String(arr,0,len)); } } } -
發送端Send
import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.util.Scanner; public class Demo2_Send { /** * 1.發送Send * 創建DatagramSocket, 隨機埠號 * 創建DatagramPacket, 指定資料, 長度, 地址, 埠 * 使用DatagramSocket發送DatagramPacket * 關閉DatagramSocket * @throws SocketException * @throws UnknownHostException */ public static void main(String[] args) throws Exception { Scanner sc = new Scanner(System.in); //創建Socket相當于創建碼頭 DatagramSocket socket = new DatagramSocket(); while(true) { //獲取鍵盤錄入的字串 String line = sc.nextLine(); if("quit".equals(line)) { break; } //創建Packet相當于集裝箱 DatagramPacket packet = new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666); //發貨,將資料發出去 socket.send(packet); } socket.close(); //關閉碼頭 } }
UDP傳輸多執行緒
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
public class Demo3_MoreThread {
public static void main(String[] args) {
new Receive().start();
new Send().start();
}
}
class Receive extends Thread {
public void run() {
try {
//創建Socket相當于創建碼頭
DatagramSocket socket = new DatagramSocket(6666);
//創建Packet相當于創建集裝箱
DatagramPacket packet = new DatagramPacket(new byte[1024], 1024);
while(true) {
socket.receive(packet); //接貨,接收資料
byte[] arr = packet.getData(); //獲取資料
int len = packet.getLength(); //獲取有效的位元組個數
String ip = packet.getAddress().getHostAddress(); //獲取ip地址
int port = packet.getPort(); //獲取埠號
System.out.println(ip + ":" + port + ":" + new String(arr,0,len));
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
class Send extends Thread {
public void run() {
try {
//創建鍵盤錄入物件
Scanner sc = new Scanner(System.in);
//創建Socket相當于創建碼頭
DatagramSocket socket = new DatagramSocket();
while(true) {
//獲取鍵盤錄入的字串
String line = sc.nextLine();
if("quit".equals(line)) {
break;
}
//創建Packet相當于集裝箱
DatagramPacket packet = new DatagramPacket(line.getBytes(), line.getBytes().length, InetAddress.getByName("127.0.0.1"), 6666);
//發貨,將資料發出去
socket.send(packet);
}
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
UDP聊天圖形化界面
- UDP聊天發送、記錄、清屏、震動功能
- UDP聊天快捷鍵、代碼優化、生成jar檔案(自行百度)
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileWriter;
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.text.SimpleDateFormat;
import java.util.Date;
public class Demo4_GUIChat extends Frame {
private TextField tf;
private Button send;
private Button log;
private Button clear;
private Button shake;
private TextArea viewText;
private TextArea sendText;
private DatagramSocket socket;
private BufferedWriter bw;
/**
* @param args
* GUI聊天
*/
public Demo4_GUIChat() {
init();
southPanel();
centerPanel();
event();
}
public void event() {
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
socket.close();
bw.close();
} catch (IOException e1) {
e1.printStackTrace();
}
System.exit(0);
}
});
send.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
send();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
log.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
logFile();
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
clear.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
viewText.setText("");
}
});
shake.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
try {
send(new byte[]{-1},tf.getText());
} catch (IOException e1) {
e1.printStackTrace();
}
}
});
sendText.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e) {
//if(e.getKeyCode() == KeyEvent.VK_ENTER && e.isControlDown()) { //isControlDown ctrl是否被按下
if(e.getKeyCode() == KeyEvent.VK_ENTER) {
try {
send();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
});
}
private void shake() {
int x = this.getLocation().x; //獲取橫坐標位置
int y = this.getLocation().y; //獲取縱坐標位置
for(int i = 0; i < 5; i++) {
try {
this.setLocation(x + 20, y + 20);
Thread.sleep(20);
this.setLocation(x + 20, y - 20);
Thread.sleep(20);
this.setLocation(x - 20, y + 20);
Thread.sleep(20);
this.setLocation(x - 20, y - 20);
Thread.sleep(20);
this.setLocation(x, y);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void logFile() throws IOException {
bw.flush(); //重繪緩沖區
FileInputStream fis = new FileInputStream("config.txt");
ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在記憶體中創建緩沖區
int len;
byte[] arr = new byte[8192];
while((len = fis.read(arr)) != -1) {
baos.write(arr, 0, len);
}
String str = baos.toString(); //將記憶體中的內容轉換成了字串
viewText.setText(str);
fis.close();
}
private void send(byte[] arr, String ip) throws IOException {
DatagramPacket packet = new DatagramPacket(arr, arr.length, InetAddress.getByName(ip), 9999);
socket.send(packet); //發送資料
}
private void send() throws IOException {
String message = sendText.getText(); //獲取發送區域的內容
String ip = tf.getText(); //獲取ip地址;
ip = ip.trim().length() == 0 ? "255.255.255.255" : ip;
send(message.getBytes(),ip);
String time = getCurrentTime(); //獲取當前時間
String str = time + " 我對:" + (ip.equals("255.255.255.255") ? "所有人" : ip) + "說\r\n" + message + "\r\n\r\n"; //alt + shift + l 抽取區域變數
viewText.append(str); //將資訊添加到顯示區域中
bw.write(str); //將資訊寫到資料庫中
sendText.setText("");
}
private String getCurrentTime() {
Date d = new Date(); //創建當前日期物件
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
return sdf.format(d); //將時間格式化
}
public void centerPanel() {
Panel center = new Panel(); //創建中間的Panel
viewText = new TextArea();
sendText = new TextArea(5,1);
center.setLayout(new BorderLayout()); //設定為邊界布局管理器
center.add(sendText,BorderLayout.SOUTH); //發送的文本區域放在南邊
center.add(viewText,BorderLayout.CENTER); //顯示區域放在中間
viewText.setEditable(false); //設定不可以編輯
viewText.setBackground(Color.WHITE); //設定背景顏色
sendText.setFont(new Font("xxx", Font.PLAIN, 15));
viewText.setFont(new Font("xxx", Font.PLAIN, 15));
this.add(center,BorderLayout.CENTER);
}
public void southPanel() {
Panel south = new Panel(); //創建南邊的Panel
tf = new TextField(15);
tf.setText("127.0.0.1");
send = new Button("發 送");
log = new Button("記 錄");
clear = new Button("清 屏");
shake = new Button("震 動");
south.add(tf);
south.add(send);
south.add(log);
south.add(clear);
south.add(shake);
this.add(south,BorderLayout.SOUTH); //將Panel放在Frame的南邊
}
public void init() {
this.setLocation(500, 50);
this.setSize(400, 600);
new Receive().start();
try {
socket = new DatagramSocket();
bw = new BufferedWriter(new FileWriter("config.txt",true)); //需要在尾部追加
} catch (Exception e) {
e.printStackTrace();
}
this.setVisible(true);
}
private class Receive extends Thread { //接收和發送需要同時執行,所以定義成多執行緒的
public void run() {
try {
DatagramSocket socket = new DatagramSocket(9999);
DatagramPacket packet = new DatagramPacket(new byte[8192], 8192);
while(true) {
socket.receive(packet); //接收資訊
byte[] arr = packet.getData(); //獲取位元組資料
int len = packet.getLength(); //獲取有效的位元組資料
if(arr[0] == -1 && len == 1) { //如果發過來的陣列第一個存盤的值是-1,并且陣列長度是1
shake(); //呼叫震動方法
continue; //終止本次回圈,繼續下次回圈,因為震動后不需要執行下面的代碼
}
String message = new String(arr,0,len); //轉換成字串
String time = getCurrentTime(); //獲取當前時間
String ip = packet.getAddress().getHostAddress(); //獲取ip地址
String str = time + " " + ip + " 對我說:\r\n" + message + "\r\n\r\n";
viewText.append(str);
bw.write(str);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
new Demo4_GUIChat();
}
}
TCP協議
1.客戶端
- 創建Socket連接服務端(指定ip地址,埠號)通過ip地址找對應的服務器
- 呼叫Socket的getInputStream()和getOutputStream()方法獲取和服務端相連的IO流
- 輸入流可以讀取服務端輸出流寫出的資料
- 輸出流可以寫出資料到服務端的輸入流
2.服務端
- 創建ServerSocket(需要指定埠號)
- 呼叫ServerSocket的accept()方法接收一個客戶端請求,得到一個Socket
- 呼叫Socket的getInputStream()和getOutputStream()方法獲取和客戶端相連的IO流
- 輸入流可以讀取客戶端輸出流寫出的資料
- 輸出流可以寫出資料到客戶端的輸入流
代碼示例:先開服務端,再開客戶端
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
public class Demo1_Client {
/**
* 1.客戶端
* 創建Socket連接服務端(指定ip地址,埠號)通過ip地址找對應的服務器
* 呼叫Socket的getInputStream()和getOutputStream()方法獲取和服務端相連的IO流
* 輸入流可以讀取服務端輸出流寫出的資料
* 輸出流可以寫出資料到服務端的輸入流
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
//創建Socket指定ip地址和埠號
Socket socket = new Socket("127.0.0.1", 12345);
InputStream is = socket.getInputStream(); //獲取客戶端輸入流
OutputStream os = socket.getOutputStream(); //獲取客戶端的輸出流
byte[] arr = new byte[1024];
int len = is.read(arr); //讀取服務器發過來的資料
System.out.println(new String(arr,0,len)); //將資料轉換成字串并列印
os.write("學習挖掘機哪家強?".getBytes()); //客戶端向服務器寫資料
socket.close();
}
}
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Demo1_Server {
/**
* 2.服務端
* 創建ServerSocket(需要指定埠號)
* 呼叫ServerSocket的accept()方法接收一個客戶端請求,得到一個Socket
* 呼叫Socket的getInputStream()和getOutputStream()方法獲取和客戶端相連的IO流
* 輸入流可以讀取客戶端輸出流寫出的資料
* 輸出流可以寫出資料到客戶端的輸入流
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12345); //創建服務器
Socket socket = server.accept(); //接受客戶端的請求
InputStream is = socket.getInputStream(); //獲取客戶端輸入流
OutputStream os = socket.getOutputStream(); //獲取客戶端的輸出流
os.write("百度一下你就知道".getBytes()); //服務器向客戶端寫出資料
byte[] arr = new byte[1024];
int len = is.read(arr); //讀取客戶端發過來的資料
System.out.println(new String(arr,0,len)); //將資料轉換成字串并列印
socket.close();
}
}
TCP協議代碼優化
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.net.Socket;
import java.net.UnknownHostException;
public class Demo2_Client {
/**
* 1.客戶端
* 創建Socket連接服務端(指定ip地址,埠號)通過ip地址找對應的服務器
* 呼叫Socket的getInputStream()和getOutputStream()方法獲取和服務端相連的IO流
* 輸入流可以讀取服務端輸出流寫出的資料
* 輸出流可以寫出資料到服務端的輸入流
* @throws IOException
* @throws UnknownHostException
*/
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket("127.0.0.1", 12345);
//將位元組流包裝成了字符流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//PrintStream中有寫出換行的方法
PrintStream ps = new PrintStream(socket.getOutputStream());
System.out.println(br.readLine());
ps.println("服務端你好呀!");
System.out.println(br.readLine());
ps.println("我是客戶端啊!");
socket.close();
}
}
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.net.ServerSocket;
import java.net.Socket;
public class Demo2_Server {
/**
* 2.服務端
* 創建ServerSocket(需要指定埠號)
* 呼叫ServerSocket的accept()方法接收一個客戶端請求,得到一個Socket
* 呼叫Socket的getInputStream()和getOutputStream()方法獲取和客戶端相連的IO流
* 輸入流可以讀取客戶端輸出流寫出的資料
* 輸出流可以寫出資料到客戶端的輸入流
* @throws IOException
*/
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12345); //創建服務器
Socket socket = server.accept(); //接受客戶端的請求
InputStream is = socket.getInputStream(); //獲取輸入流
OutputStream os = socket.getOutputStream(); //獲取輸出流
BufferedReader br = new BufferedReader(new InputStreamReader(is));
PrintStream ps = new PrintStream(os);
ps.println("你也好,你是誰啊?");
System.out.println(br.readLine());
ps.println("哦,原來是我的客戶端啊!");
System.out.println(br.readLine());
server.close();
socket.close();
}
}
服務端是多執行緒的
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.net.ServerSocket;
import java.net.Socket;
public class Demo3_Server {
public static void main(String[] args)throws IOException{
//創建服務器
ServerSocket server = new ServerSocket(12345);
while(true) {
//接受客戶端的請求
final Socket socket = server.accept();
new Thread() {
public void run() {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("你好,你是誰啊?");
System.out.println(br.readLine());
ps.println("哦,原來你是我的客戶端啊!");
System.out.println(br.readLine());
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
練習
- 客戶端向服務器寫字串(鍵盤錄入),服務器(多執行緒)將字串列印并反轉后寫回,客戶端再次讀取到是反轉后的字串
- 客戶端向服務器上傳檔案
- 客戶端向服務器寫字串(鍵盤錄入),服務器(多執行緒)將字串列印并反轉后寫回,客戶端再次讀取到是反轉后的字串
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
public class Test1_Client {
public static void main(String[] args) throws UnknownHostException, IOException {
Scanner sc = new Scanner(System.in); //創建鍵盤錄入物件
Socket socket = new Socket("127.0.0.1", 12345); //創建客戶端,指定ip地址和埠號
//獲取輸入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//獲取輸出流
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(sc.nextLine()); //將字串寫到服務器去
System.out.println(br.readLine()); //將反轉后的結果讀出來
socket.close();
}
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
public class Test1_Server {
public static void main(String[] args) throws IOException {
ServerSocket server = new ServerSocket(12345);
System.out.println("服務器啟動,系結埠:12345");
while(true) {
final Socket socket = server.accept(); //接受客戶端的請求
new Thread() { //開啟一條執行緒
public void run() {
try {
//獲取輸入流
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
//獲取輸出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = br.readLine(); //將客戶端寫過來的資料讀取出來
System.out.println(line);
line = new StringBuilder(line).reverse().toString();//鏈式編程
ps.println(line); //反轉后寫回去
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
- 客戶端向服務器上傳檔案
步驟分析 :
1.選擇要上傳的檔案路徑, 驗證路徑是否存在以及是否是檔案夾 – 客戶端
2.發送檔案名到服務端 – 客戶端
3.建立多執行緒的服務器 – 服務端
4.讀取檔案名 – 服務端
5.判斷檔案是否存在, 將結果發回客戶端 – 服務端
6.接收結果, 如果存在給予提示, 程式直接退出 – 客戶端
7.如果不存在, 定義FileInputStream讀取檔案, 寫出到網路 – 客戶端
8.定義FileOutputStream, 從網路讀取資料, 存盤到本地 – 服務端
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Scanner;
/**
1.選擇要上傳的檔案路徑, 驗證路徑是否存在以及是否是檔案夾 -- 客戶端
2.發送檔案名到服務端 -- 客戶端
6.接收結果, 如果存在給予提示, 程式直接退出 -- 客戶端
7.如果不存在, 定義FileInputStream讀取檔案, 寫出到網路 -- 客戶端
*/
public class Test2_UpdateClient {
public static void main(String[] args) throws UnknownHostException, IOException {
// 1.提示輸入要上傳的檔案路徑, 驗證路徑是否存在以及是否是檔案夾
File file = getFile();
// 2.發送檔案名到服務端
Socket socket = new Socket("127.0.0.1", 12345);
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println(file.getName());
// 6.接收結果, 如果存在給予提示, 程式直接退出
String result = br.readLine(); //讀取存在后不存在的結果
if("存在".equals(result)) {
System.out.println("您上傳的檔案已經存在,請不要重復上傳");
socket.close();
return;
}
// 7.如果不存在, 定義FileInputStream讀取檔案, 寫出到網路
FileInputStream fis = new FileInputStream(file);
byte[] arr = new byte[8192];
int len;
System.out.println("檔案上傳中,請等待...");
while((len = fis.read(arr)) != -1) {
ps.write(arr, 0, len);
}
fis.close();
socket.close();
}
private static File getFile() {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個檔案路徑:");
while(true) {
String line = sc.nextLine();
File file = new File(line);
if(!file.exists()) {
System.out.println("您錄入的檔案路徑不存在,請重新錄入:");
}else if(file.isDirectory()) {
System.out.println("您錄入的是檔案夾路徑,請輸入一個檔案路徑:");
}else {
return file;
}
}
}
}
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
3.建立多執行緒的服務器 -- 服務端
4.讀取檔案名 -- 服務端
5.判斷檔案是否存在, 將結果發回客戶端 -- 服務端
8.定義FileOutputStream, 從網路讀取資料, 存盤到本地 -- 服務端
*/
public class Test2_UpdateServer {
public static void main(String[] args) throws IOException {
//3,建立多執行緒的服務器
ServerSocket server = new ServerSocket(12345);
System.out.println("服務器啟動,系結埠號:12345");
//4.讀取檔案名
while(true) {
final Socket socket = server.accept(); //接受請求
new Thread() {
public void run() {
try {
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
PrintStream ps = new PrintStream(socket.getOutputStream());
String fileName = br.readLine();
//5.判斷檔案是否存在, 將結果發回客戶端
File dir = new File("update");
dir.mkdir(); //創建檔案夾
File file = new File(dir,fileName); //封裝成File物件
if(file.exists()) { //如果服務器已經存在這個檔案
ps.println("存在"); //將存在寫給客戶端
socket.close(); //關閉socket
return;
}else {
ps.println("不存在");
}
//8.定義FileOutputStream, 從網路讀取資料, 存盤到本地
FileOutputStream fos = new FileOutputStream(file);
byte[] arr = new byte[8192];
int len;
while((len = is.read(arr)) != -1) {
fos.write(arr, 0, len);
}
fos.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/207566.html
標籤:其他
