Java網(wǎng)絡(luò)編程
-
網(wǎng)絡(luò)編程:指編寫運行在多個設(shè)備(計算機(jī))的程序,這些設(shè)備都通過網(wǎng)絡(luò)連接起來。
URL處理:http://www.baidu.com/search?code=Android&type=1
- URL(Uniform Resource Locator)中文名為統(tǒng)一資源定位符,有時也被俗稱為網(wǎng)頁地址。
- http/https :傳輸協(xié)議 TCP/IP協(xié)議
- www.baidu.com :域名表示一臺網(wǎng)絡(luò)中的電腦
(ipv4 ipv6 )IP地址:唯一標(biāo)識一臺網(wǎng)絡(luò)中的計算機(jī)
?? ?? ?? ?? 32位:4個部分 每部分8個字節(jié)- DNS服務(wù)器:域名解析 將www.baidu.com的域名解析為對應(yīng)的IP地址
- search:對應(yīng)的后天程序文件 php java jsp
- ? 表示運行這個程序需要傳遞的參數(shù)
- code=Android code是服務(wù)器端規(guī)定的字段
- & 如果有多個參數(shù)使用&連接
ps:查找自己的電腦IP:win+R進(jìn)入DOS窗口輸入ifconfig即可
-
數(shù)據(jù)傳輸主要通過TCP/IP協(xié)議,以下是兩種常見的協(xié)議:
TCP(安全):TCP 是傳輸控制協(xié)議的縮寫,它保障了兩個應(yīng)用程序之間的可靠通信。通常用于互聯(lián)網(wǎng)協(xié)議,被稱 TCP / IP。
UDP(不安全,但是快):UDP 是用戶數(shù)據(jù)報協(xié)議的縮寫,一個無連接的協(xié)議。提供了應(yīng)用程序之間要發(fā)送的數(shù)據(jù)的數(shù)據(jù)包。
Socket 編程
相關(guān)概念
-
IP地址:唯一標(biāo)識某一臺電腦
-
端口號:唯一標(biāo)識電腦上的某一個進(jìn)程(程序)80
-
Socket類:客戶端 手機(jī)應(yīng)用、瀏覽器等
-
ServerSocket:服務(wù)器端 存儲、處理數(shù)據(jù)

使用方法:
- 讀取數(shù)據(jù):客戶端讀取 服務(wù)器端讀取
BufferedReader->InputStreamReader->socket.getInputStream() - 讀取終端
BufferedReader->InputStreamReader->System.in - 輸出:客戶端輸出 服務(wù)器端輸出
BufferedWriter->OutputStreamWriter->serverSocket.getOutputStream()
PrintStream(socket.getOutputStream)
1. 實現(xiàn)客戶端和服務(wù)器端傳遞數(shù)據(jù)(注意端?號必須相同 先運?Server 再運?Client)
客戶端:(1)創(chuàng)建用于通信的Socket,指明IP地址與端口號。
????????(2)使用BufferedReader用循環(huán)接收服務(wù)器端的數(shù)據(jù)。
????????(3)使用PrintStream向服務(wù)器端發(fā)送數(shù)據(jù),并告訴發(fā)送完成socket.shutdownOutput()。
服務(wù)器端:(1)創(chuàng)建服務(wù)器端的ServerSocket,并指明端口。
??????????(2)用serverSocket.accept()獲取連接客戶端的socket。
??????????(3)用PrintStream向客戶端發(fā)送數(shù)據(jù),完成時使用serverSocket.shutdownOutput()
??????????(4)使用BufferedReader接收客戶端發(fā)來的數(shù)據(jù)
模擬客戶端:
//模擬客戶端
//10.129.49.204
class Client{
public static void main(String[] args) throws IOException {
// 1.創(chuàng)建用于通信的Socket
// 指明和誰通信:IP地址 端口號
Socket socket = new Socket("10.129.25.52",8989);
//接收服務(wù)器端發(fā)來的數(shù)據(jù)
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 向服務(wù)器端發(fā)送數(shù)據(jù)
// socket.getOutputStream();
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
//客戶端向服務(wù)器端發(fā)送數(shù)據(jù)
PrintStream ps = new PrintStream(socket.getOutputStream());
ps.println("你好啊!!!");
socket.shutdownOutput();
}
}
模擬服務(wù)器端:
class Server{
public static void main(String[] args) throws IOException {
//1.創(chuàng)建服務(wù)器的serversocket
ServerSocket ss = new ServerSocket(8989);
//2.獲取連接的客戶端的socket
Socket clientSocket = ss.accept();
//3.向客戶端發(fā)送數(shù)據(jù)
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(clientSocket.getOutputStream()));
PrintStream ps = new PrintStream(clientSocket.getOutputStream());
ps.println("登錄成功");
//輸出完畢
clientSocket.shutdownOutput();
// 4.接收客戶端發(fā)來的數(shù)據(jù)
BufferedReader br = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
}
}
2. 手動輸入內(nèi)容發(fā)送,將輸?的內(nèi)容發(fā)送給客戶端 可以?直發(fā)
異常處理:如果出現(xiàn)異常,按從小到大關(guān)閉資源
兩種方式處理異常:
- 方式1使用if判斷語句
Socket socket = null;
try {
socket = new Socket("10.129.49.204",8888);
//接收服務(wù)器端信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)出錯,請重新登錄");
}finally {
// 關(guān)閉連接
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
- 方式2
try( ServerSocket serverSocket = new ServerSocket(8888)) {
// 監(jiān)聽客戶端
Socket socket = serverSocket.accept();
// 從終端接收數(shù)據(jù)發(fā)送給客戶端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
//獲取向客戶端輸出數(shù)據(jù)的輸出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
// 發(fā)送給客戶端
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
class MyClient{
public static void main(String[] args){
//連接服務(wù)器端的socket
Socket socket = null;
try {
socket = new Socket("10.129.49.204",8888);
//接收服務(wù)器端信息
BufferedReader br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)出錯,請重新登錄");
}finally {
// 關(guān)閉連接
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class MyServer{
public static void main(String[] args){
//創(chuàng)建ServerSocket 自動關(guān)閉
try( ServerSocket serverSocket = new ServerSocket(8888)) {
// 監(jiān)聽客戶端
Socket socket = serverSocket.accept();
// 從終端接收數(shù)據(jù)發(fā)送給客戶端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
//獲取向客戶端輸出數(shù)據(jù)的輸出流
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
// 發(fā)送給客戶端
ps.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
3. 實現(xiàn)客戶端向服務(wù)器端上傳圖?(字節(jié)流)
class Client{
public static void main(String[] args) throws IOException {
//鏈接服務(wù)器端 獲取socket
Socket socket = new Socket("10.129.49.204",8080);
//創(chuàng)建服務(wù)器端對應(yīng)的輸入流 用于接受服務(wù)器端發(fā)來的數(shù)據(jù)
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
System.out.println( bufferedReader.readLine());
//向服務(wù)器端發(fā)送文件(圖片)
String path = "C:\\Users\\gyl\\Desktop\\1.jpg";
//1. 將文件寫入到內(nèi)存
FileInputStream fis = new FileInputStream(path);
// 2 .創(chuàng)建字節(jié)流 outputStream
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
byte[] buffer = new byte[1024];
int length = -1;
while ((length = fis.read(buffer)) != -1){
bos.write(buffer,0,length);
}
socket.shutdownOutput();
}
}
class Server{
public static void main(String[] args) throws IOException {
//創(chuàng)建服務(wù)器的serverSocket
ServerSocket serverSocket = new ServerSocket(8080);
//監(jiān)聽客戶端連接
//當(dāng)有客戶端來連接這個服務(wù)器 就可以得到對應(yīng)的socket
//當(dāng)沒有客戶端來連接 服務(wù)器一直在這里等待
Socket socket = serverSocket.accept();
//創(chuàng)建客戶端對應(yīng)的輸出流對象 用于向這個客戶端發(fā)送數(shù)據(jù)
PrintStream printStream = new PrintStream(socket.getOutputStream());
printStream.println("連接成功 可以發(fā)送數(shù)據(jù)了");
// 接收客戶端傳遞過來的圖片
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
//文件對應(yīng)的輸出流
String path = "D:\\AndroidStudioProjects\\JavaCourse\\Java\\src\\main\\java\\day12\\media\\1.jpg";
FileOutputStream fos = new FileOutputStream(path);
byte[] buffer = new byte[1024];
int length = -1;
while ((length = bis.read(buffer)) != -1){
fos.write(buffer,0,length);
}
}
}
4.使?多線程實現(xiàn)對聊
- 創(chuàng)建一個類實現(xiàn)Runnable接口,重寫run方法
- 創(chuàng)建一個類繼承于Thread類,重寫run方法
/**
* 客戶端和服務(wù)器端可以隨意的發(fā)送內(nèi)容
* 從終端輸入
*
* 客戶端:
* 主線程:接收終端輸入 將終端的輸入發(fā)送給服務(wù)器端
* 子線程:接收服務(wù)器端發(fā)送過來的數(shù)據(jù)
* 服務(wù)器端:
* 主線程:接收終端輸入 將終端的輸入發(fā)送給客戶端
* 子線程:接收客戶端發(fā)送過來的數(shù)據(jù)
*/
class Cilent{
public static void main(String[] args) throws IOException {
//鏈接服務(wù)器端 獲取socket
Socket socket = new Socket("10.129.49.204",8888);
// 用一個子線程處理服務(wù)器端的數(shù)據(jù)
new Thread(new ClientThread(socket)).start();
// 主線程處理終端輸入發(fā)送給服務(wù)器端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
ps.println(line);
}
}
}
/**
* 創(chuàng)建一個子線程 處理客戶端接收服務(wù)器的數(shù)據(jù)
*/
class ClientThread implements Runnable{
private Socket socket;
// 保存socket對象
public ClientThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
// 獲取服務(wù)器端的輸入流
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 讀取數(shù)據(jù)
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)出錯 請重新登錄");
System.exit(-1);
}finally {
// 出現(xiàn)異常 關(guān)閉資源 從小到大
try {
if (br != null){
br.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
class Server{
public static void main(String[] args) throws IOException {
// 創(chuàng)建服務(wù)器端
ServerSocket ss = new ServerSocket(8888);
// 獲取客戶端的socket
Socket socket = ss.accept();
// 創(chuàng)建子線程 處理客戶端輸入信息
new ServerThread(socket).start();
//終端輸入流對象
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
// 客戶端輸出流對象
PrintStream ps = new PrintStream(socket.getOutputStream());
// 讀取終端的輸入 將輸入輸出給客戶端
String line = null;
while ((line = keyin.readLine()) != null){
ps.println(line);
}
}
}
/**
* 創(chuàng)建一個子線程處理服務(wù)器端接收客戶端的書據(jù)
*/
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)異常 請重新登錄");
System.exit(-1);
}finally {
// 關(guān)閉輸入輸出流
// 關(guān)閉對應(yīng)的socket鏈接
try {
if (br != null) {
br.close();
}
if (socket != null) {
socket.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
5.實現(xiàn)群聊
- 使用ArrayList 保存每一個連接到的客戶端,并且通過循環(huán)依次將信息發(fā)送給每一個客戶端。
class Server{
// 保存每一個鏈接過來的對象
public static ArrayList<Socket> sockets = new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888);
//不停地等待客戶端來連接
while (true){
Socket socket = ss.accept();
// 當(dāng)有客戶端連接過來了就保存
sockets.add(socket);
//開啟一個線程處理每個客戶端的輸入
new ServerThread(socket).start();
}
}
}
/**
* 創(chuàng)建一個子線程處理服務(wù)器端接收客戶端的書據(jù)
*/
class ServerThread extends Thread{
private Socket socket;
public ServerThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String line = null;
while ((line = br.readLine()) != null){
// 群發(fā)消息
// 遍歷Server維護(hù)的數(shù)組
for (Socket socket:Server.sockets){
// 想socket對應(yīng)的客戶端發(fā)送信息
PrintStream s = new PrintStream(socket.getOutputStream());
s.println(line);
}
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)異常 請重新登錄");
System.exit(-1);
}finally {
// 關(guān)閉輸入輸出流
// 關(guān)閉對應(yīng)的socket鏈接
try {
if (br != null) {
br.close();
}
if (socket != null) {
socket.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
}
}
class Cilent{
public static void main(String[] args) throws IOException {
//鏈接服務(wù)器端 獲取socket
Socket socket = new Socket("10.129.49.204",8888);
// 用一個子線程處理服務(wù)器端的數(shù)據(jù)
new Thread(new ClientThread(socket)).start();
// 主線程處理終端輸入發(fā)送給服務(wù)器端
BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
PrintStream ps = new PrintStream(socket.getOutputStream());
String line = null;
while ((line = keyin.readLine()) != null){
ps.println(line);
}
}
}
/**
* 創(chuàng)建一個子線程 處理客戶端接收服務(wù)器的數(shù)據(jù)
*/
class ClientThread implements Runnable{
private Socket socket;
// 保存socket對象
public ClientThread(Socket socket){
this.socket = socket;
}
@Override
public void run() {
BufferedReader br = null;
try {
// 獲取服務(wù)器端的輸入流
br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 讀取數(shù)據(jù)
String line = null;
while ((line = br.readLine()) != null){
System.out.println(line);
}
} catch (IOException e) {
System.out.println("網(wǎng)絡(luò)出錯 請重新登錄");
System.exit(-1);
}finally {
// 出現(xiàn)異常 關(guān)閉資源 從小到大
try {
if (br != null){
br.close();
}
if (socket != null){
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
心得體會
??關(guān)于客戶端和服務(wù)器端的操作,剛開始對于輸入輸出有點繞,不過多寫了幾遍之后,就更清楚了 ,類似于模板。同時又將多線程的知識融入進(jìn)來,對知識的理解也更加深刻了。