IP 地址+端口號(hào)組成了 Socket,Socket 是網(wǎng)絡(luò)上運(yùn)行的程序之間雙向通信鏈路的終點(diǎn),是 TCP 和 UDP 的基礎(chǔ),網(wǎng)絡(luò)通信其實(shí)就是 Socket 間的通信,數(shù)據(jù)在兩個(gè) Socket 間通過 IO 傳輸
InetAddress
- 用于標(biāo)識(shí)網(wǎng)絡(luò)上的硬件資源
//獲取本機(jī)的InetAddress實(shí)例
InetAddress address = InetAddress.getLocalHost();
//獲取計(jì)算機(jī)名
address.getHostName();
//獲取IP地址
address.getHostAddress();
//獲取字節(jié)數(shù)組形式的 IP 地址,以點(diǎn)分隔的四部分
byte[] bytes = address.getAddress();
//獲取其他主機(jī)的 InetAddress 實(shí)例
InetAddress address3 = InetAddress.getByName("127.0.0.1");
URL
- 統(tǒng)一資源定位符,通過URL可以直接讀取或?qū)懭刖W(wǎng)絡(luò)的數(shù)據(jù)資源
//創(chuàng)建一個(gè) URL 的實(shí)例
URL baidu = new URL("http://www.baidu.com");
URL url = new URL(baidu, "/index.html?username=tom#test");//?表示參數(shù),#表示錨點(diǎn)
url.getProtocol();//獲取協(xié)議
url.getHost();//獲取主機(jī)
url.getPort();//如果沒有指定端口號(hào),根據(jù)協(xié)議不同使用默認(rèn)端口。此時(shí)getPort()方法的返回值為 -1
url.getPath();//獲取文件路徑
url.getFile();//文件名,包括文件路徑+參數(shù)
url.getRef();//相對(duì)路徑,就是錨點(diǎn),即#號(hào)后面的內(nèi)容
url.getQuery();//查詢字符串,即參數(shù)
- 通過 URL 對(duì)象的 openStream() 方法可以得到指定資源的輸入流,通過流能夠讀取或訪問網(wǎng)頁上的資源
URL baidu = new URL("http://www.baidu.com");
InputStream is = baidu.openStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String content = null;
while ((content = br.readLine()) != null) {
System.out.println(content);
}
br.close();
is.close();
TCP 編程
- TCP 協(xié)議是面向連接、可靠的、有序的、以字節(jié)流的方式發(fā)送數(shù)據(jù),基于 TCP 協(xié)議實(shí)現(xiàn)的網(wǎng)絡(luò)通信,通信模型流程如下

TCP通信流程
客戶端 Socket
- 客戶端的 Socket 類,需指明要連接的服務(wù)器地址和端口號(hào),建立連接后通過輸入、輸出流發(fā)送和響應(yīng)信息
public class Client {
public static void main(String[] args) {
try (Socket socket = new Socket("127.0.0.1",8999)){
// 像服務(wù)器端發(fā)送信息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("我是客戶端 linyuan");
pw.flush();
// 接收服務(wù)器端消息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String message = null;
while ((message = br.readLine()) != null) {
System.out.println("服務(wù)器說:" + message);
}
// 關(guān)閉資源.....
pw.close();
os.close();
is.close();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
服務(wù)器端 ServerSocket
- 創(chuàng)建服務(wù)器端 ServerSocket 并綁定端口,通過 accept() 方法監(jiān)聽客戶端請(qǐng)求,建立連接后通過輸入、輸出流發(fā)送和響應(yīng)信息
public class Server {
public static void main(String[] args) {
try (ServerSocket serverSocket = new ServerSocket(8999)) {
System.out.println("服務(wù)器啟動(dòng)................");
while (true) {
// 監(jiān)聽客戶端連接
Socket socket = serverSocket.accept();
// 接收客戶端消息
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String message;
while ((message = br.readLine()) != null) {
System.out.println("客戶端說:" + message);
}
// 向客戶端發(fā)送消息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("歡迎加入 xxx 服務(wù)器.........");
pw.flush();
// 關(guān)閉資源.....
br.close();
is.close();
pw.close();
os.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
UDP 編程
- UDP 協(xié)議(用戶數(shù)據(jù)報(bào)協(xié)議)是無連接的、不可靠的、無序的,速度快
- 進(jìn)行數(shù)據(jù)傳輸時(shí),首先將要傳輸?shù)臄?shù)據(jù)定義成數(shù)據(jù)報(bào)(DatagramPacket),大小限制在 64k,并指名要發(fā)送的地址 Socket(主機(jī)地址和端口號(hào)),然后再將數(shù)據(jù)報(bào)發(fā)送出去
服務(wù)器端實(shí)現(xiàn)
- 創(chuàng)建 DatagramSocket 并綁定端口,創(chuàng)建 DatagramPacket 并調(diào)用 receive 方法接收客戶端發(fā)送的數(shù)據(jù)報(bào)(該方法會(huì)阻塞到接收到數(shù)據(jù)報(bào)為止),讀取數(shù)據(jù)
public class Server {
public static void main(String[] args) {
try{
byte[] data = new byte[1024];
// 接收客戶端數(shù)據(jù)報(bào)
DatagramSocket socket = new DatagramSocket(10000);
DatagramPacket rPacket = new DatagramPacket(data,0,data.length);
socket.receive(rPacket);
String info = new String(data,0,rPacket.getLength());
System.out.println("客戶端發(fā)送內(nèi)容:"+info);
// 響應(yīng)客戶端
InetSocketAddress socketAddress = new InetSocketAddress(rPacket.getAddress(),rPacket.getPort());
data = "新的一天!".getBytes();
DatagramPacket sPacket = new DatagramPacket(data,0,data.length,socketAddress);
socket.send(sPacket);
socket.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
客戶端實(shí)現(xiàn)
- 定義要發(fā)送的消息,創(chuàng)建 DatagramPacket,通過 DatagramSocket 發(fā)送數(shù)據(jù)
public class Client {
public static void main(String[] args) {
try{
InetSocketAddress socketAddress = new InetSocketAddress("localhost",10000);
byte[] data = "我是客戶端".getBytes();
DatagramPacket packet = new DatagramPacket(data,0,data.length,socketAddress);
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
}catch (Exception e){
e.printStackTrace();
}
}
}