聊天室

聊天室

 

 

服务端

package chatroom;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * 聊天室服务器端 ChatRoomServer类
 *
 * @version 1.01, 09/04/10
 */
public class ChatRoomServer {
    private ServerSocket ss;
    /* 存放Socket的集合hs */
    private HashSet<Socket> hs;

    public ChatRoomServer() {
        JFrame jf = new JFrame();
        do {
            /*
             * 弹出输入对话框,提示输入服务器需要绑定的端口号
             */
            int port = Integer.parseInt(JOptionPane.showInputDialog(jf,
                    "bind port:"));
            try {
                ss = new ServerSocket(port);
                System.out.println("server start success,now listening port:"
                        + port);
            } catch (Exception e) {
                /* 弹出确认框进行确认 */
                int op = JOptionPane.showConfirmDialog(jf, // 指定是在jf中弹出确认框
                        "bind fail,retry?", // 框体内容
                        "bind fail", // 对话框的标题
                        JOptionPane.YES_NO_OPTION); // 确认框按钮项
                /* 如果选择'否',则退出程序 */
                if (op == JOptionPane.NO_OPTION) {
                    System.exit(1);
                }
                /* 打印异常栈信息 */
                e.printStackTrace();
            }
        } while (ss == null);

        /* 创建HashSet,用来存放Socket对象 */
        hs = new HashSet<Socket>();

        while (true) {
            try {
                /* 获得Socket,网络阻塞,等待客户端的连接 */
                Socket s = ss.accept();

                /* 一旦客户端连接上,则加入HashSet,便于维护 */
                hs.add(s);

                /* 启动一个服务线程,为客户端服务 */
                new ServerThread(s).start();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 成员内部类,服务线程类
     */
    class ServerThread extends Thread {
        private Socket s;

        public ServerThread(Socket s) {
            this.s = s;
        }

        @Override
        public void run() {
            BufferedReader br = null;
            try {
                br = new BufferedReader(new InputStreamReader(s
                        .getInputStream()));
                while (true) {
                    /* 从网络中读取客户端发出的消息 */
                    String str = br.readLine();
                    /*
                     * 客户退出时的处理逻辑 规则:以"%EXIT_CHATROOM%"开头的消息为客户退出标记
                     */
                    if (str.charAt(0) == '%') {
                        String com = str.split("%")[1];
                        if (com.equals("EXIT_CHATROOM")) {
                            hs.remove(s);
                            printMessage(str.split("%")[2] + ",leave!");

                            s.close();
                            break;
                        }
                    } else {
                        /* 正常情况,直接向客户端群发消息 */
                        printMessage(str);
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        /*
         * 负责为客户端群发消息
         */
        private void printMessage(String mes) {
            System.out.println(mes);
            try {
                /* 遍历所有Socket */
                for (Socket s : hs) {
                    PrintStream ps = new PrintStream(s.getOutputStream());
                    /* 产生发消息的时刻 */
                    Date date = new Date();
                    SimpleDateFormat sdf = new SimpleDateFormat(
                            "yyyy-MM-dd HH:mm:ss");
                    /* 向客户端发消息,消息结构为mes [yyyy-MM-dd HH:mm:ss] */
                    ps.println(mes + " [" + sdf.format(date) + "]");

                    /* 注意需要及时flush,清空缓冲区 */
                    ps.flush();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /*
     * 主方法,启动聊天室服务器端
     */
    public static void main(String[] args) {
        new ChatRoomServer();
    }

}

 

客户端窗体

package chatroom;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

/**
 * 客户端窗口ChatRoomClientFrame类 负责客户端的视图表示、事件处理等逻辑 作为一个窗口,所以本类继承自JFrame
 * 为了实现事件处理,本类实现了ActionListener接口
 *
 * @version 1.01, 09/04/10
 */
public class ChatRoomClientFrame extends JFrame implements ActionListener {
    private static final long serialVersionUID = 3484437496861281646L;
    private JTextArea jta; // 多行文本域
    private JLabel label; // 文本标签
    private JTextField jtf; // 单行文本框
    private JButton jb; // 按钮
    private Socket socket; // socket 套接字
    private String name; // 用户名

    /*
     * ChatRoomClientFrame构造方法,负责初始化以及添加事件处理
     */
    public ChatRoomClientFrame(String name, Socket socket) {
        super("chatroom");
        Font f = new Font("楷体", Font.BOLD, 20); /* 设置字体 */
        jta = new JTextArea(10, 10); /* 创建10行10列的空多行文本域 */
        jta.setEditable(false); /* 设置多行文本域为不可编辑 */
        jta.setFont(f); /* 设置多行文本域字体 */
        label = new JLabel(name + ":"); /* 创建带有用户名的文本标签 */
        label.setFont(f); /* 设置文本标签字体 */
        jtf = new JTextField(25); /* 创建单行文本框 */
        jtf.setFont(f); /* 设置单行文本框字体 */
        jb = new JButton("send"); /* 创建按钮 */

        this.name = name;
        this.socket = socket;

        init(); /* 初始化,设置组件关系 */

        addEventHandler(); /* 为组件添加事件监听 */
    }

    /*
     * 初始化组件关系方法,供构造方法调用
     */
    private void init() {
        JScrollPane jsp = new JScrollPane(jta);
        this.add(jsp, BorderLayout.CENTER);
        JPanel jp = new JPanel();
        jp.add(label);
        jp.add(jtf);
        jp.add(jb);
        this.add(jp, BorderLayout.SOUTH);
    }

    /*
     * 负责为各组件添加事件处理机制
     */
    private void addEventHandler() {
        jb.addActionListener(this); // 为jb添加事件监听,JButton点击触发事件
        jtf.addActionListener(this); // 为jtf添加事件监听,JTextField敲回车触发事件
        /* 设置JFrame默认关闭状态:DO_NOTHING_ON_CLOSE */
        this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);

        /* 为JFrame添加窗口事件监听 */
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                /* 弹出确认框进行交互 */
                int op = JOptionPane.showConfirmDialog(
                        ChatRoomClientFrame.this, "exit?", "exit",
                        JOptionPane.YES_NO_OPTION);
                if (op == JOptionPane.YES_OPTION) {
                    try {
                        PrintStream ps = new PrintStream(socket
                                .getOutputStream());
                        /* 向服务器发送以%EXIT_CHATROOM%name为格式的串,代表退出信号 */
                        ps.println("%EXIT_CHATROOM%" + name);
                        /* 注意需要及时flush */
                        ps.flush();

                        try {
                            Thread.sleep(168); // 进行延时控制,防止提前关闭socket
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }

                        socket.close(); // 关闭客户端socket
                        ps.close(); // 关闭流
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    System.exit(1); // 退出程序
                }
            }
        });
    }

    /*
     * 实现事件处理方法
     */
    public void actionPerformed(ActionEvent ae) {
        try {
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(name + ": " + jtf.getText());
            ps.flush();
            /* 清空jtf中内容 */
            jtf.setText("");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /*
     * 显示并执行窗口逻辑
     */
    public void showMe() {
        this.pack(); // 自动调整此窗口的大小
        this.setVisible(true); // 设置窗口可见
        /*
         * 启动线程,负责接收服务器端发来的消息
         */
        new Thread() {
            @Override
            public void run() {
                BufferedReader br = null;
                try {
                    br = new BufferedReader(new InputStreamReader(socket
                            .getInputStream()));
                    while (true) {
                        /* 从网络中读取服务器发出的数据 */
                        String str = br.readLine();
                        /* 对JTextArea进行追加消息 */
                        jta.append(str + "\n");
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }

}
客户端

package chatroom;

import java.io.PrintStream;
import java.net.Socket;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

/**
 * 聊天室客户端 ChatRoomClient
 *
 * @version 1.01, 09/04/10
 */
public class ChatRoomClient {
    private String name; // 用户名
    private Socket socket; // Socket 套接字
    private ChatRoomClientFrame frame; // 组合复用 ChatRoomClientFrame

    /*
     * ChatRoomClient构造方法,负责构造客户端表示逻辑
     */
    public ChatRoomClient() {
        JFrame jf = new JFrame();

        /*
         * 弹出用户输入对话框,提示用户输入服务器的IP地址 返回相应字符串形式,存于变量serverIP,缺省值127.0.0.1
         */
        String serverIP = JOptionPane.showInputDialog(jf, "server IP:",
                "127.0.0.1");

        /*
         * 弹出用户输入对话框,提示用户输入服务器端口号 转化为int形式返回,存于变量serverPort
         */
        int serverPort = Integer.parseInt(JOptionPane.showInputDialog(jf,
                "port:"));

        /*
         * 弹出用户输入对话框,提示用户输入用户名,存于成员属性name
         */
        name = JOptionPane.showInputDialog(jf, "your name:");

        try {
            /* 通过IP和Port,与服务器端建立连接 */
            socket = new Socket(serverIP, serverPort);

            /* 给服务器发消息 */
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(name + ",login !");
        } catch (Exception e) {
            JOptionPane.showMessageDialog(jf, "fail,check the connection!");
            e.printStackTrace();
            System.exit(1);
        }

        /*
         * 创建ChatRoomClientFrame,进行客户端主窗口的显示
         */
        frame = new ChatRoomClientFrame(name, socket);
        frame.showMe();
    }

    /*
     * 主方法,启动聊天室客户端
     */
    public static void main(String[] args) {
        new ChatRoomClient();
    }
}

http://hi.baidu.com/xuchao_duizhang/blog/item/cf6604120b770840f819b8f4.html
package cn.tedu.chart2; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JTextArea; import javax.swing.JTextField; /** * 客户端窗体 */ public class ClientFrame extends JFrame implements ActionListener, KeyListener { JButton but; JTextArea message; JTextField text; Socket s; ClientThread client; public static void main(String[] args) { new ClientFrame(); } // 在构造函数中对窗体进行初始化 public ClientFrame() { // 取消JFrame的布局 this.setLayout(null); this.setTitle("客户端"); this.setBounds(100, 20, 400, 400); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 聊天记录 --- JTextArea message = new JTextArea(); message.setBounds(10, 10, 360, 200); // 设置聊天记录不能修改 message.setEditable(false); this.add(message); // 信息发送 JTextField JButton text = new JTextField(); text.setBounds(10, 260, 250, 40); text.addKeyListener(this); this.add(text); but = new JButton("发送"); but.setBounds(280, 260, 100, 40); // 给but按钮添加动作监听 but.addActionListener(this); this.add(but); this.setVisible(true); // 和服务器取得联系 try { s = new Socket("127.0.0.1", 65000); client = new ClientThread(s, message); client.start(); } catch (Exception e) { e.printStackTrace(); } } @Override public void actionPerformed(ActionEvent e) { if (e.getSource() == but) { if (!s.isClosed()) { String data = text.getText(); if (!"".equals(data)) { // 向服务器发送信息 client.send(data); // 清空文本框 text.setText(null); } }else { //在关闭状态下点击发送按钮 JOptionPane.showMessageDialog(null, "Socket连接已关闭,不能发送信息!", "提示", JOptionPane.ERROR_MESSAGE); } } } public void keyTyped(KeyEvent e) {} @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode() == KeyEvent.VK_ENTER) { if (!s.isClosed()) { String data = text.getText(); if (!"".equals(data)) { // 向服务器发送信息 client.send(data); // 清空文本框 text.setText(null); } }else { //在关闭状态下点击发送按钮 JOptionPane.showMessageDialog(null, "Socket连接已关闭,不能发送信息!", "提示", JOptionPane.ERROR_MESSAGE); } } } public void keyReleased(KeyEvent e) {} }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值