由于最近在看Netty框架相關(guān)的東西,就把Java IO 這塊的內(nèi)容全部重新復(fù)習(xí)了一遍。這篇文章主要是把我在復(fù)習(xí)過(guò)程中使用Java BIO 中socket來(lái)實(shí)現(xiàn)tcp通信的過(guò)程分享出來(lái)。如果文中有什么不對(duì)的地方歡迎指正討論。
Java BIO :Java Blocking-IO Java阻塞式IO。Java中最原始的IO,基于數(shù)據(jù)流處理的IO。(就是我們常說(shuō)的那個(gè)IO)
Socket:套接字。一個(gè)編程接口,實(shí)現(xiàn)了對(duì)TCP/IP協(xié)議的封裝。它包含了主機(jī)地址,端口號(hào),傳輸協(xié)議。
簡(jiǎn)單了解下概念就開(kāi)始動(dòng)手?jǐn)]一個(gè)通信demo了。首先,理理思路。通信,肯定是雙方的,沒(méi)有自己和自己通信這種操作,有一個(gè)發(fā)送端,稱之為客戶端,客戶端的Socket是一個(gè)Socket實(shí)例,有一個(gè)接收端,稱之為服務(wù)端,服務(wù)端的Socket是一個(gè)ServerSocket實(shí)例。客戶端向服務(wù)端發(fā)送數(shù)據(jù)時(shí),將需要發(fā)送的數(shù)據(jù)寫入客戶端Socket的OutPutStream中,服務(wù)端Server Socket在讀取數(shù)據(jù)時(shí)先獲取到客戶端Socket,然后拿出這個(gè)Socket中的InputStream,從Input Stream中就可以讀到客戶端發(fā)送的數(shù)據(jù)了。看著是不是特簡(jiǎn)單,其實(shí)實(shí)現(xiàn)也特簡(jiǎn)單。下面看代碼。
首先,創(chuàng)建一個(gè)服務(wù)端類。Server
1.在main方法中實(shí)例化ServerSocket,并綁定端口端口自己定義
ServerSocket serverSocket = new ServerSocket(8765);
2.啟動(dòng)serverSocket并進(jìn)入阻塞狀態(tài),等待客戶端的連接??蛻舳诉B接后將會(huì)返回客戶端的Socket
Socket socket =serverSocket.accept();
serverSocket 調(diào)用accept后會(huì)進(jìn)入阻塞狀態(tài),也就是說(shuō)程序執(zhí)行到這一步后就不會(huì)再往下執(zhí)行了,一直等待,直到有客戶端連接。這個(gè)過(guò)程可以通過(guò)debugger來(lái)感受,將斷點(diǎn)打在ServerSocket serverSocket = new ServerSocket(8765);這行,然后啟動(dòng)debugger,一步步向下執(zhí)行,程序執(zhí)行到accept()那里后就不會(huì)繼續(xù)向下執(zhí)行了。
3.當(dāng)有客戶端連接到服務(wù)端的時(shí)候會(huì)在服務(wù)端獲取到該客戶端的socket,就是accept()方法返回的那個(gè)。得到客戶端socket后我們就可以獲取到客戶端發(fā)送的內(nèi)容了。通過(guò)讀取客戶端socket中的流來(lái)獲取。
InputStream inputStream = socket.getInputStream();
BufferedReader reader =newBufferedReader(newInputStreamReader(inputStream));
String str = reader.readLine();
這個(gè)str就是我們從客戶端發(fā)來(lái)的數(shù)據(jù)了。服務(wù)端的工作就搞定了。
忘記了,數(shù)據(jù)讀取完成后記得關(guān)閉資源。記得資源關(guān)閉原則,先開(kāi)的后關(guān)。為什么?自己悟!
reader.close();? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
socket.close();
serverSocket.close();
服務(wù)端搞定,再來(lái)看看客戶端。新建Client.java
1.在main方法中創(chuàng)建Socket實(shí)例并綁定服務(wù)端的ip和端口。
Socket socket =newSocket("127.0.0.1",8756);
2.向服務(wù)端發(fā)送數(shù)據(jù),將要發(fā)送的內(nèi)容寫到socket的OutputStream中即可。
BufferedWriter writer =newBufferedWriter(newOutputStreamWriter(socket.getOutputStream()));
writer.write("你好,服務(wù)端!\n“);
writer.flush();
writer.close();
socket.close();
OK,一個(gè)簡(jiǎn)單而且簡(jiǎn)陋的socket通信就搞定了。那么現(xiàn)在問(wèn)題來(lái)了,如果多個(gè)客戶端給服務(wù)端同時(shí)發(fā)送送消息呢?方法也很簡(jiǎn)單,多開(kāi)幾個(gè)線程。將讀取客戶端的消息操作放到新開(kāi)的線程中去。這時(shí)候我們可以這樣做。
在server.java 中將代碼改成:
while(true){
Socket socket =serverSocket.accept();
new Thread(new Runnable(){
public void run(){
將讀取數(shù)據(jù)操作放入線程的run方法中。記得關(guān)閉流
InputStream inputStream = socket.getInputStream();
BufferedReader reader =newBufferedReader(newInputStreamReader(inputStream));
String str = reader.readLine();
}
}).start();
}
簡(jiǎn)單地回顧了一下Java中BIO的socket的用法,也是對(duì)自己知識(shí)的復(fù)習(xí),希望能對(duì)讀者有所幫助。