Java實現IO通信(服務器篇)
如何利用java實現我們的通信呢?首先我們了解一下什么是通信?通信的機制是怎樣的?
首先來討論一下什么是通信?通信,指人與人或人與自然之間通過某種行為或媒介進行的信息交流與傳遞,從廣義上指需要信息的雙方或多方在不違背各自意願的情況下采用任意方法,任意媒質,將信息從某方准確安全地傳送到另方。而這里所說的通信,是在同一局域網內,一個用戶給其他用戶發送信息的過程。
然后通行的機制是怎么樣的呢?這里的JavaIO通信是這樣的,首先我們需要一台服務器,並有一個或者多個用戶。用戶與用戶之間傳輸信息就必須通過服務器,服務器的作用就是處理各種用戶發來的信息,並作出各種執行各種指令。
最后來看一下如何通過代碼實現我們簡單的通信:
1.服務器:
1、首先我們需要一台服務器,我們可以用我們的電腦搭建服務器,怎么搭建呢?Java中提供了ServerSocket類,我可以使用這個類搭建服務器,在實例化這個類的時候需要指定一個端口(一般電腦上有256*256個端口,建議一般使用9000以上的端口,避免與一些熱門端口沖突),而服務器的IP地址就是電腦所在局域網下的IP地址,值得注意的是,當我們電腦在不同局域網內是IP地址是會不同的!!!一般在命令行中使用ipconfig命令查看我們電腦的IP地址。關鍵代碼:
public void createServer(int port){
try {
serverSocket=new ServerSocket(port);
} catch (IOException e){
e.printStackTrace();
}
}
2、服務器搭建好了以后,服務器接下來所需要做的就是等待用戶接進服務器,才去做下一件事,否則一直等待用戶上線。等待用戶的客戶端連接服務器是需要用到java提供的Socket類,這個類的作用,筆者解釋為起到接口的作用,在這里我們只能用一台服務器,但是一台服務器卻用多個接口,每一個接口可以連接一個用戶,而服務器就可以管理所有的接口,以達到管理所有用戶的目的
關鍵代碼:
public void connect(){
Socket socket=serverSocket.accept();
當獲取出來一個接口的時候,會用阻塞作用,會一直停留在在這里,直到有用戶連接進服務器,才會執行下一條語句。
System.out.println("有一個客戶機接入服務器");
}
3、現在我們最簡單的服務器就搭建好了,可是這個服務器只有一個功能,就是讓用戶連接一下,然后就結束了。怎么讓用戶實時連接着不斷開呢?很簡單,我們只要用一個while(true)循環讓程序不結束就可以了。接下來,再看看如何實現服務器讀取用戶的消息,和給用戶發消息呢?首先我們需要IO流,之所以叫IO通信,就是這里的發送和讀取信息都是通過IO流實現的。剛剛上面所說的一個服務器有多個接口,一個接口可以連接一個用戶,現在我們就可以根據接口,獲取出我們的IO流,同時值得注意的是一個接口獲取出來的IO流只能讀取和發送接口所對應接口連接的用戶。比如:接口A連接的是A用戶,所以由A接口獲取的IO流只能讀取A用戶發來的信息,和對A用戶發送信息。
關鍵代碼:
while(true){
try {
Socket socket=serverSocket.accept();
System.out.println("有一個客戶機接入服務器");
OutputStream output=socket.getOutputStream();//獲取輸出流,用於給用戶發送信息
InputStream input=socket.getInputStream();//獲取輸入流,用戶讀取用戶發來的信息
output.write("welcome!".getBytes());//給用戶發送“welcome”
input.read();//讀取用戶消息的一個字節,調用一次讀取一個字節,具有阻塞作用,如果用戶沒有發來消息,則會停留在這里,直到有消息發送過來。
} catch (IOException e) {
e.printStackTrace();
}
}
}
這樣我們的服務器就有了最基本的功能,用戶連接進來后,服務器可以讀取用戶的信息,可以給用戶發信息。但是仔細琢磨上面的代碼或者執行它就會發現,這個服務器僅僅能對一個連接進來的用戶發送和讀取信息。這是為什么?來分析一下,首先用戶執行進來就會執行Socket socket=serverSocket.accept();這行命令,為用戶開辟接口,而到了 input.read();這句語句,假如用戶一直沒有向服務器發送消息,哪有程序就會阻塞在這句語句這里,而其他用戶想要連接進來就得執行Socket socket=serverSocket.accept();這句語句,但是程序已經停留在input.read();這里了,這樣就會出現只能連接進來一個用戶。這也說明了主線程這能干一件事情,說到線程,我們應該怎么解決這樣的問題呢,我們不可能只能有一個用戶,那樣達不到我們通信的目的。所以這里我們需要用到多線程來替我們解決這個問題。下面將會詳細分析怎么解決這個問題。
既然我們的主線程只能做一件事情,那么我們就可以讓服務器的信息讀寫放在一個子線程里,每一個用戶由一個子線程用戶信息的讀取和發送,這個線程應該是具有該用戶的所有信息,也稱這個線程為接口線程,在服務器中可以通過一個接口線程間接訪問所有的接口線程。關鍵代碼:
ArrayList<Users> userList=new ArrayList<Users>();
while(true){
try {
Socket socket=serverSocket.accept();
System.out.println("有一個客戶機接入服務器");
Users oneUser=new User(socket,userName, password);
userList.add(oneUser);
ChatManage chat=new ChatManage(socket,userName);//傳一個socket過去用於信息的讀寫,再傳一個用戶名,用來標識聊天線程。用戶名可以
由服務器指定,也可以由用戶指定。
Chat.start();//啟動線程。
} catch (IOException e) {
e.printStackTrace();
}
}
}
Public class ChatManage extends Thread{
Socket socket;
String userName;
Public ChatManage(Socket socket,String userName){
this.socket=socket;
this.userName=userName;
}
Public void run(){
While(true){
//獲取IO流
InputStream input=socket.getInputStream ();
OuputStream output=socket.getOutputStream();
//后面就可以利用IO流讀信息和發信息了,。。。。
}
}
}
為了更好地管理每一個連接進服務器的用戶,我們可以為用戶寫一個用戶類
每一個用戶都保存在一個動態數組里。
public class Users {
String password;
String sex="man";
String account="123456";
String userName;
private Socket socket;
public Users(Socket socket,String userName,String password){
this.socket=socket;
this.userName=userName;
this.password=password;
}