QQ_2

4. 升级版三-----解决:一对多发送,多对多。

4.1 假设客户端1号QQ给多个客户端用户发送消息时,socket会被占用,在服务器中转时出现异常。1号QQ给2号QQ和3号QQ发消息,就会出现socket占用问题。

 

下图中每个方框假设是一台电脑,一台电脑登陆多个客户端。

(1)新建ClientConServerThread类,只要一个账号登陆了,就开启一个线程,让这个线程和服务器保持通讯。
  新建构造方法,继承Thread,run()不断循环获取
(2)新建类:ManageClientConServerThread,管理客户端和服务器保持通讯的线程类。
  定义HashMap集合,k:你登陆的那个QQ的号码,
(3)找到sendLoginInfoToServer,进行验证用户登陆。
  在ClientConServerThread里不断读取来自服务器的内容。

/*换工作区之后,设置失效了,87集15分钟30秒左右。
 * 1.新建两个项目,命名为QqClint、QqServer.
 * 2.当用户点击登录后,吧QQ号码和密码发送给QQServer端去验证,如果合法返回OK,如果不合法返回error
 * 补充讲:新知识,如何在网络间传递对象流。写个擦拭类TestClient、TestServer
 * 3.对message规定一些规则。
 * mesType 1 --> 表明登录成功
 * mesType 2 --> 表明登录失败
 * mesType 3 --> 表明是普通消息包
 * 
 *步骤:
 *1.在客户端QqClint--view里建类1.login-----2.FriendList-----3.Chat
 *2. 服务器端QqServer--view里新建类MyServerFrame,这是服务器端的控制界面,可以完成启动服务器,关闭服务器;通过实现ActionListener接口--actionPerformed调用new MyQqServer(); MyQqServer类在服务器端QqServer---model里,这是QQ服务器,它在监听,等待某个QQ客户端,未连接。
3.客户端QqClint---common里面定义Message类和User类,User类:用户信息类,包含userId和passwd。Message类里实现序列化接口并包含mesType变量,1.实现java.io.Serializable接口;2.定义私有变量mesType,并将类拷贝到QQServer类下的common里一份。
4.客户端QqClint---model里面定义(1)QqClientConServer类:客户端连接服务器的后台.
5.客户端QqClint---view----QqLogin类的jp1_jb1登陆按钮添加响应---监听actionPerformed里---创建QqClientUser并调用checkUser,验证方法是否合法,其实调用的是new QqClientConServer().sendLoginInfoToServer---发送第一次请求---调用getMesType方法,

    新建类(数据库相关的):QqServer----model---QqServerUser
    新建包:数据库包DB,并在其中定义SqlHelper类
 */
package view;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import common.User;
import model.QqClientUser;

public class QqLogin extends JFrame implements ActionListener {
    // 4.修改前景色。
    public static void main(String[] args) {
        QqLogin l = new QqLogin();
    }

    JLabel jbl1; // 1.定义北部,JLabel
    JPanel jp1; // 2.定义南部流布局JPanel以及3个按钮
    JButton jp1_jb1, jp1_jb2, jp1_jb3;
    // 3.定义中部--有3个JPanel,由一个叫做选项卡窗口管理;jp2放置网格布局,就是首页那9个
    JTabbedPane jtp;
    JPanel jp2, jp3, jp4;
    JLabel jp2_jbl1, jp2_jbl2, jp2_jbl3, jp2_jbl4;
    JButton jp2_jb1;
    JTextField jp2_jtf;
    JPasswordField jp2_jpf;
    JCheckBox jp2_jcb1, jp2_jcb2;

    public QqLogin() {

        jbl1 = new JLabel(new ImageIcon("image/tou.gif"));// 北部

        jp1 = new JPanel(); // 南部
        jp1_jb1 = new JButton(new ImageIcon("image/denglu.gif"));
        jp1_jb1.addActionListener(this);                         // 06-12-01响应用户登录
        jp1_jb2 = new JButton(new ImageIcon("image/quxiao.gif"));
        jp1_jb3 = new JButton(new ImageIcon("image/xiangdao.gif"));
        // 把三个按钮放到jp1,即登录、取消、注册向导
        jp1.add(jp1_jb1);
        jp1.add(jp1_jb2);
        jp1.add(jp1_jb3);
        // 中部--有3个JPanel,由一个叫做选项卡窗口管理;jp2放置网格布局,就是首页那9个
        jtp = new JTabbedPane();
        jp2 = new JPanel(new GridLayout(3, 3));
        jtp.add("QQ号码", jp2);
        jp3 = new JPanel();
        jtp.add("手机号码", jp3);
        jp4 = new JPanel();
        jtp.add("电子邮件", jp4);

        jp2_jbl1 = new JLabel("QQ号码", JLabel.CENTER);
        jp2_jtf = new JTextField();
        jp2_jb1 = new JButton(new ImageIcon("clear.gif"));
        jp2_jbl2 = new JLabel("QQ密码", JLabel.CENTER);
        jp2_jpf = new JPasswordField();
        jp2_jbl3 = new JLabel("忘记密码", JLabel.CENTER);
        jp2_jcb1 = new JCheckBox("隐身登录");
        jp2_jcb2 = new JCheckBox("记住密码");
        jp2_jbl4 = new JLabel("申请密码保护", JLabel.CENTER);
        // 添加前景色
        jp2_jbl3.setForeground(Color.blue);
        // 把控件按照顺序加入到jp2
        jp2.add(jp2_jbl1);
        jp2.add(jp2_jtf);
        jp2.add(jp2_jb1);
        jp2.add(jp2_jbl2);
        jp2.add(jp2_jpf);
        jp2.add(jp2_jbl3);
        jp2.add(jp2_jcb1);
        jp2.add(jp2_jcb2);
        jp2.add(jp2_jbl4);

        this.add(jbl1, "North");
        this.add(jp1, "South");
        this.add(jtp, "Center");
        this.setSize(350, 240);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == jp1_jb1) {            //jp1_jb1登录按钮---并给jp1_jb1进行注册监听(69行左右)
            //1.点击登陆------->2.调用QqClientUser的checkUser,其实调用的是                                                                         
            User u = new User();
            u.setUserId(jp2_jtf.getText().trim());                    //输入框JTextField的jp2_jtf里面拿内容
            u.setPasswd(new String(jp2_jpf.getPassword()));            //密码框JPasswordField的jp2_jpf的内容为字符串数组,需要new一下
            
            //7.客户端的QqLogin的actionPerformed
            QqClientUser qqClientUser = new QqClientUser();
            if(qqClientUser.checkUser(u)){
                new QqFriendList(u.getUserId());    //1_2---->1_3QQFriendList好友列表将其显示
                //关闭登录界面
                this.dispose();
            }else{
                JOptionPane.showMessageDialog(this, "用户名密码错误");
            }
        }
    }
}
QqLogin
/*1.GridLayout 类是一个布局处理器,它以矩形网格形式对容器的组件进行布置。容器被分成大小相等的矩形,一个矩形中放置一个组件。
 *2.这是一个布置容器的边框布局,它可以对容器组件进行安排,并调整其大小,使其符合下列五个区域:北、南、东、西、中。每个区域最多只能包含一个组件:NORTH、SOUTH、EAST、WEST、CENTER。
 *JLabel:用于短文本字符串或图像或二者的显示区。
GridLayout() 一行一列
GridLayout(int rows, int cols) rows行 cols列
GridLayout(int rows, int cols, int hgap, int vgap) rows行 cols 列, 列间距hgap, 行间距vgap
 * */
package view;
import java.awt.BorderLayout;
import java.awt.CardLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;

import model.ManageQqChat;
public class QqFriendList extends JFrame implements MouseListener,ActionListener{
    /*    1.主类继承JFrame---定义构造方法---定义3个JPanel,3个按钮,1个滚动条
     *    2.初始化3个按钮:jp_jb1,jp_jb2,jp_jb3
     *    3.定义中间的滚动列表。初始化JPanel:jp2----定义for循环产生50个列表---将jp2添加到JScrollPane:jsp1
     *    4.定义最下面:             初始化JPanel:jp3-----GridLayout布局,放入两个按钮:jp_jb2,jp_jb3
     *    5.定义整体:            初始化JPanel:jp1-----BorderLayout布局---将jp2,jp3,jp_jb1加入进来
     *    6.添加到显示:        jp1添加到显示并做基本设置。
重点代码:2. jp_jb1 = new JButton("我的好友");
        3.jp2 = new JPanel(new GridLayout(50,1,4,4)); 
            JLabel[] jbls = new JLabel[50];   
            jbls[i] = new JLabel(i+1+"",new ImageIcon("image/mm.jpg"),JLabel.LEFT);
            jsp1 = new JScrollPane(jp2);
        4.jp3 = new JPanel(new GridLayout(2,1));
        5.jp1 = new JPanel(new BorderLayout());
            jp1.add(jp_jb1,"North");  jp1.add(jsp1,"Center");
        6. this.add(jp1,"Center");
        
        1.复制上面代码并修改名称---定义CardLayout c1并把整个JFrame设置成CardLayout---定义显示相关设置
        2.添加MouseListener---定义mouseEntered\mouseExited
        3.添加ActionListener--定义actionPerformed
     */
    public static void main(String[] args) {
//        QqFriendList t = new QqFriendList();
    }
    JPanel jp1,jp2,jp3;
    JButton jb1,jb2,jb3;
    JScrollPane jsp1;
    
    String ownerId;
    
    //2.1
    JPanel jpmsr1,jpmsr2,jpmsr3;
    JButton jpmsr_jb1,jpmsr_jb2,jpmsr_jb3;
    JScrollPane jsp2;
    //2.4把整个JFrame设置成CardLayout
    CardLayout c1;
    public QqFriendList(String ownerId){        //1_1添加好友的号码----->1_2注册QQLogin的actionPerformed里
        
        this.ownerId = ownerId;
        
        jb1 = new JButton("我的好友");
        jb2 = new JButton("陌生人");
        jb3 = new JButton("黑名单");
        jb2.addActionListener(this);            //2.6(3)
        
        jp1 = new JPanel(new GridLayout(50,1));
        JLabel[] jls = new JLabel[50];
        for (int i = 0; i < jls.length; i++) {
            jls[i] = new JLabel(i+1+"",new ImageIcon("image/mm.jpg"),JLabel.LEFT);
            //默认只有自己显示为彩色。
            jls[i].setEnabled(false);
            if(jls[i].getText().equals(ownerId)){
                jls[i].setEnabled(true);
            }
            
            jls[i].addMouseListener(this);        //2.6(1)
            jp1.add(jls[i]);
        }
        jsp1 = new JScrollPane(jp1);
        
        jp2 = new JPanel(new GridLayout(2,1));
        jp2.add(jb2);
        jp2.add(jb3);
        
        jp1 = new JPanel(new BorderLayout());
        jp1.add(jb1,"North");
        jp1.add(jsp1,"Center");
        jp1.add(jp2,"South");
        
        //处理第二张
        jpmsr_jb1 = new JButton("我的好友");
        jpmsr_jb2 = new JButton("陌生人");
        jpmsr_jb3 = new JButton("黑名单");
        jpmsr_jb1.addActionListener(this);        //2.6(3)
        
        //2.2-jpmsr2---jpmsr2添加到滚动组件JScrollPane
        jpmsr2 = new JPanel(new GridLayout(20,1,4,4));        //rows行cols列,列间距hgap,行间距vgap
        JLabel[] jbls2 = new JLabel[20];                    //给jphy2初始化20个好友
        for (int i = 0; i < jbls2.length; i++) {
            jbls2[i] = new JLabel(i+1+"",new ImageIcon("image/mm.jpg"),JLabel.LEFT);
            jbls2[i].addMouseListener(this);        //2.6(2)
            jpmsr2.add(jbls2[i]);
        }
        jsp2 = new JScrollPane(jpmsr2);
        
        //2.3.初始化jpmsr3
        jpmsr3 = new JPanel(new GridLayout(2,1));        
        jpmsr3.add(jpmsr_jb1);
        jpmsr3.add(jpmsr_jb2);
        
        //2.1.初始化jpmsr1
        jpmsr1 = new JPanel(new BorderLayout());
        jpmsr1.add(jpmsr3,"North");
        jpmsr1.add(jsp2,"Center");
        jpmsr1.add(jpmsr_jb3,"South");
        
        //2.5----2.6实现MouseListener、ActionListener----注册监听
        c1 = new CardLayout();
        this.setLayout(c1);
        this.add(jp1,"1");        //将第一个整体布局jp1放到这里
        this.add(jpmsr1,"2");    //将第二个整体布局jpmsr1放到这里
        this.setTitle(ownerId);    //1_3 在窗口显示自己的编号
        this.setSize(200,500);
        this.setVisible(true);
    }
    
    @Override
    public void mouseClicked(MouseEvent e) {
        //响应用户双击的事件,并得到好友的编号
        if(e.getClickCount()==2){
            //得到该好友的编号
            String friend = ((JLabel)e.getSource()).getText();
            System.out.println("我在QqFriendList,你希望和"+friend+"谁聊天");
            
            Chat chat = new Chat(this.ownerId,friend);    //启动聊天界面的线程。
            /*Thread t = new Thread(chat);
            t.start();*/
            
            //把聊天页面加入到管理类
            ManageQqChat.addQqChat(this.ownerId+" "+friend, chat);
            
        }
    }
    @Override
    public void mousePressed(MouseEvent e) {
    }
    @Override
    public void mouseReleased(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {
        JLabel j1 = (JLabel)e.getSource();
        j1.setForeground(Color.red);
    }
    @Override
    public void mouseExited(MouseEvent e) {
        JLabel j1 = (JLabel)e.getSource();
        j1.setForeground(Color.black);
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==jb2){        //第一个的按钮2,就显示第二张卡片
            c1.show(this.getContentPane(), "2");
        }else if(e.getSource()==jpmsr_jb1){    //第二个的按钮1
            c1.show(this.getContentPane(), "1");
        }
    }
}
QqFriendList
package view;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.util.Date;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import model.ManageClientConServerThread;

import common.Message;
public class Chat extends JFrame implements ActionListener{
    private static final long serialVersionUID = 1L;
    /*与朋友聊天的截面
     * 1.定义JTextArea---定义JTextField和JButton----定义JPanel
     * 2.设置默认设置
     * 3.将Chat()构造方法改为有参构造方法。
     * 4.在FriendList方法mouseClicked()中调用本类的Chat(String friend)方法
     */
    public static void main(String[] args) {
//        Chat c = new Chat("1");
    }
    JTextArea jta ;
    JTextField jtf ;
    JButton jb1;
    JPanel  jp1;
    String ownerId;
    String friendId;
    public Chat(String ownerId,String friend){
        this.ownerId = ownerId;
        this.friendId = friend;
        jta = new JTextArea();
        jtf = new JTextField(15);
        jb1 = new JButton("发送");
        jb1.addActionListener(this);    //添加监听
        jp1 = new JPanel();
        jp1.add(jtf);
        jp1.add(jb1);
        
        this.add(jta,"Center");
        this.add(jp1,"South");
        this.setTitle(ownerId+"正在和"+friend+"聊天");
        this.setIconImage(new ImageIcon("image/qq.gif").getImage());
        this.setSize(300,250);
        this.setVisible(true);
    }
    
    //写一个方法,让他显示
    public void showMessage(Message m){
        String info = "我在Chat,"+m.getSender() + "对"+m.getGetter()+"说"+ m.getCon()+"\r\n";
        this.jta.append(info);
    }
    
    @Override
    public void actionPerformed(ActionEvent e) {
        //如果点击发送按钮,获取发送者的编号、接收者的编号、文本框里的发送内容、获取发送时间
        if(e.getSource() == jb1){
            Message m  = new Message();  
            m.setSender(this.ownerId);
            m.setGetter(this.friendId);
            m.setCon(jtf.getText());
            m.setSendTime(new Date().toString());    //转为字符串
        //使用输出流,发送给服务器,将Socket做成静态的
            try {
                //管理线程的类取到线程,再取到socket,再通过socket取到输出流
                ObjectOutputStream oos = new ObjectOutputStream(ManageClientConServerThread.getClientConServerThread(ownerId).getS().getOutputStream());
                oos.writeObject(m);
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
/*    @Override
    public void run() {
        while(true){
            //读取
            try {
                ObjectInputStream ois= new  ObjectInputStream(QqClientConServer.s.getInputStream());
                Message m = (Message) ois.readObject();        //并将信息显示在文本域上jta
                //显示
                String info = m.getSender() + "对"+m.getGetter()+"说"+ m.getCon()+"\r\n";
                this.jta.append(info);
                
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }*/
}
Chat

------model-------

package model;

import java.io.ObjectInputStream;
import java.net.Socket;

import view.Chat;

import common.Message;

public class ClientConServerThread extends Thread{
    private Socket s;
    public Socket getS() {
        return s;
    }
    public void setS(Socket s) {
        this.s = s;
    }
    
    public ClientConServerThread(Socket s){
        this.s = s;
    }
    public void run(){
        while(true){
            //不断的读取从服务器端发来的消息
            try {
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                Message m = (Message)ois.readObject();
                System.out.println("我在ClientConServerThread,读取从服务器发来的消息"+m.getSender()+"给"+m.getGetter()+"内容"+m.getCon());
                
                //把从服务器获得消息,显示到该显示的聊天界面
                Chat qqchat0 = ManageQqChat.getQqChat(m.getGetter()+" "+m.getSender());
                qqchat0.showMessage(m);  //显示
                
            } catch (Exception e) {
                // TODO: handle exception
            }
        }
    }
}
ClientConServerThread
package model;

import java.util.HashMap;

public class ManageClientConServerThread {
    private static HashMap hm = new HashMap<String,ClientConServerThread>();
    
    //把创建好的ClientConServerThread放到hm
    public static void addClientConServerThread(String qqId,ClientConServerThread cost){
        hm.put(qqId, cost);
    }
    
    //通过qqId取的线程
    public static ClientConServerThread getClientConServerThread(String qqId){
        return (ClientConServerThread)hm.get(qqId);
    }
}
ManageClientConServerThread
package model;
import java.util.HashMap;
import view.Chat;

public class ManageQqChat {
    private static HashMap hm = new HashMap<String,Chat>();
    
    //加入
    public static void addQqChat(String loginIdAnFriendId,Chat qqchat){
        hm.put(loginIdAnFriendId,qqchat);
        
    }
//    取出
    public static Chat getQqChat(String loginIdAnFriendId){
        return (Chat)hm.get(loginIdAnFriendId);
    }
}
ManageQqChat
//QqClientConServer类:客户端连接服务器的后台
package model;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import common.Message;
import common.User;
public class QqClientConServer {
    public static Socket s;

    //6.sendLoginInfoToServer(发送第一次请求)----------->2.QqClientUser的checkUser
    public boolean sendLoginInfoToServer(Object o){
        boolean b = false;
        try {
            System.out.println("我在QqClientConServer的try里面");
            //1.客户端通过9999端口号通过ObjectOutputStream对象输出流给服务器端发送内容----->2.MyQqServer
            s = new Socket("127.0.0.1",9999);
            ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
            oos.writeObject(o);
            
            //写过去又读回来
            //4.下面的ObjectInputStream获取服务器端的ObjectOutputStream输出----->5.进行判断,给sendLoginInfoToServer返回true/false
            ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
            Message ms = (Message)ois.readObject();
            
            //5.进行判断,给sendLoginInfoToServer返回true/false------>6.sendLoginInfoToServer
            if(ms.getMesType().equals("1")){        
                //创建一个该qq号和服务器端保持通讯连接的线程
                ClientConServerThread ccst = new ClientConServerThread(s);
                //qq号取出来作为第一个参数,创建的线程作为第二个参数。启动该通讯线程
                ccst.start();
                ManageClientConServerThread.addClientConServerThread(((User)o).getUserId(), ccst);
                b = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            
        }
        return b;
    }
}
QqClientConServer
package model;
import common.User;

//2.验证方法是否合法,返回true/false------>7.客户端的QqLogin的actionPerformed
public class QqClientUser {
    public boolean checkUser(User u){
        return new QqClientConServer().sendLoginInfoToServer(u);    //客户端QqClientConServer的sendLoginInfoToServer。返回一个对象
    }
}
QqClientUser

------common----

package common;
//1.实现java.io.Serializable接口,
//2.定义私有变量mesType,并将本类拷贝到QQServer类下的common里
public class Message implements java.io.Serializable{
    private String mesType;
    private String sender;
    private String getter;
    private String con;
    private String sendTime;
    
    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getGetter() {
        return getter;
    }
    public void setGetter(String getter) {
        this.getter = getter;
    }
    public String getCon() {
        return con;
    }
    public void setCon(String con) {
        this.con = con;
    }
    public String getSendTime() {
        return sendTime;
    }
    public void setSendTime(String sendTime) {
        this.sendTime = sendTime;
    }
    public String getMesType() {
        return mesType;
    }
    public void setMesType(String mesType) {
        this.mesType = mesType;
    }
    
}
Message
package common;
/*用户信息类*/
public class User implements java.io.Serializable{
    private String userId;
    private String passwd;
    public String getUserId() {
        return userId;
    }
    public void setUserId(String userId) {
        this.userId = userId;
    }
    public String getPasswd() {
        return passwd;
    }
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
    
}
User

服务器端:----------------------QqServer------------------------

--------------view------------(同上)

package model;
import java.util.HashMap;
public class ManagerClientThread {
    public static HashMap hm = new HashMap<String,SerConClientThread>();
    
    //向HashMap中添加一个客户端通讯线程
    public static void addClientThread(String uid,SerConClientThread ct){
        hm.put(uid,ct);
    }
    
    // 获取用户的id
    public static SerConClientThread getClientThread(String uid){
        return (SerConClientThread)hm.get(uid);
    }
}
ManagerClientThread
package model;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import common.Message;
import common.User;
public class MyQqServer {
    /**这是QQ服务器,它在监听,等待某个QQ客户端,未连接
     * 1.构造方法MyQqServer---try、finally---
     * 2.添加while循环进行循环监听。避免当输入错误时,服务器不能两次登录
     */
    public static void main(String[] args) {

    }
    public MyQqServer(){
        try {
            System.out.println("我在MyQqServer,99999监听");
            ServerSocket ss = new ServerSocket(9999);    //在9999监听
            while(true){
                Socket s = ss.accept();    //阻塞、等待连接
                //2.接收客户端发来的信息。第一次发的是用户名和密码---(传输到)-->3.服务器端MyQqServer的ObjectOutputStream输出
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                User u = (User)ois.readObject();
                System.out.println("我在MyQqServer,服务器接收用户ID"+u.getUserId()+" 密码 "+u.getPasswd());
                
                //3.调用Message,给mesType赋值--->下面的ObjectOutputStream输出----->4.客户端QqClientConServer的sendLoginInfoToServer的ObjectInputStream
                ObjectOutputStream oos = new ObjectOutputStream(s.getOutputStream());
                Message m = new Message();
                
                if(u.getPasswd().equals("123456")){
                    
                    m.setMesType("1");                //返回一个成功登录的信息包
                    oos.writeObject(m);
                    
                    //这里就单开一个线程,让该线程与客户端保持通讯
                    SerConClientThread scct =  new SerConClientThread(s);
                    ManagerClientThread.addClientThread(u.getUserId(),scct);
                    //启动与给客户端通讯的线程
                    System.out.println("我在MyQqServer:hello");
                    scct.start();
                    
                }else{
                    m.setMesType("2");
                    oos.writeObject(m);
                    s.close();
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
        }finally{
            
        }
    }
}
MyQqServer
package model;
//功能:服务器和某个客户端的通信线程
import java.net.*;
import java.io.*;
import common.Message;
public class SerConClientThread extends Thread{
    
    Socket s;
    public SerConClientThread(Socket s){
        //把服务器和该客户端的连接赋值给s
        this.s  = s ;
    }
    public void run(){
        while(true){
            try {
                ObjectInputStream ois = new ObjectInputStream(s.getInputStream());
                Message m =(Message) ois.readObject();        //将Object转成Message
                System.out.println("我在SerConClientThread,"+m.getSender()+"给"+m.getGetter()+" 说 "+m.getCon());
                
                //一会完成转发任务。找到接收人的通讯线程,然后发出去
                SerConClientThread sc2 = ManagerClientThread.getClientThread(m.getGetter());
                ObjectOutputStream oos = new ObjectOutputStream(sc2.s.getOutputStream());
                oos.writeObject(m);        //将从m里读取到的内容发出去
            } catch (Exception e) {
                // TODO: handle exception
            }
    }
}
}
SerConClientThread

--------view------

package view;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

import model.MyQqServer;
public class MyServerFrame extends JFrame implements ActionListener{
    /**服务器端的控制界面,可以完成启动服务器,关闭服务器
     */
    public static void main(String[] args) {
        MyServerFrame m = new MyServerFrame();
    }
    JPanel jp1;
    JButton jb1,jb2;
    
    public MyServerFrame(){
        jb1 = new JButton("开启服务器");
        jb1.addActionListener(this);        //注册监听
        jb2 = new JButton("强制下线");
        jp1 = new JPanel();
        jp1.add(jb1);
        jp1.add(jb2);
        
        this.add(jp1,"Center");
        this.setSize(500,400);
        this.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if(e.getSource()==jb1){
            new MyQqServer();
        }
    }
}
MyServerFrame

 

posted @ 2019-06-25 12:45  ChengXiaoFeng  阅读(318)  评论(0)    收藏  举报