?? 聊天.txt
字號:
>>當前位置:Java大本營>Socket編程>文章內容
java網絡聊天程序的實現
作者: 發布時間:2007-12-04 00:02:06
設計思路
Socket是實現client/server模式的通信方式,它首先要建立穩定的連接,然后以流的方式傳輸數據,實現網絡通信。使用Socket進行Client/Server程序設計的一般連接過程是這樣的:Server端監聽某個端口是否有連接請求,Client端向Server端發出連接請求,Server端向Client端發回接受消息。一個連接就建立起來了。Server端和Client端都可以通過Send,Write等方法與對方通信。
因為在創建socket時如果發生錯誤,將會產生IOException,所以在創建ServerSocket和Socket時我用了try-catch-finally語句捕獲和處理異常,并通過JOptionPane給用戶發出提示。
本程序接收消息的模塊使用了教材上的由Socket對象得到輸入流,并構造相應的BufferedReader對象的方法,而發送模塊是通過構造PrintWriter對象并將數據輸出到Server的方法,因為對輸出來說,使用Writer方式具有明顯的優勢。這一優勢是通過PrintWriter表現出來的,它有一個過載的構建器,能獲取第二個參數:一個布爾值標志,指向是否在每一次println()結束的時候自動刷新輸出。每次寫入了輸出內容后,它的緩沖區必須刷新,使信息能正式通過網絡傳遞出去。這樣就能保證信息每次能夠及時準確地從發送端發出。
在設計本程序時我還特意將發送消息的日期和時間跟消息一起發送到接收端,這樣可以方便用戶閱讀聊天記錄。
設計GUI界面時我用了最常見的模型,即上面有個JTextArea存放聊天記錄,下面的JTextArea讓用戶輸入信息,最下方還有三個按鈕,用于發送信息,清空記錄和關閉窗口。
本程序加入了GUI界面有以下三個原因:
1.由于本程序要實現全雙工的網絡通信,如果要在DOS界面下實現這種通信方式只有用到多線程,這樣就增加了程序 的復雜程度,也更容易出錯。而用GUI界面只要對原有程序稍加改動就可以通過JButton事件處理程序實現實時收發 功能而不受順序的限制。而用同樣的核心代碼不加GUI界面只能實現半雙工的通信模式。
2.在DOS界面下通信只能發英文而不能發中文,而用GUI界面就可以實現中文的收發。
3.GUI界面在人機交互方面更加友好,更加方便,使用起來更順手。
以下是程序的主要設計思路:
1.先在Server端創建一個ServerSocket監聽本機的6789端口,等待客戶端的連接請求。
2.Client端啟動后,會向客戶端的6789端口發出連接請求,當Server端收到請求后會由ServerSocket通過accept()方法返回一個對應的Server端Socket與Client端進行連接,連接后兩臺機器間就建立了一個Socket——Socket的連接,繼而實現Socket之間的通信。此時Server端和Client端就基本沒有什么差別了,發送和接收信息都是一樣的。
3.創建一個無限循環,由Socket分別得到輸入輸出流,構造BufferedReader對象存放得到的輸入流,并讀出輸入流中的數據,顯示在聊天記錄對話框中。用輸出流構造一個PrintWriter對象。此時程序的接收功能就有了。
4.用事件處理程序控制信息的發送,當發送按鈕按下時,從聊天對話框中取出輸入的字符串,并向接收端發送該字符串,刷新輸出流,使接收端馬上收到該字符串。
5.當按下清除記錄按鈕時清空所有對話框中的字符。
6.按下關閉按鈕時,關閉所有連接并退出程序。此時另一端沒有關閉的程序會彈出一個對話框告訴用戶連接已經斷開。
設計模型
Server端: Client端:
主要程序描述
Server端:
public TCPServer()
{
//調用方法createUserInterface()
createUserInterface();
//用try和catch實現異常的捕獲和拋出
try
{
//在與客戶端的連接沒有建立之前將GUI組件設為不可用
chatJTextArea.setEditable( false );
sendJButton.setEnabled( false );
clearJButton.setEnabled( false );
//在端口6789建立監聽socket,并在historyJTextArea中顯示提示語
ServerSocket welcomeSocket=new ServerSocket( 6789 );
historyJTextArea.append( "等待連接..."+"\n" );
//當監聽socket監聽到有客戶端連接后建立一個新的socket用于傳送數據
//并在historyJTextArea中顯示提示語
Socket connectionSocket=welcomeSocket.accept( );
historyJTextArea.append( "連接已建立,端口:"+connectionSocket.getLocalPort()+"\n" );
historyJTextArea.append( "主機信息:"+connectionSocket.getInetAddress().getLocalHost()+"\n" );
historyJTextArea.append( "socket信息:"+connectionSocket+"\n" );
//恢復GUI組件的可用性
chatJTextArea.setEditable( true );
sendJButton.setEnabled( true );
clearJButton.setEnabled( true );
//建立變量fromClient用于存放從客戶端接受到的數據
String fromClient;
//通過一個while循環實現連續的接收功能
while( true )
{
//從connectionSocket中取得輸出流,并構造PrintWriter對象
OutputStream output=connectionSocket.getOutputStream();
outToClient=new PrintWriter(output,true);
//建立BufferedReader存放從socket中取得的輸入流
BufferedReader inFromClient=new BufferedReader(
new InputStreamReader(
connectionSocket.getInputStream( ) ) );
//從輸入流緩存區中讀取數據存入變量fromClient中
fromClient=inFromClient.readLine( );
if( fromClient!=null)
//在historyJTextArea中顯示接收到的數據
{
historyJTextArea.append("Client:"+"\n"+fromClient+"\n");
}
}//end while
}//end try
catch( IOException e )
{
//發生異常時出現提示
JOptionPane.showMessageDialog( null,
e,"發生異常!",
JOptionPane.ERROR_MESSAGE );
}//end catch
finally
{
}//end finally
}
//建立方法sendJButtonActionPerformed用于響應sendJButton的動作
private void sendJButtonActionPerformed( ActionEvent event )
{
//建立變量words存放用戶在chatJTextArea里輸入的數據
String words=chatJTextArea.getText();
//執行判斷,如果用戶沒有輸入數據則提示用戶輸入數據,如果輸入了數據就將其發送到socket中
if( words.equals( "" ) )
{
JOptionPane.showMessageDialog( null,
"輸入不能為空,請輸入有效字符","輸入有誤",
JOptionPane.INFORMATION_MESSAGE );
}
else
{
//利用DateFormat的方法getDateTimeInstance取得一個DateFormat對象
//將其存放到time中
DateFormat time=DateFormat.getDateTimeInstance();
//利用new Date()返回當前系統時間,并用time的format方法將其轉化為String
//用變量str存放格式化后的要發送的數據
String str=" "+words+"\t"+"("+time.format( new Date() )+")";
try
{
//將str字符串內容發送Client端
outToClient.println(str);
outToClient.flush();
}
catch(Exception e)
{
JOptionPane.showMessageDialog( null,
e,"發生異常!",
JOptionPane.ERROR_MESSAGE );
}
finally
{
}//end finally
sendJButton.requestFocusInWindow();
historyJTextArea.append( "Server:"+"\n"+str+"\n" );
chatJTextArea.setText( "" );
}
}//end method sendJButtonActionPerformed
Client端:
public TCPClient()
{
//調用方法createUserInterface
createUserInterface();
try
{
chatJTextArea.setEnabled( false );
sendJButton.setEnabled( false );
clearJButton.setEnabled( false );
//與主機建立連接并在historyJTextArea中顯示提示語
Socket clientSocket=new Socket( "localhost",6789 );
historyJTextArea.append( "連接已建立,端口:"+clientSocket.getLocalPort()+"\n" );
historyJTextArea.append( "客戶端信息:"+clientSocket.getInetAddress().getLocalHost()+"\n" );
historyJTextArea.append( "socket信息:"+clientSocket+"\n" );
chatJTextArea.setEnabled( true );
sendJButton.setEnabled( true );
clearJButton.setEnabled( true );
//建立變量存放從Server端發送過來的數據
String fromServer;
while( true )
{
//從clientSocket中取得輸出流,并構造PrintWriter對象
OutputStream output=clientSocket.getOutputStream();
outToServer=new PrintWriter(output,true);
//建立BufferedReader存放從socket中取得的輸入流
BufferedReader inFromServer=new BufferedReader(
new InputStreamReader(
clientSocket.getInputStream( ) ) );
//從輸入流中緩存區讀取數據存入變量fromServer中
fromServer=inFromServer.readLine( );
if( fromServer!=null )
{
//在historyJTextArea中顯示接收到的數據
historyJTextArea.append("Server:"+"\n"+fromServer+"\n");
}
}//end while
}//end try
catch( IOException e )
{
//發生異常時出現提示
JOptionPane.showMessageDialog( null,
e,"發生異常!",
JOptionPane.ERROR_MESSAGE );
}//end catch
finally
{
}//end finally
}
//建立方法sendJButtonActionPerformed用于響應sendJButton的動作
private void sendJButtonActionPerformed( ActionEvent event )
{
//建立變量words存放用戶在chatJTextArea里輸入的數據
String words=chatJTextArea.getText();
//執行判斷,如果用戶沒有輸入數據則提示用戶輸入數據,如果輸入了數據就將其發送到socket中
if( words.equals( "" ) )
{
JOptionPane.showMessageDialog( null,
"輸入不能為空,請輸入有效字符","輸入有誤",
JOptionPane.INFORMATION_MESSAGE );
}
else
{
//利用DateFormat的方法getDateTimeInstance取得一個DateFormat對象
//將其存放到time中
DateFormat time=DateFormat.getDateTimeInstance();
//利用new Date()返回當前系統時間,并用time的format方法將其轉化為String
//用變量str存放格式化后的要發送的數據
String str=" "+words+"\t"+"("+time.format( new Date() )+")";
try
{
//將str字符串內容發送到Server端
outToServer.println(str);
outToServer.flush();
}
catch(Exception e)
{
JOptionPane.showMessageDialog( null,
e,"發生異常!",
JOptionPane.ERROR_MESSAGE );
}
finally
{
}//end finally
sendJButton.requestFocusInWindow();
historyJTextArea.append( "Client:"+"\n"+str+"\n" );
chatJTextArea.setText( "" );
}
}//end method sendJButtonActionPerformed
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -