網絡基礎
通信必備條件.png
- 端口:區別是電腦上的哪個進程發出的通信請求(0 ~ 65535,其中1~1023系統保留)
http:80 ftp:21 telnet:23 - 協議:通信過程所使用的語言(TCP/IP)
- IP地址:互聯網中的唯一標識
IP+端口號 組成了Socket。Socket是網絡上運行的程序之間雙向通信鏈路的終結點,是TCP和UDP的基礎。
JAVA中的網絡支持
針對網絡通信的不同層次,java提供的網絡功能分為四大類
- InetAddress:用于標識網絡上的硬件資源,類IP地址。
- URL:統一資源定位符 通過URL可以直接讀取和寫入網絡上的數據。
- Sockets:使用TCP協議實現網絡通信的Socket相關的類。
- Datagram:使用UDP協議,將數據保存在數據報中,通過網絡進行通訊。
InetAddress類
無構造方法,無法通過new的方法創造對象。有很多靜態方法,可以返回該類。
public void useInetAddress(){
try {
// 獲取本機的InetAddress
InetAddress inetAddress = InetAddress.getLocalHost();
System.out.println("計算機名" + inetAddress.getHostName());
System.out.println("計算機IP" + inetAddress.getHostAddress());
System.out.println(inetAddress);
// 其它獲取inetAddress的方式
// InetAddress inetAddress2 = InetAddress.getByName("Edwin");
// InetAddress inetAddress3 = InetAddress.getByName("1.1.1.10");
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
URL類
public void useURL(){
try {
// 創建URL實例
URL immoc = new URL("http://www.imooc.com");
URL url = new URL(immoc,"/index.html?username=tom#test");
System.out.println("協議:"+ url.getProtocol());
System.out.println("Host:"+ url.getHost());
// 如果為指定端口號,則為-1
System.out.println("Port:" + url.getPort() );
System.out.println("filePath:" + url.getPath());
System.out.println("fileName:" + url.getFile());
System.out.println("相對路徑:"+ url.getRef());
System.out.println("查詢字符串:"+ url.getQuery());
URL baidu = new URL("http://www.baidu.com");
// 通過URL對象的openStream方法可以獲取指定資源的輸入流
InputStream inputStream = baidu.openStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream);
// 添加緩沖 提高效率
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String data = bufferedReader.readLine();
while (data!=null){
System.out.println(data);
data = bufferedReader.readLine();
}
bufferedReader.close();
inputStreamReader.close();
inputStream.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
Socket-TCP編程簡介
- 基于TCP協議實現網絡通訊的類
服務端的Socket類
客戶端的ServerSocket類
Socket通信模型.png
實現步驟:
創建serversocket 和socket
打開連接到socket的輸入/輸出流
按照協議讀寫
關閉輸入輸出流
public class ServerModel {
public static void main(String args[]){
try {
// 創建服務器端的socket,綁定指定的端口并監聽
ServerSocket serverSocket = new ServerSocket(8888);
// 調用accept監聽
System.out.println("等待客戶端鏈接");
Socket socket = serverSocket.accept();
// 獲取客戶端的信息
InputStream is = socket.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader bufferedReader = new BufferedReader(isr);
String info = null;
while ((info = bufferedReader.readLine())!=null){
System.out.println("client info : " + info);
}
socket.shutdownInput();
OutputStream outputStream = socket.getOutputStream();
PrintWriter printWriter = new PrintWriter(outputStream);
printWriter.write("welcome");
printWriter.flush();
// 關閉資源
printWriter.close();
outputStream.close();
bufferedReader.close();
isr.close();
is.close();
socket.close();
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class ClientModel {
public static void main(String args[]){
// 創建客戶端的socket,指定服務器端的地址和端口
try {
Socket socket = new Socket("localHost",8888);
// 獲取輸出流發送登陸信息
OutputStream os = socket.getOutputStream();
PrintWriter pw = new PrintWriter(os);
pw.write("userName:edwin;key:123");
pw.flush();
socket.shutdownOutput();
// 獲取輸入流來獲取服務器端的響應
InputStream inputStream = socket.getInputStream();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
String info = null;
while ((info = bufferedReader.readLine())!= null){
System.out.println("server said:"+info);
}
// 關閉資源
bufferedReader.close();
inputStream.close();
pw.close();
os.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行結果.png
運行結果.png
為上面所演示的程序添加多線程來實現多客戶端的功能
繼承線程類
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 bufferedReader = null;
OutputStream outputStream = null;
PrintWriter printWriter = null;
try {
// 獲取客戶端的信息
is = socket.getInputStream();
isr = new InputStreamReader(is);
bufferedReader = new BufferedReader(isr);
String info = null;
while ((info = bufferedReader.readLine())!=null){
System.out.println("client info : " + info);
}
socket.shutdownInput();
outputStream = socket.getOutputStream();
printWriter = new PrintWriter(outputStream);
printWriter.write("welcome");
printWriter.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 關閉資源
try{
printWriter.close();
outputStream.close();
bufferedReader.close();
isr.close();
is.close();
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
在服務器端啟動循環監聽
Socket socket = null;
int count = 0;
// 循環監聽
while (true){
socket = serverSocket.accept();
// 創建線程
ServerThread serverThread = new ServerThread(socket);
serverThread.run();
System.out.println(++count);
}
運行結果.png
Socket-UDP編程簡介
UDP無連接無序,數據封裝為數據報的形式(datagram)
- 需要用到的類:
DatagramPacket:表示數據報包
DatagramSocket:表示端到端通信的類
public class UDPServer {
public static void main(String args[]){
try {
// 創建服務器端的DatagramSocket,指定端口
DatagramSocket socket = new DatagramSocket(8800);
// 創建數據報文,由于接受服務端的數據
byte[] data = new byte[1024];
DatagramPacket packet = new DatagramPacket(data,data.length);
// 接收數據
System.out.println("服務器端啟動...");
socket.receive(packet);//此方法在接收到數據之前會一直阻塞
// 讀取數據
System.out.println("從客戶端得到的數據為:"+ new String(data));
// 向客戶端發送響應
// 定義客戶端的地址,端口等
InetAddress address = packet.getAddress();
int port = packet.getPort();
byte[] reMessage = "welcome".getBytes();
// 創建數據報
DatagramPacket rePacket = new DatagramPacket(reMessage,reMessage.length,address,port);
// 響應
socket.send(rePacket);
socket.close();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class UDPClient {
public static void main(String args[]){
try {
// 定義服務器地址
InetAddress address =InetAddress.getByName("localHost");
int port = 8800;
byte[] data = "此為服務端數據內容".getBytes();
// 創建數據報
DatagramPacket packet = new DatagramPacket(data,data.length,address,port);
// 創建socket
DatagramSocket socket = new DatagramSocket();
// 發送
socket.send(packet);
// 接收響應
byte[] reMessage = new byte[1024];
DatagramPacket repacket = new DatagramPacket(reMessage,reMessage.length);
socket.receive(repacket);
System.out.println(new String(reMessage));
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
運行結果.png
補充內容
在TCP的示例中使用了多線程來完成持續監聽來模擬多個客戶端的訪問,我們可以通過設計線程的優先級來調整程序的運行情況
...
serverThread.setPriority(4);//范圍[1,10],默認:5
...
輸出流關閉的過程中會一起關閉socket,所以不單獨進行關閉。傳輸可以以對象的形式進行,只需要使用ObjectOutputStream。