引言
為了學習Java網絡編程,用一個QQ(屌絲版)作為例子練手,記錄屌絲版QQ的開發過程,這里我們認為已經掌握其中的網絡基礎部分,即HTTP協議,TCP/IP協議等,在此基礎上我們開始我們的Java網絡部分的學習,我們要知道服務器和客戶端是如何通信的,首先我們要了解Java網絡知識中的一個很重要的東西——Socket
Socket初探
ServerSocket和Socket
首先服務器端需要用到java.net包下的ServerSocket類,該類的一個實例用於監聽等待客戶端的連接,而客戶端需要用到net包下的Socket類,用於向服務器端發送連接請求,客戶端是怎樣與服務器端建立連接的呢,首先客戶端的Socket實例要制定服務器端的ip地址和端口,服務器端如何與客戶端建立連接呢,服務器端的ServerSocket類的accept一直在監聽等待客戶端發來的連接請求,如果沒有收到,則一直阻塞在accept這句代碼這兒(可以在Socket s=ss.accept();這行代碼后面打印出一句語句,可以發現,程序並不會執行到這行代碼),以下代碼1說明服務器端ServerSocket的用法,代碼2說明客戶端Socket的用法
代碼1
創建一個類,名字叫Server,在類的構造函數中創建ServerSocket等實例
public class MyServer1 {
public MyServer1()
{
//在9999號端口監聽
ServerSocket ss=new ServerSocket(9999);
//等待某個客戶端來連接,該函數會返回一個Scoket連接
Socket s=ss.accept();
}
}
代碼2
創建一個類,名字叫Client
public class MyClient1 {
public MyClient1()
{
//Socket,就是連接某個服務器端,127.0.0.1表示服務器的Ip 9999表示端口號
Socket s=new Socket("127.0.0.1", 9999);
}
}
服務器和客戶端互發信息
服務器端和客戶端是如何發送信息的呢,用到的還是java.io包下的東西,服務器端要讀取客戶端發來的信息,用到InputStreamReader,BufferedReader,其中InputStreamReader的輸入為Socket.getInputStream()方法返回的輸入流,要發送信息給客戶端用到PrintWriter,其中PrintWriter的輸入為Socket.getOutputStream()方法返回的輸出流,具體用法如下
客戶端發送信息
//如果s連接成功,就可以發數據給服務器
//我們通過pw向s寫數據 true表示刷新流
PrintWriter pw=new PrintWriter(s.getOutputStream(),true);
pw.println("Hello Server,I'm Client");
服務器端接受信息
//要讀取s中傳遞的數據
InputStreamReader isr=new InputStreamReader(s.getInputStream());
BufferedReader br=new BufferedReader (isr);
//行讀取
String info=br.readLine();
System.out.println("服務器收到的信息是,"+info);
然后服務器端向客戶端發送信息
PrintWriter pw=new PrintWriter(s.getOutputStream(), true);
pw.println("Hello Client,I'm Server");
然后客戶端收到服務器端的信息
InputStreamReader isr=new InputStreamReader(s.getInputStream());
BufferedReader br=new BufferedReader (isr);
//行讀取
String response=br.readLine();
System.out.println("客戶端收到的信息是,"+response);
服務器和客戶端互發信息(從控制台輸入)
之前服務器和客戶端互發的信息是寫死在pw.println里,我們稍微修改一下,從控制台輸入
之前建立連接的方式相同,而且讀取和發送信息的方式也類似,只是多了一個需要從控制台輸入信息
服務器端代碼
比如服務器端接受客戶端發來的信息依舊不變,從Socket.getInputStream()方法返回的輸入流作為InputStreamReader的輸入
但服務器端還需要一個InputStreamReader接受從System.in傳進來的輸入用來接收從控制台輸入的想發送給客戶端的信息
//接受客戶端發來的信息
InputStreamReader isr=new InputStreamReader(s.getInputStream());
BufferedReader br=new BufferedReader(isr);
//打印客戶端發來的信息
String infoFromClient=br.readLine();
System.out.println("客戶端發來"+infoFromClient);
//接收從控制台輸入的信息
InputStreamReader isr2=new InputStreamReader(System.in);
BufferedReader br2=new BufferedReader(isr2);
//打印從控制台輸入的信息
System.out.println("輸入要發送給客戶端的信息");
String response=br2.readLine();
客戶端的代碼
而客戶端代碼也類似
InputStreamReader isr=new InputStreamReader(System.in);
BufferedReader br=new BufferedReader(isr);
InputStreamReader isr2=new InputStreamReader(s.getInputStream());
BufferedReader br2=new BufferedReader(isr2);
服務器和客戶端互發信息(從聊天窗口輸入)
有了第一個的基礎,這一部分就只是將從控制台輸入變成了從JTextArea域里讀取文字,這里我們暫且認為已有Java界面的基礎,對JFrame了解
這一部分我們希望客戶端發來的消息顯示在聊天窗口中,而不是控制台,那么將
System.out.println("客戶端發來"+infoFromClient);替代為jta.append("客戶端發來"+info+"\r\n");即可
另外我們希望客戶端發給服務器的消息也從聊天窗口輸入,那么我們需要繼承ActionListener,實現當點擊發送按鈕時,讀取JTextField域的文字,具體實現如下
String info=jtf.getText();
pw.println(info);
//清空發送框的內容
jtf.setText("");