有很多天沒有寫了,這些天跟着視頻教程,學着做了一個非常簡單的聊天程序,當然是仿QQ的,代碼也不是我原創的,不過我覺得這些代碼寫出來以後還是很有幫助的,對面向對象思想的理解,甚至說是以後忘記哪行代碼了,過來查查看也是好的
代碼略多,我會順便把整個工程結構的圖粘在下面的:
客戶端:
package com.Common;
//定義一個接口 用來表示包的種類
public interface MessageType {
String message_login_successd = "1"; //表示登陸成功
String message_login_failed = "2"; //表示登陸失敗
String message_communicate_content = "3"; //聊天信息
String message_get_onlinefriendlist = "4"; //向服務器請求在線好友列表
String message_onlinefriendlist = "5"; //服務器返回的在線好友列表
}
package com.Common;
//這個類用於定義與服務器交互的信息類型
//因爲交互信息過多 分類更好管理
public class Message implements java.io.Serializable{
private String mesType;
private String getter;
private String sender;
private String time;
private String content;
public String getMesType() {
return mesType;
}
public void setMesType(String mesType) {
this.mesType = mesType;
}
public String getGetter() {
return getter;
}
public void setGetter(String getter) {
this.getter = getter;
}
public String getSender() {
return sender;
}
public void setSender(String sender) {
this.sender = sender;
}
public String getTime() {
return time;
}
public void setTime(String time) {
this.time = time;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
package com.Common;
//用於封裝UserName 和 password
public class User implements java.io.Serializable{
private String userName;
private String password;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
package com.QqClient.Management;
//用來管理用戶的聊天窗口
import java.util.*;
import com.QqClient.View.QqChat;
public class ManageChat {
private static HashMap hm = new HashMap<String,QqChat>();
public static void addChat(String ownerAndChater,QqChat chat){
hm.put(ownerAndChater, chat);
}
public static QqChat getChat(String ownerAndChater){
return (QqChat)hm.get(ownerAndChater);
}
}
package com.QqClient.Management;
import java.util.*;
//用來管理客戶端的線程
import com.QqClient.Model.QqClientConServerThread;
public class ManageClientThread {
//一臺計算機只需要維護一個hashmap即可 因此將hm設置爲靜態的全局變量
private static HashMap hm = new HashMap<String,QqClientConServerThread>();
public static void addClientConServerThread(String clientID,QqClientConServerThread thread){
//將得到的信息放入到hashmap中
hm.put(clientID, thread);
}
public static QqClientConServerThread getClientConServerThread(String clientID){
//得到的是object
return (QqClientConServerThread) hm.get(clientID);
}
}
package com.QqClient.Management;
//用來管理好友列表
import java.util.*;
import com.QqClient.View.QqFriendList;
public class ManageFriendList {
private static HashMap hm = new HashMap<String,QqFriendList>();
public static void addQqFriendList(String listowner,QqFriendList friendList){
hm.put(listowner, friendList);
}
public static QqFriendList getQqFriendList(String listowner){
return (QqFriendList)hm.get(listowner);
}
}
package com.QqClient.Model;
//跟服務器直接連接 用於後臺信息交互
import java.io.*;
import java.net.*;
import com.Common.*;
import com.QqClient.Management.ManageClientThread;
public class QqClientConServer {
//如果將這裏設置成全局變量 會出現問題 當在窗口調用socket讀取數據時 會出現兩個窗口爭奪一個socket的錯誤
public Socket s;
public static int i = 1;
//發送登陸信息給服務器 進行驗證
public boolean sendLoginInfoToSever(Object object){
boolean b = false;
try {
s = new Socket("127.0.0.1",9999);
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(object);
System.out.println("已將登陸信息發送給服務器進行驗證");
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
Message mes = (Message)ois.readObject();
System.out.println(mes.getMesType());
if(mes.getMesType().equals("1")){
b=true;
//驗證成功,連接已經建立 此時爲客戶端生成一個進程 並將該進程添加到
QqClientConServerThread conThread = new QqClientConServerThread(s);
conThread.start();
ManageClientThread.addClientConServerThread(((User)object).getUserName(), conThread);
}
//s.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("b="+b);
return b;
}
}
package com.QqClient.Model;
//這是一個用來控制客戶端接受信息的線程
import java.net.*;
import java.io.*;
import com.Common.*;
import com.QqClient.Management.ManageChat;
import com.QqClient.View.QqFriendList;
import com.Common.*;
import com.QqClient.Management.*;
public class QqClientConServerThread extends Thread{
//首先得到對應的socket
private Socket socket;
public QqClientConServerThread(Socket s){
this.socket = s;
}
public void run(){
while(true){
//不停的讀
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message mes = (Message)ois.readObject();
//System.out.println("我是"+mes.getGetter()+" 我收到來的"+mes.getSender()+" 的消息: "+mes.getContent());
//如果是聊天信息 則顯示
if(mes.getMesType().equals(MessageType.message_communicate_content)){
//在對應的聊天窗口顯示
ManageChat.getChat(mes.getGetter()+mes.getSender()).showMessage(mes);
}else if(mes.getMesType().equals(MessageType.message_onlinefriendlist)){
//將好友名單取出來 並刷新好友列表
//以空格在間隔進行拆分
String con = mes.getContent();
String friends[] = con.split(" ");
//得到對應的好友列表
QqFriendList friendList = ManageFriendList.getQqFriendList(mes.getGetter());
System.out.println(mes.getGetter()+"得到了好友在線列表");
//更新好友列表的在線情況 這裏可能在第一次上線時 socket建立後 服務器發來信息的時間早於friendlist的創建時間 因此要判斷一下
if(friendList!=null){
friendList.updateFriendList(friends);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
package com.QqClient.Model;
import java.net.*;
import com.Common.*;
//後臺用於調用連接服務器的各個函數
public class QqClientUser implements java.io.Serializable{
//檢查用戶名和密碼
public boolean CheckUser(User user){
QqClientConServer qccs = new QqClientConServer();
return qccs.sendLoginInfoToSever(user);
}
}
package com.QqClient.View;
import javax.swing.*;
import com.Common.*;
import com.QqClient.Management.ManageClientThread;
import com.QqClient.Model.QqClientConServer;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
//爲了讓用戶聊天窗口能一直處於監聽狀態 需要將其做成線程
public class QqChat extends JFrame implements ActionListener{
JTextArea chatHistory;
JTextField chatWord;
JButton sendButton;
JPanel southPanel;
String sender;
String getter;
//繪製一個山寨QQ的聊天界面
public QqChat(String sender,String getter){
this.sender = sender;
this.getter = getter;
chatHistory = new JTextArea();
chatHistory.setEditable(false);
sendButton = new JButton("發送");
sendButton.addActionListener(this);
chatWord = new JTextField(15);
southPanel = new JPanel();
southPanel.add(chatWord);
southPanel.add(sendButton);
this.add(chatHistory);
this.add(southPanel,BorderLayout.SOUTH);
this.setLocation(420,200);
this.setSize(400, 300);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
//this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setTitle(sender+"正在和"+getter+"聊天ing");
this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//QqChat qc = new QqChat();
}
//定義一個方法用來顯示信息
public void showMessage(Message mes){
String info = mes.getSender()+"對你說:"+mes.getContent()+"\n";
chatHistory.append(info);
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//封裝mes信息
Message mes = new Message();
mes.setSender(sender);
mes.setGetter(getter);
mes.setContent(chatWord.getText());
mes.setTime(new java.util.Date().toString());
mes.setMesType(MessageType.message_communicate_content);
//發送給服務器(先用不好的方法直接獲取Scoket 待修改)
try {
Socket s = ManageClientThread.getClientConServerThread(sender).getSocket();
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(mes);
//顯示一下
String info = "你對"+mes.getGetter()+"說: "+mes.getContent()+"\n";
chatHistory.append(info);
chatWord.setText("");
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
//用線程進行讀取 這段代碼要求socket是靜態的才能獲取 而這會導致兩個窗口爭奪一個socket的現象出現
// public void run() {
// // TODO Auto-generated method stub
// //監聽接口
// while(true){
// //讀取
// try {
// ObjectInputStream ois = new ObjectInputStream(QqClientConServer.s.getInputStream());
// System.out.println(QqClientConServer.i+1);
// Message mes = (Message)ois.readObject();
//
// //顯示
// String info = mes.getSender()+"對你說:"+mes.getContent()+"\n";
// chatHistory.append(info);
// chatWord.setText("");
//
// } catch (Exception e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
//
//
// }
}
package com.QqClient.View;
import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.net.Socket;
import javax.swing.*;
import com.Common.*;
import com.QqClient.Management.*;
import com.QqClient.Model.*;
//我登陸兩次時 因爲是在兩個程序進程中 因此 獲得的s不會相同 但是一個進程的兩個窗口s是相同的
//因此 也需要調用線程來進行管理
public class QqClientLogin extends JFrame implements ActionListener{
//繪製一個山寨QQ登陸窗口
//定義組件
JLabel northLogo;
JLabel userName,passWord;
JTextField userNameField;
JPasswordField passWordField;
JLabel forgetPassword;
JLabel applyQQ;
JPanel southPanel;
JButton loginButton;
JCheckBox rememberPassword;
JCheckBox invisibleLogin;
JLabel applyProtect;
//框架
JPanel qqNumberLoginPanel;
JPanel phoneNumberLoginPanel;
JPanel emailLoginPanel;
JTabbedPane tabPane;
//在構造函數中對組件進行初始化
public QqClientLogin(){
//登陸窗口北部
northLogo = new JLabel(new ImageIcon("image/beijing1.jpg"));
//登陸窗口南部
southPanel = new JPanel();
loginButton = new JButton(new ImageIcon("image/denglu.png"));
loginButton.setPreferredSize(new Dimension(148,29)); //改變按鈕大小時使用setPreferredSize
loginButton.addActionListener(this);
//loginButton.setSize(148, 29);
southPanel.add(loginButton);
//登陸窗口中間
userName = new JLabel("QQ號碼",JLabel.CENTER);
passWord = new JLabel("QQ密碼",JLabel.CENTER);
userNameField = new JTextField();
passWordField = new JPasswordField();
forgetPassword = new JLabel("忘記密碼",JLabel.CENTER);
forgetPassword.setForeground(Color.red);
applyQQ = new JLabel("申請QQ",JLabel.CENTER);
applyProtect = new JLabel("申請密碼保護");
rememberPassword = new JCheckBox("記住密碼");
invisibleLogin = new JCheckBox("隱身登陸");
qqNumberLoginPanel = new JPanel();
qqNumberLoginPanel.setLayout(new GridLayout(3,3));
qqNumberLoginPanel.add(userName);
qqNumberLoginPanel.add(userNameField);
qqNumberLoginPanel.add(applyQQ);
qqNumberLoginPanel.add(passWord);
qqNumberLoginPanel.add(passWordField);
qqNumberLoginPanel.add(forgetPassword);
qqNumberLoginPanel.add(rememberPassword);
qqNumberLoginPanel.add(invisibleLogin);
qqNumberLoginPanel.add(applyProtect);
phoneNumberLoginPanel = new JPanel();
emailLoginPanel = new JPanel();
//用tab窗口
tabPane = new JTabbedPane();
tabPane.addTab("QQ號碼", qqNumberLoginPanel);
tabPane.addTab("手機號碼", phoneNumberLoginPanel);
tabPane.addTab("電子郵件", emailLoginPanel);
this.add(northLogo,BorderLayout.NORTH);
this.add(southPanel,BorderLayout.SOUTH);
this.add(tabPane,BorderLayout.CENTER);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
this.setTitle("QQ登陸");
this.setSize(280, 300);
this.setLocation(300, 150);
this.setVisible(true);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
QqClientLogin qcl = new QqClientLogin();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
System.out.println("用戶登錄");
QqClientUser qcu = new QqClientUser();
User user = new User();
user.setUserName(userNameField.getText());
user.setPassword(new String(passWordField.getPassword()));
System.out.println(user.getUserName()+user.getPassword());
boolean b = qcu.CheckUser(user);
if(b==true){
QqFriendList qfl = new QqFriendList(user.getUserName());
ManageFriendList.addQqFriendList(user.getUserName(), qfl);
//向服務器發送一個請求在線好友列表的包
Socket s = ManageClientThread.getClientConServerThread(user.getUserName()).getSocket();
try {
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
Message mes= new Message();
mes.setMesType(MessageType.message_get_onlinefriendlist);
//要設定sender 不然服務器不會知道是誰的請求
mes.setSender(user.getUserName());
oos.writeObject(mes);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
qfl.setVisible(true);
this.dispose();
}else{
JOptionPane.showMessageDialog(this, "QQ號或密碼錯誤");
}
}
}
package com.QqClient.View;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.QqClient.Management.ManageChat;
import com.QqClient.Model.*;
public class QqFriendList extends JFrame implements ActionListener,MouseListener{
//繪製一個簡單的好友列表
//定義需要的組件
JButton friendListButton1,friendListButton2,friendListButton3;
JButton strangerListButton1,strangerListButton2,strangerListButton3;
JButton hateListButton1,hateListButton2,hateListButton3;
//注意好友列表 黑名單 陌生人三個卡片中的控件要設置成三個 不然調用會出現問題
JLabel[] labelList1,labelList2,labelList3;
JScrollPane list;
JPanel friendListPanel;
JPanel strangerListPanel;
JPanel hateListPanel;
JPanel panel1;
JPanel panel2;
JPanel panel3;
JPanel buttonPanel1,buttonPanel2,buttonPanel3;
String ownerID;
//定義卡片佈局
CardLayout cardLayout;
//定義一個方法用來更新好友的在線列表
public void updateFriendList(String[] onlinFriendList){
for(int i=0;i<onlinFriendList.length;i++){
labelList1[Integer.parseInt(onlinFriendList[i])-1].setEnabled(true);
System.out.println(Integer.parseInt(onlinFriendList[i])+"已被設置成在線");
}
}
public QqFriendList(String ownerID){
this.ownerID = ownerID;
//第一面
friendListButton1 = new JButton("好友列表");
friendListButton1.addActionListener(this);
strangerListButton1 = new JButton("陌生人");
strangerListButton1.addActionListener(this);
hateListButton1 = new JButton("黑名單");
hateListButton1.addActionListener(this);
labelList1 = new JLabel[50];
friendListPanel = new JPanel(new GridLayout(labelList1.length,1,4,4));
for(int i=0;i<labelList1.length;i++){
labelList1[i] = new JLabel(i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList1[i].addMouseListener(this);
labelList1[i].setEnabled(false);
if(labelList1[i].getText().equals(ownerID)){
//只讓用戶自己顯示在線
labelList1[i].setEnabled(true);
}
friendListPanel.add(labelList1[i]);
}
System.out.println("所有圖標已被設置成不在線");
list = new JScrollPane(friendListPanel);
buttonPanel1 = new JPanel(new GridLayout(2,1));
buttonPanel1.add(strangerListButton1);
buttonPanel1.add(hateListButton1);
panel1 = new JPanel();
panel1.setLayout(new BorderLayout());
panel1.add(friendListButton1,BorderLayout.NORTH);
panel1.add(list,BorderLayout.CENTER);
panel1.add(buttonPanel1,BorderLayout.SOUTH);
//第二面
friendListButton2 = new JButton("好友列表");
friendListButton2.addActionListener(this);
strangerListButton2 = new JButton("陌生人");
strangerListButton2.addActionListener(this);
hateListButton2 = new JButton("黑名單");
hateListButton2.addActionListener(this);
labelList2 = new JLabel[20];
strangerListPanel = new JPanel(new GridLayout(labelList2.length,1,4,4));
for(int i=0;i<labelList2.length;i++){
labelList2[i] = new JLabel("壞人"+i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList2[i].addMouseListener(this);
strangerListPanel.add(labelList2[i]);
}
strangerListPanel.addMouseListener(this);
list = new JScrollPane(strangerListPanel);
buttonPanel2 = new JPanel(new GridLayout(2,1));
buttonPanel2.add(friendListButton2);
buttonPanel2.add(strangerListButton2);
panel2 = new JPanel();
panel2.setLayout(new BorderLayout());
panel2.add(buttonPanel2,BorderLayout.NORTH);
panel2.add(list,BorderLayout.CENTER);
panel2.add(hateListButton2,BorderLayout.SOUTH);
//第三面
friendListButton3 = new JButton("好友列表");
friendListButton3.addActionListener(this);
strangerListButton3 = new JButton("陌生人");
strangerListButton3.addActionListener(this);
hateListButton3 = new JButton("黑名單");
hateListButton3.addActionListener(this);
labelList3 = new JLabel[20];
hateListPanel = new JPanel(new GridLayout(labelList3.length,1,4,4));
for(int i=0;i<labelList3.length;i++){
labelList3[i] = new JLabel("黑名"+i+1+"", new ImageIcon("image/QQtouxiang.png"), JLabel.LEFT);
labelList3[i].addMouseListener(this);
hateListPanel.add(labelList3[i]);
}
hateListPanel.addMouseListener(this);
list = new JScrollPane(hateListPanel);
buttonPanel3 = new JPanel(new GridLayout(3,1));
buttonPanel3.add(friendListButton3);
buttonPanel3.add(strangerListButton3);
buttonPanel3.add(hateListButton3);
panel3 = new JPanel();
panel3.setLayout(new BorderLayout());
panel3.add(buttonPanel3,BorderLayout.NORTH);
panel3.add(list,BorderLayout.CENTER);
//運用卡片佈局
cardLayout = new CardLayout();
this.setLayout(cardLayout);
this.add(panel1,"1");
this.add(panel2,"2");
this.add(panel3,"3");
//定義窗體屬性
this.setSize(260, 600);
this.setTitle(ownerID);
this.setIconImage(new ImageIcon("image/QQ.png").getImage());
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
//QqFriendList qfl = new QqFriendList();
}
//對按下button換card進行處理
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
//點擊陌生人的時候顯示卡片2
if(e.getSource()==strangerListButton1
||e.getSource()==strangerListButton2
||e.getSource()==strangerListButton3){
//不允許JFrame直接刷 所以不能直接寫this
cardLayout.show(this.getContentPane(), "2");
}
//點擊黑名單顯示卡片3
else if(e.getSource()==hateListButton1
||e.getSource()==hateListButton2
||e.getSource()==hateListButton3){
cardLayout.show(this.getContentPane(), "3");
}//點擊我的好友的時候顯示卡片1
else if(e.getSource()==friendListButton1
||e.getSource()==friendListButton2
||e.getSource()==friendListButton3){
cardLayout.show(this.getContentPane(), "1");
}
}
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
if(e.getClickCount()==2){
String name = ((JLabel)e.getSource()).getText();
QqChat chat = new QqChat(this.ownerID,name);
//將Chat放入到對應的方法中
ManageChat.addChat(this.ownerID+name, chat);
// //線程的另一種方法
// Thread thread = new Thread(chat);
// thread.start();
}
}
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
JLabel label = (JLabel)e.getSource();
label.setForeground(Color.red);
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
JLabel label = (JLabel)e.getSource();
label.setForeground(Color.black);
}
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
}
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
}
服務器端:
package com.QqServer.Model;
import java.util.*;
public class ManageServerConThread {
//將hashmap做成靜態的 這樣系統只需要維護一個hashmap即可
public static HashMap<String,QqServerConClientThread> hm = new HashMap<String,QqServerConClientThread>();
//將函數編寫爲靜態的 這樣方便直接調用
public static void addClientThread(String getter,QqServerConClientThread clientThread){
//向hashmap中添加線程
hm.put(getter, clientThread);
}
public static QqServerConClientThread getServerConClientThread(String getter){
//返回的是object
return (QqServerConClientThread)hm.get(getter);
}
//返回在線人列表
public static String getOlineFriends(){
//使用迭代器來完成hm的遍歷
String friendList = "";
Iterator it = hm.keySet().iterator();
while(it.hasNext()){
friendList += it.next().toString()+" ";
}
return friendList;
}
}
package com.QqServer.Model;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.*;
import com.Common.Message;
import com.Common.User;
public class QqServer {
public QqServer(){
try {
//這裏代表QQ服務器在9999端口監聽 等待QQ客戶端的連接
ServerSocket ss = new ServerSocket(9999);
//阻塞 等待
System.out.println("服務器已打開,在端口9999監聽");
while(true){
Socket s = ss.accept();
System.out.println("連接成功");
ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
User user = (User)ois.readObject();
Message mes = new Message();
//這裏只做簡單判斷 因爲連接數據庫過於繁瑣
System.out.println(user.getPassword());
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
if(user.getPassword().equals("123456")){
mes.setMesType("1");
System.out.println(mes.getMesType());
oos.writeObject(mes);
//連接成功以後,需要在服務器端建立線程來控制與客戶端的鏈接 以防止因客戶端過多造成服務器混亂
QqServerConClientThread qscct = new QqServerConClientThread(s);
//將連接成功的客戶端的socket保存在hashmap中 方便返回信息
ManageServerConThread.addClientThread(user.getUserName(),qscct);
//線程創建後 通知其他在線的人他上線了
qscct.notifyOthers(user.getUserName());
//啓動和用戶通訊的線程
qscct.start();
}else{
mes.setMesType("2");
oos.writeObject(mes);
s.close();
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally{
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
package com.QqServer.Model;
import java.net.*;
import java.io.*;
import com.Common.*;
//這是一個用來維護與客戶端通訊的線程
public class QqServerConClientThread extends Thread{
Socket socket;
public QqServerConClientThread(Socket socket){
//首先要接受並保存此線程對應客戶端的Socket
this.socket = socket;
}
//定義一個函數用來通知其他在線用戶此線程的擁有者已經上線
public void notifyOthers(String owner){
//得到在線人的id
String friendlist = ManageServerConThread.getOlineFriends();
String friends[] = friendlist.split(" ");
Message mes = new Message();
mes.setSender(owner);
mes.setMesType(MessageType.message_onlinefriendlist);
mes.setContent(owner);
for(int i=0;i<friends.length;i++){
mes.setGetter(friends[i]);
System.out.println("我是"+owner+" 我要告訴"+friends[i]+" 我上線了");
try {
ObjectOutputStream oos = new ObjectOutputStream(ManageServerConThread.getServerConClientThread(friends[i]).socket.getOutputStream());
oos.writeObject(mes);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void run(){
//這裏在線程啓動後便可接受來自對應客戶端的信息
while(true){
try {
ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
Message mes = (Message)ois.readObject();
//讀取mes內的相關信息
//System.out.println(mes.getSender()+" 對 "+mes.getGetter()+"說: "+mes.getContent());
//對來自客戶端的信息類型進行驗證 以便進行相應的處理
if(mes.getMesType().equals(MessageType.message_communicate_content)){
//回覆時要得到對應客戶端的Socket 因此 應該將接受到的socket存儲在一個hashmap中 便於管理和查找
//根據得到的getter 從hashmap中得到對應的socket
Socket getterSocket = ManageServerConThread.getServerConClientThread(mes.getGetter()).socket;
ObjectOutputStream oos = new ObjectOutputStream(getterSocket.getOutputStream());
oos.writeObject(mes);
}else if(mes.getMesType().equals(MessageType.message_get_onlinefriendlist)){
//返回對應的好友列表
//從管理線程的地方得到所有在線信息
String friendList = ManageServerConThread.getOlineFriends();
Message returnMes = new Message();
returnMes.setContent(friendList);
returnMes.setMesType(MessageType.message_onlinefriendlist);
returnMes.setGetter(mes.getSender());
//得到的發送者的Socket 把好友列表返回給他
Socket s = ManageServerConThread.getServerConClientThread(mes.getSender()).socket;
ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
oos.writeObject(returnMes);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
package com.QqServer.View;
import javax.swing.*;
import com.QqServer.Model.QqServer;
import java.awt.*;
import java.awt.event.*;
public class QqServerFrame extends JFrame implements ActionListener{
JButton startButton;
JButton stopButton;
JPanel northPanel;
public QqServerFrame(){
startButton = new JButton("啓動服務器");
startButton.addActionListener(this);
stopButton = new JButton("關閉服務器");
northPanel = new JPanel();
northPanel.add(startButton);
northPanel.add(stopButton);
this.add(northPanel,BorderLayout.NORTH);
this.setSize(400, 300);
this.setLocation(550, 150);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
QqServerFrame qsf = new QqServerFrame();
}
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
if(e.getSource()==startButton){
System.out.println("準備啓動服務器");
QqServer qs =new QqServer();
}
}
}
c
com.Common包中的類是一樣的,用來描述客戶端在相互聊天時以及與服務器交互的規則,因此我只在客戶端粘貼了對應的代碼,不過兩個工程文件中都要有,服務器的開始類是QqServerFrame 客戶端的開始類是 QqClientLogin 注意一定要先開啓服務器再運行客戶端
只完成了一些非常簡單的功能 希望大神們不要笑話
效果圖: