java學習筆記------java網絡編程五

有很多天沒有寫了,這些天跟着視頻教程,學着做了一個非常簡單的聊天程序,當然是仿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();
		}
	}

}


myEclipse中的工程結構:

       

  c

    

com.Common包中的類是一樣的,用來描述客戶端在相互聊天時以及與服務器交互的規則,因此我只在客戶端粘貼了對應的代碼,不過兩個工程文件中都要有,服務器的開始類是QqServerFrame     客戶端的開始類是 QqClientLogin       注意一定要先開啓服務器再運行客戶端    


只完成了一些非常簡單的功能   希望大神們不要笑話


效果圖:

  


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章