網絡基礎
- 端口號范圍0-65535,系統保留0-1023,常見端口http:80,ftp:21,telnet:23
- socket=ip+端口
- java主要分為InetAdress,URL,Socket(TCP),DatagramSocket(UDP)等類
InetAddress類
InetAddress類沒有構造方法,可以通過靜態方法獲取InetAddress實例對象。
- 獲取本地主機:getLocalHost()
- 通過主機名獲取實例:getByName(String Host)
- 對實例操作:getHostName()獲取主機名,getHostAddress()獲取主機ip地址,getAddress()以字節數組的形式返回ip地址
測試:
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Arrays;
public class Test{
public static void main(String[] args) throws UnknownHostException{
//獲取本機名
InetAddress address=InetAddress.getLocalHost();
System.out.println(address.getHostName());//輸出主機名
System.out.println(address.getHostAddress());//輸出主機ip地址
byte[] bytes=address.getAddress(); //用字節數組表示ip地址
System.out.println(Arrays.toString(bytes));
//通過主機名獲取
InetAddress address2=InetAddress.getByName("你們的大神");//通過名字獲取,name可為主機名或者ip地址
//InetAddress address2=InetAddress.getByName("baidu.com");
//InetAddress address2=InetAddress.getByName("192.168.0.109");
System.out.println(address2.getHostName());
System.out.println(address2.getHostAddress());
byte[] bytes2=address2.getAddress();
System.out.println(Arrays.toString(bytes2));
}
}
URL類
常用構造方法:
- URL(String spec)
- URL(String protocol, String host, int port,String file)
- URL(URL context, String spec) 通過已存在的URL構建
常用get方法:
getRef()獲取錨點,getQuery()獲取查詢字符串,getPort()獲取端口號(未指定默認為-1,而瀏覽器默認為80),其他的見測試用例。
測試:
import java.net.MalformedURLException;
import java.net.URL;
public class Test {
public static void main(String[] args) throws MalformedURLException {
URL imooc = new URL("http://www.imooc.com"); // 直接創建
URL url = new URL(imooc, "/index.html?username=tom#test");// 根據已存在的創建,?表示參數,#表示錨點
System.out.println(url.getProtocol());
System.out.println(url.getHost());
System.out.println(url.getPort()); //如未指定,則返回-1;
System.out.println(url.getPath());
System.out.println(url.getFile());
System.out.println(url.getRef()); //錨點
System.out.println(url.getQuery()); //查詢字符串
}
}
結果:
http
www.imooc.com
-1
/index.html
/index.html?username=tom
test
username=tom
獲取頁面內容
使用openStream()獲取字節輸入流。
測試:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
//通過URL獲取頁面內容
public class Test {
public static void main(String[] args) throws IOException {
URL url=new URL("http://www.baidu.com");
InputStream is=url.openStream();//使用openStream獲取字節輸入流
InputStreamReader isr=new InputStreamReader(is,"utf-8");//在字節到字符流時需要指定編碼方式,避免亂碼
BufferedReader br=new BufferedReader(isr); //添加緩沖流
String data=br.readLine();
while (data!=null){
System.out.println(data);
data=br.readLine();
}
}
}
Socket TCP通信
流程
創建ServerSocket和Socket,打開輸入輸出流,進行操作讀寫操作,關閉輸入輸出流,關閉socket。
具體
- ServerServer類是服務端socket,偵聽客戶端的請求。
常用構造:ServerSocket(int port)
常用實例方法:accept(),close(),getInetAddress(),getPort() - Socket類是通信的端點。
常用構造:Socket(InetAddress address,int port)或Socket(String host,int port)
常用實例方法:getInetAddress(),close()
getInputStream(),getOutputStream(),shutdownInput(),shutdownOutput() - 多線程服務器,可以接受多個客戶端的請求,創建一個線程類,完成對客戶端的操作。
測試
Server.java (服務器)
import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
public class Server {
public static void main(String[] args) throws IOException {
// 1.創建服務器ServerSocket,綁定端口
ServerSocket serverSocket = new ServerSocket(8888);
// 2.使用accept偵聽,偵聽來自客戶端的連接
System.out.println("****服務器正在啟動,偵聽連接****");
int count=0;
Socket socket;
while (true) {
socket = serverSocket.accept();
ServerThread serverThread = new ServerThread(socket);
serverThread.start();
count++;
System.out.println("client number:"+count);
InetAddress address=socket.getInetAddress();
System.out.println("client address:"+address.getHostAddress());
}
// serverSocket.close();不會執行到這一步,一直循環,去掉該語句。
}
}
ServerThread.java (服務器線程)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
public class ServerThread extends Thread {
Socket socket = null;
public ServerThread(Socket socket) {
this.socket = socket;
}
public void run() {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
OutputStream os = null;
PrintWriter pw = null;
try {
is = socket.getInputStream();
isr = new InputStreamReader(is);
br = new BufferedReader(isr); // 添加緩沖流
String data = null;
while ((data = br.readLine()) != null) {
System.out.println("我是服務端,客戶端說:" + data);
}
socket.shutdownInput(); // 關閉socket的輸入流
os = socket.getOutputStream();
pw = new PrintWriter(os);
pw.write("hello");
pw.flush();
socket.shutdownOutput();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (pw != null)
pw.close();
if (os != null)
os.close();
if (br != null)
br.close();
if (isr != null)
isr.close();
if (is != null)
is.close();
if (socket != null)
socket.close();
} catch (IOException e2) {
// TODO: handle exception
e2.printStackTrace();
}
}
}
}
Client.java (客戶端)
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class Client {
public static void main(String[] args) throws UnknownHostException, IOException {
//1.創建客戶端socket,指定服務器地址和端口
Socket socket=new Socket("localhost", 8888);//本地服務器的8888端口
//2. 獲取輸出流,發送信息
OutputStream os=socket.getOutputStream();
PrintWriter pw=new PrintWriter(os);
pw.write("admin:456");
pw.flush();
socket.shutdownOutput();
// 3. 獲取輸入流,接收信息
InputStream is=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr); //添加緩沖流
String data=null;
while((data=br.readLine())!=null){
System.out.println("我是客戶端,服務端說:"+data);
}
socket.shutdownInput(); //關閉socket的輸入流
//3.關閉資源
is.close();
isr.close();
br.close();
pw.close();
os.close();
socket.close();
}
}
Socket UDP通信
流程
客戶端和服務器創建DatagramPacket保存相應數據,創建DatagramSocket,使用DatagramSocket實例的send(),receive()方法來進行通信
具體
- DatagramPacket類是UDP用來發送的數據報,UDP無連接,所以數據中可以包含ip地址,端口號等。另外,需要另外定義一個byte[]類型的數組,用來存放數據,這個數組與DatagramPacket實例實質上是同一個。
- DatagramSocket類是用來發送或者接受數據報的,主要使用該實例的receive(DatagramPacket packet)和send(DatagramPacket packet)方法,分別把數據存放在packet中的數組中(自己另外定義的),以及相關信息。
- 也可以用多線程服務器。
測試
UDPserver.java(UDP服務器)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPServer {
public static void main(String[] args) throws IOException {
// 1. 創建服務器端datagramsocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
// 2. 創建數據報,用于接受客戶端發送的數據
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data, 0, data.length);
// 3.接受客戶端發送的數據,存放在packet
System.out.println("***服務器正在啟動***");
socket.receive(packet);
// 4.讀取數據
String info = new String(data, 0, packet.getLength());
System.out.println("i'm server,client say:" + info);
// 數據,發送至客戶端
// 1.得到客戶端地址,端口,數據
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] data2 = "hello".getBytes();
// 2.創建數據報
DatagramPacket packet2 = new DatagramPacket(data2, data2.length, address, port);
// 3.響應客戶端
socket.send(packet2);
// 4.關閉資源
socket.close();
}
}
UDPclient(客戶端)
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UDPClient {
public static void main(String[] args) throws IOException {
// 1.定義服務器的地址,端口,數據
InetAddress address = InetAddress.getByName("localhost");
int port = 8800;
byte[] data = "admin:123".getBytes();
// 2.創建數據報,包含信息
DatagramPacket packet = new DatagramPacket(data, data.length, address, port);
// 3.創建DatagramSocket對象
DatagramSocket socket = new DatagramSocket();
socket.send(packet);
// 接受來自服務器數據
byte[] data2 = new byte[1024];
DatagramPacket packet2 = new DatagramPacket(data2, 0, data2.length);
// 3.接受客戶端發送的數據,存放在packet
socket.receive(packet2);
// 4.讀取數據
String info = new String(data2, 0, packet2.getLength());
System.out.println("i'm client,server say:" + info);
}
}