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       注意一定要先开启服务器再运行客户端    


只完成了一些非常简单的功能   希望大神们不要笑话


效果图:

  


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值