——Http屬於應用層——
——TCP/IP屬於傳輸層——
TCP協議(傳輸控制協議)是面向連接、可靠的,以字節流方式發送數據
可以使用Socket進行網絡通信,需要雙方通信設備的IP和端口號
常見端口號http80 ftp21 telnet23
——UDP/IP屬於傳輸層——
UDP協議(用戶數據報協議)是無連接、不可靠、無序的,以數據報(Datagram)方式發送數據
相關操作類:DatagramPacket數據報包,DatagramSocket進行端到端通信的類
——Socket就是網絡上運行的兩個程序之間的雙向通信鏈路的終結點——
基於TCP協議實現網絡通信的類:客戶端的Socket和服務器的ServerSocket
——以下Socket是基於TCP/IP協議的——
Socket通信實現的步驟:
1、創建ServerSocket和Socket
2、打開連接到Socket的輸入輸出流
3、按照協議對Socket進行讀寫操作
4、關閉輸入輸出流和Socket
服務器端:
1、創建ServerSocket,綁定監聽端口
2、通過accept方法監聽客戶端請求
3、連接建立後,通過輸入流讀取客戶端發送的請求信息
4、通過輸出流向客戶端發送響應的信息
5、關閉相關資源
客戶端:
1、創建Socket,指定需要連接的服務器的地址和端口號
2、連接建立後,通過輸出流向服務器發送請求信息
3、通過輸入流獲取服務器響應的信息
4、關閉相關資源
以下例子的解釋:
服務器向客戶端發送請求;
客戶端獲取輸出流 攜帶數據"用戶名:admin;密碼:123";
服務器獲取輸入流 得到客戶端發送的數據;
服務器獲取輸出流 攜帶數據"歡迎您!";
客戶端獲取輸入流 得到服務器發送的數據;
例1:實現在服務器端獲取客戶端發送的信息,端口號8888
服務器端Server
//1、創建ServerSocket,綁定監聽端口
ServerSocket serverSocket=new ServerSocket(8888);//建議使用1024往後的端口
//2、通過accept方法監聽客戶端請求,等待客戶端的連接
System.out.println("————服務器即將開啓,等待客戶端的連接");
Socket socket=serverSocket.accept();//獲取客戶端發送的Socket實例,用於監聽
//3、連接建立後,通過輸入流讀取客戶端發送的請求信息(通過客戶端的輸入流讀取客戶端的信息)
InputStream is=socket.getInputStream();//獲取字節輸入流InputStreamReader isr=new InputStreamReader(is);//轉換字節流爲字符流
BufferedReader br=new BufferedReader(isr);//爲字符輸入流添加緩衝
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("我是服務器,客戶端說:"+info);//循環獲取客戶端的信息
}
socket.shutdownInput();//關閉輸入流
//5、關閉相關資源
br.close();
isr.close();
is.close();
serverSocket.close();
socket.close();
客戶端Client
//1、創建Socket,指定需要連接的服務器的地址和端口號
Socket socket=new Socket("localhost",8888);
//2、連接建立後,通過輸出流向服務器發送請求信息
OutputStream os=socket.getOutputStream();//字節輸出流
PrintWriter pw=new PrintWriter(os);//將輸出流包裝爲打印流
pw.write("用戶名:admin;密碼:123");
pw.flush();//刷新緩存,向服務器端發送信息
socket.shutdownOutput();//關閉輸出流
//4、關閉相關資源
pw.close();
os.close();
socket.close();
例2:實現在服務器端獲取客戶端發送的信息並對客戶端做出響應,端口號8888
——Server結果——
——Client結果——
服務器端Server
//1、創建ServerSocket,綁定監聽端口
ServerSocket serverSocket=new ServerSocket(8888);//建議使用1024往後的端口
//2、通過accept方法監聽客戶端請求,等待客戶端的連接
System.out.println("————服務器即將開啓,等待客戶端的連接");
Socket socket=serverSocket.accept();//獲取客戶端發送的Socket實例,用於監聽
//3、連接建立後,通過輸入流讀取客戶端發送的請求信息(通過客戶端的輸入流讀取客戶端的信息)
InputStream is=socket.getInputStream();//獲取字節輸入流
InputStreamReader isr=new InputStreamReader(is);//轉換字節流爲字符流
BufferedReader br=new BufferedReader(isr);//爲字符輸入流添加緩衝
String info=null;
while ((info=br.readLine())!=null) {//循環獲取客戶端的信息
System.out.println("我是服務器,客戶端說:"+info);//info爲從客戶端獲取的信息
}
socket.shutdownInput();//關閉輸入流
//4、通過輸出流向客戶端發送響應的信息
OutputStream os=socket.getOutputStream();
PrintWriter pw=new PrintWriter(os);//與客戶端發送信息類似
pw.write("歡迎您!");
pw.flush();
//5、關閉相關資源
pw.close();
os.close();
br.close();
isr.close();
is.close();
serverSocket.close();
socket.close();
客戶端Client
//1、創建Socket,指定需要連接的服務器的地址和端口號
Socket socket=new Socket("localhost",8888);
//2、連接建立後,通過輸出流向服務器發送請求信息
OutputStream os=socket.getOutputStream();//字節輸出流
PrintWriter pw=new PrintWriter(os);//將輸出流包裝爲打印流
pw.write("用戶名:admin;密碼:123");
pw.flush();//刷新緩存,向服務器端發送信息
socket.shutdownOutput();//關閉輸出流
//3、通過輸入流獲取服務器響應的信息——暫無
InputStream is=socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
BufferedReader br=new BufferedReader(isr);
String info=null;
while ((info=br.readLine())!=null) {
System.out.println("我是客戶端,服務器說:"+info);//info爲從服務器獲取的信息
}
//4、關閉相關資源
br.close();
isr.close();
is.close();
pw.close();
os.close();
socket.close();
多線程服務器步驟:實現服務器與多客戶端之間的通信
1、服務器端創建ServerSocket,循環調用accept等待客戶端的連接
2、客戶端創建一個Socket並請求和服務器連接
3、服務器接受客戶端請求,創建socket與客戶端建立專線連接
4、建立連接的兩個socket在一個單獨的線程上對話
5、服務器端繼續等待新的連接
例3:通過循環監聽等待客戶端,開啓服務器端線程處理類來實現多客戶端通信
——Server結果——
——Client結果——
服務器端Server
// 1、創建ServerSocket,綁定監聽端口
ServerSocket serverSocket = new ServerSocket(8888);// 建議使用1024往後的端口
// 2、通過accept方法監聽客戶端請求,等待客戶端的連接
Socket socket = null;
int count = 0;// 記錄客戶端數量
System.out.println("————服務器即將開啓,等待客戶端的連接——");
while (true) {// 循環監聽等待客戶端的連接
socket = serverSocket.accept();// 獲取客戶端發送的Socket實例,用於監聽
// 創建一個新線程
ServerThread serverThread = new ServerThread(socket);
// 啓動線程
serverThread.start();
count++;
System.out.println("客戶端的數量:" + count);
//可以通過InetAddress獲取客戶端IP
InetAddress address=socket.getInetAddress();
System.out.println("當前客戶端的IP:"+address.getHostAddress());
}
// serverSocket.close();
服務器端線程處理類ServerThread extends Thread
@Override
public void run() {
InputStream is = null;
InputStreamReader isr = null;
BufferedReader br = null;
String info = null;
OutputStream os = null;
PrintWriter pw = null;
try {
// 3、連接建立後,通過輸入流讀取客戶端發送的請求信息(通過客戶端的輸入流讀取客戶端的信息)
is = socket.getInputStream();// 獲取字節輸入流
isr = new InputStreamReader(is);// 轉換字節流爲字符流
br = new BufferedReader(isr);// 爲字符輸入流添加緩衝
while ((info = br.readLine()) != null) {// 循環獲取客戶端的信息
System.out.println("我是服務器,客戶端說:" + info);// info爲從客戶端獲取的信息
}
socket.shutdownInput();// 關閉輸入流
// 4、通過輸出流向客戶端發送響應的信息
os = socket.getOutputStream();
pw = new PrintWriter(os);// 與客戶端發送信息類似
pw.write("歡迎您!");
pw.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
// 5、關閉相關資源
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 e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
客戶端Client同上
——以下是Socket基於UDP/IP協議的——
服務器端步驟:
1、創建DatagramSocket指定端口號
2、創建DatagramPacket
3、接收客戶端發送的數據信息
4、讀取數據
客戶端步驟:
1、定義發送信息
2、創建DatagramPacket,包含要發送的信息
3、創建DatagramSocket
4、發送數據
例1:服務器接收客戶端發送的數據,向客戶端響應數據,端口號8800
——UDPServer結果——
——UDPClient結果——
服務器UDPServer
/**
* 服務器接收客戶端發送的數據
*/
//1、創建DatagramSocket指定端口號
DatagramSocket socket=new DatagramSocket(8800);
//2、創建DatagramPacket
byte[] data=new byte[2014];//創建字節數組指定接收的數據報的大小
DatagramPacket packet=new DatagramPacket(data, data.length);
//3、接收客戶端發送的數據信息
System.out.println("——服務器已經啓動,等待客戶端發送數據——");
socket.receive(packet);//此方法在接收到數據之前會一直阻塞
//4、讀取數據
String info=new String(data,0,packet.getLength());//字節數組 位置 大小
System.out.println("我是服務器,客戶端說:"+info);
/**
* 向客戶端響應數據
*/
//1、定義客戶端的地址 端口號 數據
InetAddress address=packet.getAddress();//地址
int port=packet.getPort();//端口號
byte[] data2="歡迎您!".getBytes();//數據
//2、創建數據報,包含響應的數據信息
DatagramPacket packet2=new DatagramPacket(data2, data2.length,address,port);
//3、響應客戶端
socket.send(packet2);
//4、關閉資源
socket.close();
客戶端UDPClient
/**
* 向服務器發送數據
*/
//1、定義發送信息
InetAddress address=InetAddress.getByName("localhost");
int port=8800;//端口號
byte[] data="用戶名:admin;密碼:123".getBytes();
//2、創建DatagramPacket,包含要發送的信息
DatagramPacket packet=new DatagramPacket(data, data.length,address,port);//字節數組 大小 服務器地址 端口號
//3、創建DatagramSocket
DatagramSocket socket=new DatagramSocket();
//4、發送數據
socket.send(packet);
/**
* 接收服務器響應的數據
*/
//1、創建數據報,用於接收服務器響應的數據,保存在字節數組
byte[] data2=new byte[1024];
DatagramPacket packet2=new DatagramPacket(data2, data2.length);
//2、接收服務器響應的數據
socket.receive(packet2);
//3、讀取數據
String reply=new String(data2,0,packet2.getLength());
System.out.println("我是客戶端,服務器說:"+reply);
//4、關閉資源
socket.close();
關於多線程與TCP同理
注意:
多線程優先級
是否關閉輸入輸出流(socket已經關閉就無需關閉其它流)
TCP通信傳輸對象Object(ObjectOutputStream)和文件File(FileOutputStream)