目錄
TCP/IP
TCP-傳輸控制協定
- 面向連接配接的、可靠的、基于位元組流的傳輸層通信協定
- 資料大小無限制
- 連接配接三次握手,斷開連接配接四次握手
UDP協定-使用者資料報協定
- 是一種無連接配接的傳輸層協定
- 提供面向事務的簡單不可靠資訊傳送服務,每個包的大小64KB
IP協定-網際網路協定位址
- 配置設定給物聯網裝置的唯一辨別
端口号
- 公認端口:0~1023
- 注冊端口:1024~49151
- 動态或私有端口:49152~65535
常用端口
- MySQL:3306
- Oracle:1521
- Tomcat:8080
- SMTP:25
- Web伺服器:80
- FTP伺服器:21
InetAddress類
概念:表示網際網路協定(IP)位址對象,封裝了與該IP位址相關的所有資訊,并提供擷取資訊的常用方法
// 擷取本地主機位址對象
InetAddress inetAddress = InetAddress.getLocalHost();
// 擷取IP位址字元串
System.out.println("本機IP: " + inetAddress.getHostAddress());
// 擷取主機名
System.out.println("主機名: " + inetAddress.getHostName());
// 根據IP擷取本機對象
InetAddress byName = InetAddress.getByName("10.0.139.215");
// 擷取本機對象
InetAddress localhost = InetAddress.getByName("localhost");
// 擷取本機對象
InetAddress byName1 = InetAddress.getByName("127.0.0.1");
// 測試3秒是否可達
InetAddress byName2 = InetAddress.getByName("www.baidu.com");
System.out.println("測試3秒是否可達: " + byName2.isReachable(3000));
// 擷取所有IP
InetAddress[] allByName = InetAddress.getAllByName("www.baidu.com");
for (InetAddress address : allByName) {
System.out.println(address);
}
TCP程式設計
步驟
伺服器端(接收端)
- 建立Socket連接配接,并綁定端口号
- 監聽
- 建立流
- 讀取資料
- 關閉
用戶端(發送端)
- 建立Socket連接配接,并綁定IP位址和端口号
- 建立流
- 讀取資料
- 關閉
每一端,既可以發送資料,也可以接收資料
用戶端向伺服器端發送資料
伺服器端
package com.robot.net.tcp;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
/**
* 伺服器端(TCP)。
*
* @author 張寶旭
*/
public class TcpService {
public static void main(String[] args) throws IOException {
// 1、建立Socket連接配接
ServerSocket listener = new ServerSocket(12580);
// 2、監聽
System.out.println("伺服器啟動成功,等待連接配接...");
Socket client = listener.accept();
// 3、建立接收流
InputStream inputStream = client.getInputStream();
BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream);
// 4、讀取資料
byte[] buf = new byte[1024];
int len = bufferedInputStream.read(buf);
if (len != -1) {
System.out.println(new String(buf, 0, len));
} else {
System.out.println("讀取失敗");
}
// 4、關閉
bufferedInputStream.close();
listener.close();
}
}
用戶端
package com.robot.net.tcp;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* 用戶端(TCP)。
*
* @author 張寶旭
*/
public class TcpClient {
public static void main(String[] args) throws IOException {
// 1、建立連接配接
Socket socket = new Socket("127.0.0.1", 12580);
// 2、建立流
OutputStream outputStream = socket.getOutputStream();
BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(outputStream);
// 3、發送資料
String say = "Hello";
bufferedOutputStream.write(say.getBytes());
// 4、關閉
bufferedOutputStream.close();
socket.close();
}
}
用戶端向伺服器端發送檔案
package com.robot.net.tcp;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP 傳輸檔案 伺服器端。
*
* @author 張寶旭
*/
public class FileServer {
public static void main(String[] args) throws IOException {
ServerSocket listener = new ServerSocket(12580);
Socket client = listener.accept();
InputStream inputStream = client.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream("d:myTemp\\server.jpg");
int len = 0;
byte[] buf = new byte[1024];
while ((len = inputStream.read(buf)) != -1) {
fileOutputStream.write(buf, 0, len);
}
fileOutputStream.close();
inputStream.close();
listener.close();
}
}
package com.robot.net.tcp;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
/**
* TCP 傳輸檔案 用戶端。
*
* @author 張寶旭
*/
public class FileClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("127.0.0.1", 12580);
OutputStream outputStream = socket.getOutputStream();
FileInputStream fileInputStream = new FileInputStream("d:\\myTemp\\client.jpg");
int len;
byte[] buf = new byte[1024];
while ((len = fileInputStream.read(buf)) != -1) {
outputStream.write(buf, 0, len);
}
fileInputStream.close();
outputStream.close();
socket.close();
}
}
伺服器端與用戶端互發消息
package com.robot.net.tcp;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
/**
* TCP 伺服器端與用戶端互發消息 伺服器端。
*
* @author 張寶旭
*/
public class TcpService {
public static void main(String[] args) throws IOException {
// 1、建立Socket連接配接
ServerSocket listener = new ServerSocket(12580);
// 2、監聽
System.out.println("伺服器啟動成功,等待連接配接...");
Socket client = listener.accept();
// 3、建立流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(client.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
// 4、讀取資料
String say = bufferedReader.readLine();
System.out.println("Client: " + say);
// 回複資訊
String reply = "I am Server";
bufferedWriter.write(reply);
bufferedWriter.newLine();
bufferedWriter.flush();
System.out.println("Server: " + reply);
// 4、關閉
bufferedWriter.close();
bufferedReader.close();
listener.close();
}
}
package com.robot.net.tcp;
import java.io.*;
import java.net.Socket;
/**
* TCP 伺服器端與用戶端互發消息 用戶端。
*
* @author 張寶旭
*/
public class TcpClient {
public static void main(String[] args) throws IOException {
// 1、建立連接配接
Socket socket = new Socket("127.0.0.1", 12580);
// 2、建立流
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
BufferedWriter bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
// 3、發送資料
String say = "I am Client";
bufferedWriter.write(say);
bufferedWriter.newLine();
bufferedWriter.flush();
System.out.println("Client: " + say);
// 接收資料
String reply = bufferedReader.readLine();
System.out.println("Server: " + reply);
// 4、關閉
bufferedWriter.close();
bufferedReader.close();
socket.close();
}
}
網絡聊天室
實作效果
多個用戶端可以連接配接同一個伺服器端,并發送消息,全部消息在伺服器端顯示
使用者類,存儲使用者資訊
package com.robot.net.chat;
/**
* 使用者類。
*
* @author 張寶旭
*/
public class User {
private String name;
private int age;
private String gender;
public User() {
}
public User(String name, int age, String gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", gender='" + gender + '\'' +
'}';
}
}
工具類
可根據IP位址,在存儲使用者的map中查找此IP的使用者,并傳回
package com.robot.net.chat;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author 張寶旭
*/
public class Tool {
/**
* 根據IP位址,查找使用者
* @param map 使用者集合
* @param ip IP位址
* @return 查找到的使用者
*/
public static User getUserBuIp(ConcurrentHashMap<String, User> map, String ip) {
for (Map.Entry<String, User> entry : map.entrySet()) {
if (entry.getKey().equals(ip)) {
return entry.getValue();
}
}
return null;
}
}
伺服器端
所有用戶端的聊天都會傳輸到伺服器端,每個用戶端使用者需要提前加入到群聊中,才可聊天。
package com.robot.net.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* TCP 網絡聊天室 伺服器端。
* 所有用戶端的聊天都會傳輸到伺服器端。
* 每個用戶端使用者需要提前加入到群聊中,才可聊天。
*
* @author 張寶旭
*/
public class Server {
public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
// 鍵:IP位址,值:使用者
ConcurrentHashMap<String, User> map = new ConcurrentHashMap<>();
// 臨時初始化一個使用者
map.put("127.0.0.1", new User("zbx", 21, "男"));
ServerSocket listener = null;
try {
// 建立Socket
listener = new ServerSocket(12580);
System.out.println("伺服器啟動成功");
// 擷取多個連接配接,每個連接配接開啟一個線程去接收
while (true) {
Socket client = listener.accept();
// 根據IP位址,查找使用者
User user = Tool.getUserBuIp(map, client.getInetAddress().getHostAddress());
if (user == null) {
System.out.println(client.getInetAddress().getHostAddress() + " 連接配接失敗,群裡沒有此使用者");
} else {
System.out.println(user.getName() + " 加入聊天");
pool.submit(new Reply(user, client));
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
assert listener != null;
listener.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
伺服器端處理資料的線程
伺服器端每次收到一個用戶端的請求連接配接,就會建立一個線程來執行任務
package com.robot.net.chat;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Socket;
/**
* 伺服器端負責接收處理資料的線程。
*
* @author 張寶旭
*/
public class Reply implements Runnable {
Socket socket = null;
BufferedReader bufferedReader = null;
User user;
public Reply() {
}
public Reply(User user, Socket socket) {
this.socket = socket;
this.user = user;
}
@Override
public void run() {
try {
// 擷取流
bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
// 讀取資料
while (true) {
// 讀取消息
String receive = bufferedReader.readLine();
if (receive == null) {
System.out.println(user.getName() + "異常退出");
break;
}
// 結束條件
if (receive.equals("bye")) {
System.out.println(user.getName() + "退出聊天");
break;
}
// 列印資料
System.out.println(user.getName() + "--->" + receive);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
用戶端
向伺服器端發送消息
package com.robot.net.chat;
import java.io.*;
import java.net.Socket;
import java.util.Scanner;
/**
* TCP 網絡聊天室 用戶端。
*
* @author 張寶旭
*/
public class Client {
public static void main(String[] args) {
Socket socket = null;
BufferedWriter bufferedWriter = null;
try {
socket = new Socket("127.0.0.1", 12580);
bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
Scanner scanner = new Scanner(System.in);
// 可以連續發送消息
while (true) {
String say = scanner.next();
bufferedWriter.write(say);
bufferedWriter.newLine();
bufferedWriter.flush();
System.out.println("client::" + say);
if (say.equals("bye")) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
assert bufferedWriter != null;
bufferedWriter.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
UDP程式設計
步驟
伺服器端(接收端)
- 建立Socket,并綁定端口号
- 建立資料報包
- 接收資料
- 處理資料
- 關閉
用戶端(發送端)
- 建立Socket
- 建立資料報包,并綁定發送IP和端口号
- 發送資料
- 關閉
每一端,既可以發送資料,也可以接收資料
用戶端向伺服器端發送資料
伺服器端
package com.robot.net.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* @author 張寶旭
*/
public class receive {
public static void main(String[] args) throws IOException {
// 建立Socket,并綁定端口号
DatagramSocket datagramSocket = new DatagramSocket(6666);
// 建立緩沖區
byte[] buf = new byte[1024];
// 建立資料報包
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length);
// 接收資料
datagramSocket.receive(datagramPacket);
// 擷取資料
byte[] data = datagramPacket.getData();
// 列印資料
System.out.println(new String(data, 0, data.length));
// 關閉
datagramSocket.close();
}
}
用戶端
package com.robot.net.udp;
import java.io.IOException;
import java.net.*;
/**
* @author 張寶旭
*/
public class Send {
public static void main(String[] args) throws IOException {
// 建立Socket
DatagramSocket datagramSocket = new DatagramSocket();
// 建立要發送的資料,并轉換為位元組
byte[] buf = "Hello".getBytes();
// 建立資料報包,并綁定發送IP和端口号
DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length, InetAddress.getByName("127.0.0.1"), 6666);
// 發送資料
datagramSocket.send(datagramPacket);
// 關閉
datagramSocket.close();
}
}
網絡聊天室
實作效果
一個伺服器端可以連接配接多個用戶端,每個用戶端都可以向伺服器端發送消息, 并顯示在伺服器端
伺服器端
package com.robot.net.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
/**
* UDP 網絡聊天室 伺服器端。
* @author 張寶旭
*/
public class ChatReceive {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket(8899);
System.out.println("聊天室啟動");
while (true) {
byte[] buf = new byte[1024];
DatagramPacket packet = new DatagramPacket(buf, buf.length);
datagramSocket.receive(packet);
byte[] data = packet.getData();
System.out.println(packet.getAddress().getHostAddress() + "::" +new String(data, 0, data.length));
}
} catch (IOException e) {
e.printStackTrace();
} finally {
assert datagramSocket != null;
datagramSocket.close();
}
}
}
用戶端
package com.robot.net.udp;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;
/**
* @author 張寶旭
*/
public class ChatSend {
public static void main(String[] args) {
DatagramSocket datagramSocket = null;
try {
datagramSocket = new DatagramSocket();
Scanner scanner = new Scanner(System.in);
while (true) {
System.out.println("輸入消息,回車發送");
String next = scanner.next();
DatagramPacket packet = new DatagramPacket(next.getBytes(), next.getBytes().length,
InetAddress.getByName("10.0.139.255"), 8899);
datagramSocket.send(packet);
System.out.println("發送成功");
if (next.equals("bye")) {
System.out.println("退出聊天");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
assert datagramSocket != null;
datagramSocket.close();
}
}
}
anner = new Scanner(System.in);
while (true) {
System.out.println("輸入消息,回車發送");
String next = scanner.next();
DatagramPacket packet = new DatagramPacket(next.getBytes(), next.getBytes().length,
InetAddress.getByName("10.0.139.255"), 8899);
datagramSocket.send(packet);
System.out.println("發送成功");
if (next.equals("bye")) {
System.out.println("退出聊天");
break;
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
assert datagramSocket != null;
datagramSocket.close();
}
}
}