Posted on 2009-12-18 21:56
啥都寫點(diǎn) 閱讀(440)
評(píng)論(0) 編輯 收藏 所屬分類:
J2SE

客戶端通過Socket連接聊天室服務(wù)器的端口,然后獲得Socket的 輸入和輸出,往輸入流中寫自己的連接信息,包括IP地址和賬戶。

客戶端連接服務(wù)器后,啟動(dòng)一個(gè)線程專門去接受服務(wù)器端發(fā)送的信息

使用StringTokenizer分析收到的信息,信息類型主要有:聊天信息、聊天室成員信息和服務(wù)器退出信息。

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.StringTokenizer;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.border.TitledBorder;


/** *//**
* 聊天室的客戶端程序,GUI界面。
*/

public class ChatClient extends JFrame implements ActionListener
{
// 登陸聊天室的名字標(biāo)簽和輸入框
JLabel nameLabel = new JLabel();
JTextField nameTextField = new JTextField(15);

// 連接和斷開連接的按鈕
JButton connectButton = new JButton();
JButton disConnectButton = new JButton();

// 聊天室內(nèi)容的文本域
JTextArea chatContentTextArea = new JTextArea(9, 30);

// 發(fā)送消息的按鈕
JButton sendMsgButton = new JButton();
// 消息輸入框
JTextField msgTextField = new JTextField(20);
JLabel msglabel = new JLabel();
// 聊天室用戶列表
java.awt.List peopleList = new java.awt.List(10);


/**//*以下定義數(shù)據(jù)流和網(wǎng)絡(luò)變量*/
Socket soc = null;
PrintStream ps = null;
// 客戶端偵聽服務(wù)器消息的線程
ClentListener listener = null;


public ChatClient()
{
init();
}

// 初始化圖形界面

public void init()
{

this.setTitle("聊天室客戶端");
// 初始化按鈕和標(biāo)簽
nameLabel.setText("姓名:");
connectButton.setText("連 接");
connectButton.addActionListener(this);
disConnectButton.setText("斷 開");
disConnectButton.addActionListener(this);
// 設(shè)置聊天內(nèi)容不可編輯
chatContentTextArea.setEditable(false);
sendMsgButton.setText("發(fā) 送");
sendMsgButton.addActionListener(this);
msgTextField.setText("請(qǐng)輸入聊天信息");
//panel1放置輸入姓名和連接兩個(gè)按鈕
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout());
panel1.add(nameLabel);
panel1.add(nameTextField);
panel1.add(connectButton);
panel1.add(disConnectButton);
//用于放置聊天信息顯示和聊天人員列表
JPanel panel2 = new JPanel();
panel2.setLayout(new FlowLayout());
JScrollPane pane1 = new JScrollPane(chatContentTextArea);
pane1.setBorder(new TitledBorder(BorderFactory.createEtchedBorder(
Color.white, new Color(134, 134, 134)), "聊天內(nèi)容"));
panel2.add(pane1);
JScrollPane pane2 = new JScrollPane(peopleList);
pane2.setBorder(new TitledBorder(BorderFactory.createEtchedBorder(
Color.white, new Color(134, 134, 134)), "用戶列表"));
panel2.add(pane2);
//用于放置發(fā)送信息區(qū)域
JPanel panel3 = new JPanel();
panel3.setLayout(new FlowLayout());
panel3.add(msglabel);
panel3.add(msgTextField);
panel3.add(sendMsgButton);
// 將組件添加到界面
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(panel1, BorderLayout.NORTH);
this.getContentPane().add(panel2, BorderLayout.CENTER);
this.getContentPane().add(panel3, BorderLayout.SOUTH);
this.pack();

try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(this);

} catch (Exception e)
{
e.printStackTrace();
}
}


/** *//**
* 關(guān)閉聊天室客戶端事件
*/

protected void processWindowEvent(WindowEvent e)
{
super.processWindowEvent(e);

if (e.getID() == WindowEvent.WINDOW_CLOSING)
{
// 如果是關(guān)閉聊天室客戶端,則斷開連接
disconnect();
dispose();
System.exit(0);
}
}

/** *//**
* 處理按鈕事件
*/

public void actionPerformed(ActionEvent event)
{
Object source = event.getSource();

if (source == connectButton)
{
// 如果點(diǎn)擊連接按鈕

if (soc == null)
{

try
{
// 使用端口2525實(shí)例化一個(gè)本地套接字
soc = new Socket(InetAddress.getLocalHost(), Constants.SERVER_PORT);
// 在控制臺(tái)打印實(shí)例化的結(jié)果
System.out.println(soc);
//將ps指向soc的輸出流
ps = new PrintStream(soc.getOutputStream());
//定義一個(gè)字符緩沖存儲(chǔ)發(fā)送信息
StringBuffer info = new StringBuffer(Constants.CONNECT_IDENTIFER).append(Constants.SEPERATOR);
//其中INFO為關(guān)鍵字讓服務(wù)器識(shí)別為連接信息
//并將name和ip用":"分開,在服務(wù)器端將用一個(gè)
//StringTokenizer類來讀取數(shù)據(jù)
String userinfo = nameTextField.getText() + Constants.SEPERATOR
+ InetAddress.getLocalHost().getHostAddress();
ps.println(info.append(userinfo));

ps.flush();
//將客戶端線程實(shí)例化,并啟動(dòng)
listener = new ClentListener(this, nameTextField.getText(), soc);
listener.start();

} catch (IOException e)
{
System.out.println("Error:" + e);
disconnect();
}
}

} else if (source == disConnectButton)
{
// 如果點(diǎn)擊斷開連接按鈕
disconnect();

} else if (source == sendMsgButton)
{
//如果點(diǎn)擊發(fā)送按鈕

if (soc != null)
{
//定義并實(shí)例化一個(gè)字符緩沖存儲(chǔ)發(fā)送的聊天信息
StringBuffer msg = new StringBuffer(Constants.MSG_IDENTIFER).append(Constants.SEPERATOR);
//用打印流發(fā)送聊天信息
ps.println(msg.append(msgTextField.getText()));
ps.flush();
}
}
}


/** *//**
* 斷開與服務(wù)器的連接
*/

public void disconnect()
{

if (soc != null)
{

try
{
// 用打印流發(fā)送QUIT信息通知服務(wù)器斷開此次通信
ps.println(Constants.QUIT_IDENTIFER);
ps.flush();
soc.close(); //關(guān)閉套接字
listener.toStop();
soc = null;

} catch (IOException e)
{
System.out.println("Error:" + e);
}
}
}

public static void main(String[] args)
{
ChatClient client = new ChatClient();
client.setVisible(true);
}


/** *//**
* 客戶端線程類用來監(jiān)聽服務(wù)器傳來的信息
*/

class ClentListener extends Thread
{
//存儲(chǔ)客戶端連接后的name信息
String name = null;
//客戶端接受服務(wù)器數(shù)據(jù)的輸入流
BufferedReader br = null;
//實(shí)現(xiàn)從客戶端發(fā)送數(shù)據(jù)到服務(wù)器的打印流
PrintStream ps = null;

//存儲(chǔ)客戶端的socket信息
Socket socket = null;
//存儲(chǔ)當(dāng)前運(yùn)行的ChatClient實(shí)例
ChatClient parent = null;

boolean running = true;

//構(gòu)造方法

public ClentListener(ChatClient p, String n, Socket s)
{

//接受參數(shù)
parent = p;
name = n;
socket = s;


try
{
//實(shí)例化兩個(gè)數(shù)據(jù)流
br = new BufferedReader(new InputStreamReader(s
.getInputStream()));
ps = new PrintStream(s.getOutputStream());


} catch (IOException e)
{
System.out.println("Error:" + e);
parent.disconnect();
}
}
// 停止偵聽

public void toStop()
{
this.running = false;
}

//線程運(yùn)行方法

public void run()
{
String msg = null;

while (running)
{
msg = null;

try
{
// 讀取從服務(wù)器傳來的信息
msg = br.readLine();
System.out.println("receive msg: " + msg);

} catch (IOException e)
{
System.out.println("Error:" + e);
parent.disconnect();
}
// 如果從服務(wù)器傳來的信息為空則斷開此次連接

if (msg == null)
{
parent.listener = null;
parent.soc = null;
parent.peopleList.removeAll();
running = false;
return;
}
//用StringTokenizer類來實(shí)現(xiàn)讀取分段字符
StringTokenizer st = new StringTokenizer(msg, Constants.SEPERATOR);
//讀取信息頭即關(guān)鍵字用來識(shí)別是何種信息
String keyword = st.nextToken();


if (keyword.equals(Constants.PEOPLE_IDENTIFER))
{
//如果是PEOPLE則是服務(wù)器發(fā)來的客戶連接信息
//主要用來刷新客戶端的用戶列表
parent.peopleList.removeAll();
//遍歷st取得目前所連接的客戶

while (st.hasMoreTokens())
{
String str = st.nextToken();
parent.peopleList.add(str);
}

} else if (keyword.equals(Constants.MSG_IDENTIFER))
{
//如果關(guān)鍵字是MSG則是服務(wù)器傳來的聊天信息,
//主要用來刷新客戶端聊天信息區(qū)將每個(gè)客戶的聊天內(nèi)容顯示出來
String usr = st.nextToken();
parent.chatContentTextArea.append(usr);
parent.chatContentTextArea.append(st.nextToken("\0"));
parent.chatContentTextArea.append("\r\n");

} else if (keyword.equals(Constants.QUIT_IDENTIFER))
{
//如果關(guān)鍵字是QUIT則是服務(wù)器關(guān)閉的信息, 切斷此次連接
System.out.println("Quit");

try
{
running = false;
parent.listener = null;
parent.soc.close();
parent.soc = null;

} catch (IOException e)
{
System.out.println("Error:" + e);

} finally
{
parent.soc = null;
parent.peopleList.removeAll();
}
break;
}
}
//清除用戶列表
parent.peopleList.removeAll();
}
}
}

--
學(xué)海無涯