Java-網(wǎng)絡(luò)編程(TCP-UDP)
網(wǎng)絡(luò)基礎(chǔ)
- 網(wǎng)絡(luò)編程最主要的工作就是在發(fā)送端把信息通過規(guī)定好的協(xié)議進(jìn)行組裝包,在接收端按照規(guī)定好的協(xié)議把包進(jìn)行解析,從而提取出對應(yīng)的信息,達(dá)到通信的目的。中間最主要的就是數(shù)據(jù)包的組裝,數(shù)據(jù)包的過濾,數(shù)據(jù)包的捕獲,數(shù)據(jù)包的分析,當(dāng)然最后再做一些處理,代碼、開發(fā)工具、數(shù)據(jù)庫、服務(wù)器架設(shè)和網(wǎng)頁設(shè)計這5部分你都要接觸
簡介
- 網(wǎng)絡(luò):兩臺或多臺設(shè)備通過一定物理設(shè)備連接起來構(gòu)成了網(wǎng)絡(luò)
- 網(wǎng)絡(luò)通信:將數(shù)據(jù)通過網(wǎng)絡(luò)從一臺設(shè)備傳輸?shù)搅硪慌_設(shè)備
- TCP協(xié)議: 傳輸控制協(xié)議
- 1.使用TCP協(xié)議前,須先建立TCP連接,形成傳輸數(shù)據(jù)通道
- 2.傳輸前,采用”三次握手”方式,是可靠的
- 3.TCP協(xié)議進(jìn)行通信的兩個應(yīng)用進(jìn)程:客戶端、服務(wù)端
- 4.在連接中可進(jìn)行大數(shù)據(jù)量的傳輸
- 5.傳輸完畢,需釋放已建立的連接,效率低
- UDP協(xié)議: 用戶數(shù)據(jù)協(xié)議
- 1.將數(shù)據(jù)、源、目的封裝成數(shù)據(jù)包,不需要建立連接
- 2.因無需連接,故是不可靠的
- 2.每個數(shù)據(jù)報的大小限制在64K內(nèi),不適合傳輸大量數(shù)據(jù)
- 4.發(fā)送數(shù)據(jù)結(jié)束時無需釋放資源(因為不是面向連接的),速度快
Java提供的網(wǎng)絡(luò)功能類
- InetAddress: 用于標(biāo)識網(wǎng)絡(luò)上的硬件資源
- Socket和ServerSocket: 使用TCP協(xié)議實現(xiàn)網(wǎng)絡(luò)通信的 Socket 相關(guān)的類
- Datagram: 使用UDP協(xié)議,將數(shù)據(jù)保存在數(shù)據(jù)報中,通過網(wǎng)絡(luò)進(jìn)行通信
InetAddress
- getLocalHost() 獲取本機(jī) InetAddress 對象
- getByName() 根據(jù)指定主機(jī)名/域名獲取 ip 地址對象
- getHostName() 獲取 InetAddress 對象的主機(jī)名
- getHostAddress() 獲取 InetAddress 對象的地址
package com.jwt.network;
import java.net.InetAddress;
import java.net.UnknownHostException;
public class InetAddress_ {
public static void main(String[] args) throws UnknownHostException {
//獲取本機(jī)InetAddress 對象
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
//根據(jù)指定主機(jī)名/域名獲取對象
InetAddress host2 = InetAddress.getByName("jianjian");
System.out.println(host2);
InetAddress host3 = InetAddress.getByName("www.baidu.com");
System.out.println(host3);
//獲取InetAddress對象的主機(jī)名
String host3Name = host3.getHostName();
System.out.println(host3Name);
//獲取InetAddress對象的地址
String host3Address = host3.getHostAddress();
System.out.println(host3Address);
}
}
/**
jianjian/192.168.50.204
jianjian/192.168.50.204
www.baidu.com/14.215.177.39
www.baidu.com
14.215.177.39
**/
Socket
簡介
- 套接字(Socket)開發(fā)網(wǎng)絡(luò)應(yīng)用程序被廣泛采用,以至于成為事實上的標(biāo)準(zhǔn)。
- 通信的兩端都要有Socket,是兩臺機(jī)器間通信的端點(diǎn)。
- 網(wǎng)絡(luò)通信其實就是 Socket 間的通信。
- Socket 允許程序把網(wǎng)絡(luò)連接當(dāng)成一個流,數(shù)據(jù)在兩個 Socket 間通過 IO 傳輸。
- 一般主動發(fā)起通信的應(yīng)用程序?qū)倏蛻舳耍却ㄐ耪埱蟮臑榉?wù)端。
TCP編程
簡介
- 1.基于客戶端-服務(wù)端的網(wǎng)絡(luò)通信
- 2.底層使用的是TCP/IP協(xié)議
- 3.應(yīng)用場景舉例:客戶端發(fā)送數(shù)據(jù),服務(wù)端接受并顯示控制臺
流程
TCP,傳輸前先開服務(wù)端,accept,等客戶端接入,然后獲得客戶端 socket 然后進(jìn)行 IO 操作
服務(wù)端編寫
-
Step 1
:創(chuàng)建ServerSocket對象,綁定監(jiān)聽的端口
- ServerSocket serverSocket = new ServerSocket(Port);
-
Step 2
:調(diào)用accept()方法監(jiān)聽客戶端的請求
- Socket socket = serverSocket.accept();
-
step 3
:連接建立后,通過輸入流讀取客戶端發(fā)送的請求信息
- InputStream inputStream = socket.getInputStream();
-
Step 4
:通過輸出流向客戶端發(fā)送響應(yīng)信息
- OutputStream outputStream = socket.getOutputStream();
-
Step 5
:關(guān)閉相關(guān)資源
- outputStream.close();
- inputStream.close();
- socket.close();
- serverSocket.close();
客戶端編寫
-
Step 1:創(chuàng)建Socket對象,指明需要鏈接的服務(wù)器的地址和端號
- Socket socket = new Socket(“server address”, port);
-
Step 2:鏈接建立后,通過輸出流向服務(wù)器發(fā)送請求信息
- OutputStream outputStream = socket.getOutputStream();
-
Step 3:通過輸入流獲取服務(wù)器響應(yīng)的信息
- InputStream inputStream = socket.getInputStream();
-
Step 4:關(guān)閉相關(guān)資源
- inputStream.close();
- outputStream.close();
- socket.close();
例子1:使用字節(jié)流通信
- 1.編寫一個服務(wù)器端和一個客戶端
- 2.服務(wù)器端監(jiān)聽 9999 端口
- 3.客戶端連接到服務(wù)器端, 發(fā)送”你好,服務(wù)端!”,并接收服務(wù)器端回發(fā)的”你好,客戶端!”,再退出
- 4.服務(wù)器端接收到客戶端發(fā)送的信息,輸出,并發(fā)送”你好,客戶端!”, 再退出
服務(wù)端
package com.jwt.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP01Server {
public static void main(String[] args) throws IOException {
//1. 監(jiān)聽本機(jī)的9999 端口, 等待連接
// 細(xì)節(jié): 要求在本機(jī)沒有其它服務(wù)在監(jiān)聽9999
// 細(xì)節(jié):這個ServerSocket 可以通過accept() 返回多個Socket[多個客戶端連接服務(wù)器的并發(fā)]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("我是服務(wù)端,正在監(jiān)聽9999端口,等待連接...");
//2. 當(dāng)沒有客戶端連接9999 端口時,程序會阻塞, 等待連接
// 如果有客戶端連接,則會返回Socket 對象,程序繼續(xù)
Socket socket = serverSocket.accept();
System.out.println("服務(wù)端socket=" + socket.getClass());
//3. 通過輸入流,讀取客戶端寫入到數(shù)據(jù)通道的數(shù)據(jù), 顯示
InputStream inputStream = socket.getInputStream();
//4. IO 讀取
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen=inputStream.read(buf))!= -1) {
System.out.println(new String(buf,0,readLen));
}
//5. 通過輸出流,寫入數(shù)據(jù)到數(shù)據(jù)通道
OutputStream outputStream = socket.getOutputStream();
outputStream.write("服務(wù)端說:你好,客戶端!".getBytes());
// 設(shè)置結(jié)束標(biāo)記
socket.shutdownOutput();
//6.關(guān)閉流和socket
outputStream.close();
inputStream.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出.....");
}
}
客戶端
package com.jwt.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
public class SocketTCP01Client {
public static void main(String[] args) throws IOException {
//1. 連接服務(wù)端(ip , 端口)如果連接成功,返回Socket 對象
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
System.out.println("客戶端socket返回=" + socket.getClass());
//2. 連接上后,生成Socket, 通過socket.getOutputStream()
OutputStream outputStream = socket.getOutputStream();
//3. 通過輸出流,寫入數(shù)據(jù)到數(shù)據(jù)通道
outputStream.write("客戶端說:你好,服務(wù)端!".getBytes());
// 設(shè)置結(jié)束標(biāo)記
socket.shutdownOutput();
//4. 獲取和socket 關(guān)聯(lián)的輸入流. 讀取數(shù)據(jù)(字節(jié)),并顯示
InputStream inputStream = socket.getInputStream();
byte[] buf = new byte[1024];
int readLen = 0;
while ((readLen=inputStream.read(buf))!= -1) {
System.out.println(new String(buf,0,readLen));
}
//5. 關(guān)閉流對象和socket, 必須關(guān)閉
inputStream.close();
outputStream.close();
socket.close();
System.out.println("客戶端退出.....");
}
}
例子2:使用字符流通信
- 1.編寫一個服務(wù)端和一個客戶端
- 2.服務(wù)端在9999端口監(jiān)聽
- 3.客戶端連接到服務(wù)端,發(fā)送”你好,服務(wù)端!”,并接收服務(wù)端回發(fā)的”你好,客戶端!”,再退出
- 4.服務(wù)端接收到客戶端發(fā)送的信息,輸出,并發(fā)送”你好,客戶端!”,再退出
服務(wù)端
package com.jwt.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
//1. 監(jiān)聽本機(jī)的9999 端口, 等待連接
// 細(xì)節(jié): 要求在本機(jī)沒有其它服務(wù)在監(jiān)聽9999
// 細(xì)節(jié):這個ServerSocket 可以通過accept() 返回多個Socket[多個客戶端連接服務(wù)器的并發(fā)]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("我是服務(wù)端,正在監(jiān)聽9999端口,等待連接...");
//2. 當(dāng)沒有客戶端連接9999 端口時,程序會阻塞, 等待連接
// 如果有客戶端連接,則會返回Socket 對象,程序繼續(xù)
Socket socket = serverSocket.accept();
System.out.println("服務(wù)端socket=" + socket.getClass());
//3. 通過socket.getInputStream() 讀取客戶端寫入到數(shù)據(jù)通道的數(shù)據(jù), 顯示
InputStream inputStream = socket.getInputStream();
//4. IO 讀取, 使用字符流, 使用InputStreamReader 將inputStream 轉(zhuǎn)成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5. 通過輸出流,寫入數(shù)據(jù)到數(shù)據(jù)通道
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("服務(wù)端說:你好,客戶端!");
// 設(shè)置結(jié)束標(biāo)記
bufferedWriter.newLine();// 插入一個換行符,表示回復(fù)內(nèi)容的結(jié)束
bufferedWriter.flush();//注意需要手動的flush
//6.關(guān)閉流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出.....");
}
}
客戶端
package com.jwt.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class SocketTCP02Server {
public static void main(String[] args) throws IOException {
//1. 監(jiān)聽本機(jī)的9999 端口, 等待連接
// 細(xì)節(jié): 要求在本機(jī)沒有其它服務(wù)在監(jiān)聽9999
// 細(xì)節(jié):這個ServerSocket 可以通過accept() 返回多個Socket[多個客戶端連接服務(wù)器的并發(fā)]
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("我是服務(wù)端,正在監(jiān)聽9999端口,等待連接...");
//2. 當(dāng)沒有客戶端連接9999 端口時,程序會阻塞, 等待連接
// 如果有客戶端連接,則會返回Socket 對象,程序繼續(xù)
Socket socket = serverSocket.accept();
System.out.println("服務(wù)端socket=" + socket.getClass());
//3. 通過socket.getInputStream() 讀取客戶端寫入到數(shù)據(jù)通道的數(shù)據(jù), 顯示
InputStream inputStream = socket.getInputStream();
//4. IO 讀取, 使用字符流, 使用InputStreamReader 將inputStream 轉(zhuǎn)成字符流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String s = bufferedReader.readLine();
System.out.println(s);
//5. 通過輸出流,寫入數(shù)據(jù)到數(shù)據(jù)通道
OutputStream outputStream = socket.getOutputStream();
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(outputStream));
bufferedWriter.write("服務(wù)端說:你好,客戶端!");
// 設(shè)置結(jié)束標(biāo)記
bufferedWriter.newLine();// 插入一個換行符,表示回復(fù)內(nèi)容的結(jié)束
bufferedWriter.flush();//注意需要手動的flush
//6.關(guān)閉流和socket
bufferedWriter.close();
bufferedReader.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出.....");
}
}
例子3:文件傳輸
- 1.編寫一個服務(wù)端和一個客戶端
- 2.服務(wù)器端在 8888 端口監(jiān)聽
- 3.客戶端連接到服務(wù)端,發(fā)送一張圖片 /Users/jianjian/Downloads/a.jpeg
- 4.服務(wù)器端接收到客戶端發(fā)送的圖片,保存到 src 下,發(fā)送”收到圖片”再退出
- 5.客戶端接收到服務(wù)端發(fā)送的”收到圖片”,再退出
- 6.該程序要求使用 StreamUtils.java,我們直接使用
服務(wù)端
package com.jwt.socket;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPFileUploadServer {
public static void main(String[] args) throws Exception {
//1. 服務(wù)端在本機(jī)監(jiān)聽8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服務(wù)端監(jiān)聽8888端口....");
//2. 等待連接
Socket socket = serverSocket.accept();
//3. 讀取客戶端發(fā)送的數(shù)據(jù),通過Socket 得到輸入流
System.out.println("服務(wù)端開始接收圖片");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
//4. 將得到bytes 數(shù)組,寫入到指定的路徑,就得到一個文件了
String destFilePath = "src//a.jpeg";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.flush();
System.out.println("服務(wù)端接收圖片成功");
//5.向客戶端回復(fù)"收到圖片"通過socket 獲取到輸出流(字符)
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write("服務(wù)端:收到圖片");
bw.flush();//把內(nèi)容刷新到數(shù)據(jù)通道
socket.shutdownOutput();//設(shè)置寫入結(jié)束標(biāo)記
//6.關(guān)閉其他資源
bw.close();
bos.close();
bis.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出.....");
}
}
/**
服務(wù)端監(jiān)聽8888端口....
服務(wù)端開始接收圖片
服務(wù)端接收圖片成功
服務(wù)端退出.....
**/
客戶端
package com.jwt.socket;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
public class TCPFileUploadClient {
public static void main(String[] args) throws Exception {
//1.客戶端連接服務(wù)端8888,得到Socket 對象
Socket socket = new Socket(InetAddress.getLocalHost(), 8888);
//2.創(chuàng)建讀取磁盤文件的輸入流
System.out.println("客戶端開始發(fā)送圖片");
String filePath = "/Users/jianjian/Downloads/a.jpeg";
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
//bytes 就是filePath 對應(yīng)的字節(jié)數(shù)組
byte[] bytes = StreamUtils.streamToByteArray(bis);
//3.通過socket 獲取到輸出流, 將bytes 數(shù)據(jù)發(fā)送給服務(wù)端
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bos.flush();
socket.shutdownOutput();//設(shè)置寫入數(shù)據(jù)的結(jié)束標(biāo)記
System.out.println("客戶端發(fā)送圖片成功");
//4.接收從服務(wù)端回復(fù)的消息
InputStream inputStream = socket.getInputStream();
//使用StreamUtils 的方法,直接將inputStream 讀取到的內(nèi)容轉(zhuǎn)成字符串
String s = StreamUtils.streamToString(inputStream);
System.out.println(s);
//5.關(guān)閉相關(guān)的流
inputStream.close();
bos.close();
bis.close();
socket.close();
System.out.println("客戶端退出.....");
}
}
/**
客戶端開始發(fā)送圖片
客戶端發(fā)送圖片成功
服務(wù)端:收到圖片
客戶端退出.....
**/
UDP編程
簡介
- 類 DatagramSocket 和 DatagramPacket [數(shù)據(jù)包/數(shù)據(jù)報]實現(xiàn)了基于 UDP 協(xié)議網(wǎng)絡(luò)程序。
- UDP 數(shù)據(jù)報通過數(shù)據(jù)報套接字 DatagramSocket 發(fā)送和接收,系統(tǒng)不保證 UDP 數(shù)據(jù)報一定能夠安全送到目的地,也不能確定什么時候可以抵達(dá)。
- DatagramPacket 對象封裝了 UDP 數(shù)據(jù)報,在數(shù)據(jù)報中包含了發(fā)送端的IP地址和端口號以及接收端的IP地址和端口號。
- UDP協(xié)議中每個數(shù)據(jù)報都給出了完整的地址信息,因此無須建立發(fā)送方和接收方的連接
流程
UDP,以數(shù)據(jù)報作為數(shù)據(jù)的傳輸載體,在進(jìn)行傳輸時首先要把傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(Datagram),在數(shù)據(jù)報中指明數(shù)據(jù)要到達(dá)的Socket(主機(jī)地址和端口號),然后再將數(shù)據(jù)以數(shù)據(jù)報的形式發(fā)送出去,然后就沒有然后了,服務(wù)端收不收到我就不知道了,除非服務(wù)端收到后又給我回一段確認(rèn)的數(shù)據(jù)報。
接收端編寫
-
Step 1:創(chuàng)建DatagramSocket,指定端口號
- DatagramSocket socket = new DatagramSocket(9999);
-
Step 2:創(chuàng)建DatagramPacket
- DatagramPacket packet = new DatagramPacket(buf,buf.length);
-
Step 3:接收發(fā)送端發(fā)送的數(shù)據(jù)信息
- socket.receive(packet);
-
Step 4:讀取數(shù)據(jù)
- packet.getLength();
- packet.getData();
-
Step 5:關(guān)閉相關(guān)資源
- socket.close();
發(fā)送端編寫
-
Step 1:定義發(fā)送信息
- byte[] data = “發(fā)送端:hello 明天吃火鍋~”.getBytes();
-
Step 2:創(chuàng)建DatagramPacket,包含將要發(fā)送的信息
- DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName(“jianjian”), 9999);
-
Step 3:創(chuàng)建DatagramSocket
- DatagramSocket socket = new DatagramSocket(9998);
-
Step 4:發(fā)送數(shù)據(jù)
- socket.send(packet);
-
Step 5:關(guān)閉相關(guān)資源
- socket.close();
例子:接受端發(fā)送端通信
- 1.編寫一個接收端 A 和一個發(fā)送端 B
- 2.接收端 A 在 9999 端口等待接收數(shù)據(jù)
- 3.發(fā)送端 B 向接收端 A 發(fā)送數(shù)據(jù)”hello ,明天吃火鍋~”
- 4.接收端 A 接收到發(fā)送端 B 發(fā)送的數(shù)據(jù),回復(fù)”好的,明天見”,再退出
- 5.發(fā)送端接收回復(fù)的數(shù)據(jù),再退出
接受端
package com.jwt.socket;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPReceiverA {
public static void main(String[] args) throws IOException {
//1. 創(chuàng)建一個DatagramSocket 對象,準(zhǔn)備在9999 接收數(shù)據(jù)
DatagramSocket socket = new DatagramSocket(9999);
//2. 構(gòu)建一個DatagramPacket 對象,準(zhǔn)備接收數(shù)據(jù)
// 一個UDP數(shù)據(jù)包最大64k
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,buf.length);
System.out.println("接收端A等待接收數(shù)據(jù)..");
//3. 調(diào)用接收方法, 將通過網(wǎng)絡(luò)傳輸?shù)腄atagramPacket 對象,填充到packet 對象
//當(dāng)有數(shù)據(jù)包發(fā)送到本機(jī)的9999 端口時,就會接收到數(shù)據(jù)
// 如果沒有數(shù)據(jù)包發(fā)送到本機(jī)的9999 端口, 就會阻塞等待.
socket.receive(packet);
//4. 把packet進(jìn)行拆包,取出數(shù)據(jù),并顯示
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data, 0, length);
System.out.println(s);
//5. 回復(fù)信息給B端,將需要發(fā)送的數(shù)據(jù),封裝到DatagramPacket 對象
data = "接收端:好的, 明天見".getBytes();
//內(nèi)容字節(jié)數(shù)組, 數(shù)組長度,主機(jī)(IP),端口
packet = new DatagramPacket(data, data.length, InetAddress.getByName("jianjian"), 9998);
socket.send(packet);
//6. 關(guān)閉資源
socket.close();
System.out.println("A 端退出...");
}
}
/**
接收端A等待接收數(shù)據(jù)..
發(fā)送端:hello 明天吃火鍋~
A 端退出...
**/
發(fā)送端
package com.jwt.socket;
import java.io.IOException;
import java.net.*;
public class UDPSenderB {
public static void main(String[] args) throws IOException {
//1.創(chuàng)建DatagramSocket 對象,準(zhǔn)備在9998 端口接收數(shù)據(jù)
DatagramSocket socket = new DatagramSocket(9998);
//2. 將需要發(fā)送的數(shù)據(jù),封裝到DatagramPacket 對象
byte[] data = "發(fā)送端:hello 明天吃火鍋~".getBytes();
DatagramPacket packet = new DatagramPacket(data, data.length, InetAddress.getByName("jianjian"), 9999);
socket.send(packet);
//3. 接收從A 端回復(fù)的信息
//(1).構(gòu)建一個DatagramPacket 對象,準(zhǔn)備接收數(shù)據(jù)
byte[] buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
//(2) 調(diào)用接收方法, 將通過網(wǎng)絡(luò)傳輸?shù)腄atagramPacket 對象,填充到packet 對象
socket.receive(packet);
//(3) 可以把packet 進(jìn)行拆包,取出數(shù)據(jù),并顯示.
int length = packet.getLength();//實際接收到的數(shù)據(jù)字節(jié)長度
data = packet.getData();//接收到數(shù)據(jù)
String s = new String(data, 0, length);
System.out.println(s);
//4. 關(guān)閉資源
socket.close();
System.out.println("B 端退出");
}
}
/**
接收端:好的, 明天見
B 端退出
**/
本章練習(xí)
1.編程題Homework01.java
- (1)使用字符流的方式,編寫一個客戶端程序和服務(wù)器端程序
- (2)客戶端發(fā)送”name”,服務(wù)器端接收到后,返回”我是nova”,nova 是你自己的名字
- (3)客戶端發(fā)送”hobby”,服務(wù)器端接收到后,返回”編寫java程序”
- (4)不是這兩個問題,回復(fù)”你說啥呢”
- 問題:目前,我們只能問一次,就退出了,怎么可以問多次? ->while ->聊天
服務(wù)端
package com.jwt.socket.homework;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Homework01Server {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("我是服務(wù)端,正在監(jiān)聽9999端口,等待連接...");
Socket socket = serverSocket.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = br.readLine();
System.out.println(s);
String answer = "";
if ("name".equals(s)) {
answer = "我是nova";
} else if("hobby".equals(s)) {
answer = "編寫java程序";
} else {
answer = "你說啥呢";
}
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(answer);
bw.flush();
socket.shutdownOutput();
bw.close();
br.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出.....");
}
}
客戶端
package com.jwt.socket.homework;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class Homework01Client {
public static void main(String[] args) throws IOException {
Socket socket = new Socket(InetAddress.getByName("jianjian"),9999);
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//從鍵盤讀取用戶的問題
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入你的問題:");
String question = scanner.next();
bw.write(question);
bw.flush();
socket.shutdownOutput();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = br.readLine();
System.out.println(s);
br.close();
bw.close();
socket.close();
System.out.println("客戶端退出.....");
}
}
2.編程題Homework02.java
- (1)編寫一個接收端A和一個發(fā)送端B,使用UDP協(xié)議完成
- (2)接收端在8888端口等待接收數(shù)據(jù)
- (3)發(fā)送端向接收端發(fā)送數(shù)據(jù)”四大名著是哪些”
- (4)接收端接收到發(fā)送端發(fā)送的問題后,返回”四大名著是<<紅樓夢>> ..”,否則返回what?
- (5)接收端和發(fā)送端程序退出
接受端
package com.jwt.socket.homework;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class Homework02ReceiverA {
//- (1)編寫一個接收端A和一個發(fā)送端B,使用UDP協(xié)議完成
//- (2)接收端在8888端口等待接收數(shù)據(jù)
//- (3)發(fā)送端向接收端發(fā)送數(shù)據(jù)"四大名著是哪些"
//- (4)接收端接收到發(fā)送端發(fā)送的問題后,返回"四大名著是<<紅樓夢>> ..”,否則返回what?
//- (5)接收端和發(fā)送端程序退出
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(8888);
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf,0,buf.length);
System.out.println("接收端A等待接收數(shù)據(jù)..");
socket.receive(packet);
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data,0,length);
System.out.println(s);
String anser = "";
if("四大名著是哪些".equals(s)){
anser = "四大名著是<<紅樓夢>>...";
} else {
anser = "What?";
}
buf = anser.getBytes();
packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("jianjian"), 9999);
socket.send(packet);
socket.close();
System.out.println("A 端退出");
}
}
發(fā)送端
package com.jwt.socket.homework;
import java.io.IOException;
import java.net.*;
import java.util.Scanner;
public class Homework02SenderB {
//- (1)編寫一個接收端A和一個發(fā)送端B,使用UDP協(xié)議完成
//- (2)接收端在8888端口等待接收數(shù)據(jù)
//- (3)發(fā)送端向接收端發(fā)送數(shù)據(jù)"四大名著是哪些"
//- (4)接收端接收到發(fā)送端發(fā)送的問題后,返回"四大名著是<<紅樓夢>> ..”,否則返回what?
//- (5)接收端和發(fā)送端程序退出
public static void main(String[] args) throws IOException {
DatagramSocket socket = new DatagramSocket(9999);
Scanner scanner = new Scanner(System.in);
System.out.println("請輸入你的問題:");
String question = scanner.next();
byte[] buf = question.getBytes();
DatagramPacket packet = new DatagramPacket(buf, buf.length, InetAddress.getByName("jianjian"), 8888);
socket.send(packet);
buf = new byte[1024];
packet = new DatagramPacket(buf, buf.length);
socket.receive(packet);
int length = packet.getLength();
byte[] data = packet.getData();
String s = new String(data, 0, length);
System.out.println(s);
socket.close();
System.out.println("B 端退出");
}
}
3.編程題Homework03.java
- (1)編寫客戶端程序和服務(wù)器端程序
- (2)客戶端可以輸入一個音樂文件名,比如高山流水,服務(wù)端收到音樂名后,可以給客戶端返回這個音樂文件,如果服務(wù)器沒有這個文件,返回一個默認(rèn)的音樂即可
- (3)客戶端收到文件后,保存到本地
- (4)提示:該程序可以使用StreamUtils.java
- 本質(zhì):其實就是指定下載文件的應(yīng)用先自己結(jié)合老師講的文件上傳來做
服務(wù)端
package com.jwt.socket.homework;
import com.jwt.socket.StreamUtils;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class Homework03Server {
public static void main(String[] args) throws Exception {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服務(wù)端監(jiān)聽9999端口....");
Socket socket = serverSocket.accept();
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String s = br.readLine();
System.out.println(s);
//發(fā)送音樂
System.out.println("服務(wù)端開始發(fā)送音樂");
String music = "";
if ("高山流水".equals(s)){
music = "高山流水.mp3";
} else {
music = "無名.mp3";
}
String filePath = "src//" + music;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(filePath));
byte[] bytes = StreamUtils.streamToByteArray(bis);
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
bos.write(bytes);
bos.flush();
socket.shutdownOutput();//設(shè)置寫入數(shù)據(jù)的結(jié)束標(biāo)記
System.out.println("客戶端發(fā)送音樂成功");
bos.close();
bis.close();
socket.close();
serverSocket.close();
System.out.println("服務(wù)端退出...");
}
}
客戶端
package com.jwt.socket.homework;
import com.jwt.socket.StreamUtils;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;
public class Homework03Client {
public static void main(String[] args) throws Exception {
Socket socket = new Socket(InetAddress.getLocalHost(), 9999);
Scanner scanner = new Scanner(System.in);
System.out.println("輸入音樂名:");
String downMusic = scanner.next();
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(downMusic);
bw.flush();
socket.shutdownOutput();
//讀取客戶端發(fā)送的數(shù)據(jù),通過Socket 得到輸入流
System.out.println("客戶端開始接收音樂");
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
byte[] bytes = StreamUtils.streamToByteArray(bis);
// 將得到bytes 數(shù)組,寫入到指定的路徑,就得到一個文件了
String destFilePath = "/Users/jianjian/Downloads/" + downMusic + ".mp3";
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destFilePath));
bos.write(bytes);
bos.flush();
System.out.println("客戶端接收音樂成功");
bos.close();
bis.close();
bw.close();
socket.close();
System.out.println("客戶端退出...");
}
}