ChatClient

ChatClient

package com.tianhe.frm.chat;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 *
 *<br>
 * 客户端的实现效果 <br>
 *<br>
 * 1.登录服务器,如果服务器端口号和IP号输入的字符都是"0"则,客户端连接到默认的服务器 <br>
 *<br>
 * 2.输入聊天昵称 <br>
 *<br>
 * 3.输入"-quit"会自动退出聊天 <br>
 *<br>
 * 4.输入"-getList"会得到在线用户的名称 <br>
 *<br>
 * 5.输入"-to <用户名称> <聊天信息>"会把信息发送到指定的用户处,他人看不到 <br>
 *<br>
 * 6.输入"-help"会得到客户端相应操作帮助 <br>
 *<br>
 * 6.直接输入内容则会将内容发送到所有在线的用户处 <br>
 *<br>
 *<br>
 *<br>
 *<br>
 * 客户端的类与方法 <br>
 *<br>
 * 1.建立连接方法:connectServer(String ip,int serverPort) <br>
 *<br>
 * 2.断开连接方法:disconnectServer() <br>
 *<br>
 * 2.发送消息方法:sendMes(String mes) <br>
 *<br>
 * 3.接受消息方法:getMes() <br>
 *<br>
 * 4.接受一次消息:getMesOnce() <br>
 *<br>
 * 5.获得用户列表:getList(String mes) <br>
 *<br>
 * 6.测试连接方法:testConnect(String ip,int serverPort) <br>
 *<br>
 * 7.检查用户名 :checkNickName(String nickName) <br>
 *<br>
 * 8.获得帮助列表:helpList(); <br>
 *<br>
 * 9.各项内容的输入在main方法中进行 <br>
 *<br>
 *<br>
 *<br>
 *<br>
 * 重点注意的地方 <br>
 *<br>
 * 由于客户端无法知道服务器何时转发数据,所以客户端需要一直不停地监听消息,为了不影响其他的方法,如发送数据,这里用到多线程,即为接受数据单独建立一个线程,以防止影响其他方法的正常工作。
 *
 */
public class ChatClient implements Runnable
{
    private String serverIp = "localhost";
   
    private int serverPort = 9999;
   
    private InetAddress serverAddr = null;
   
    // 客户端
    private DatagramSocket ds = null;
   
    // 发送的数据报
    private DatagramPacket dp = null;
   
    // 用来测试是否能够连接成功或者用户名是否正确
    // 在testConnect和checkNickName中会用到.
    // 并穿插在sendMes方法中
    private boolean test = true;
   
    /**
     * 建立连接
     *
     * @param ip 服务器IP号
     * @param serverPort 服务器Port
     */
    public boolean initServer(InetAddress serverAddr, int serverPort)
    {
        this.serverAddr = serverAddr;
        this.serverPort = serverPort;
       
        try
        {
            ds = new DatagramSocket();
        }
        catch (SocketException s)
        {
            System.out.println("The Connection of server is error.");
            return false;
        }
       
        return true;
    }
   
    /**
     * 断开连接
     */
    public void disconnectServer()
    {
        // 当客户端断开连接之前,客户端会向服务器端发送一个信息,
        // 以便告诉服务器该客户下线
        this.sendMes("-quit");
        if (ds != null)
            ds.close();
       
    }
   
    /**
     * 发送消息
     *
     * @param mes
     */
    public void sendMes(String mes)
    {
        byte[] buf = mes.getBytes();
        dp = new DatagramPacket(buf, buf.length, serverAddr, serverPort);
        // 当建立发送时,测试正常
        test = true;
        try
        {
            ds.send(dp);
        }
        catch (NullPointerException n)
        {
            // 如果无法得到要发送的消息,测试终止
            test = false;
            System.out.println("The nullity of the address of connection");
        }
        catch (IOException s)
        {
            // 如果无法发送消息至服务器,测试终止
            test = false;
            System.out.println("There is a problem to send message.");
        }
        finally
        {
        }
    }
   
    /**
     * 得到数据
     */
    public void getMes()
    {
        byte[] buf = new byte[1024];
        DatagramPacket getDatas = new DatagramPacket(buf, buf.length);
        String mes = null;
        try
        {
            while (true)
            {
                ds.receive(getDatas);
                mes = new String(buf, 0, getDatas.getLength());
                // 如果服务器发送的消息中的头片段有-getList
                // 表明客户端获得在线用户列表,调用getList方法解析
                if (mes.indexOf("-getList") == 0)
                    this.getList(mes);
                else
                    System.out.println(mes);
            }
        }
        catch (IOException i)
        {
            System.out.println("Fail in receving message");
        }
    }
   
    /**
     * 得到一次数据
     *
     */
    public String getMesOnce()
    {
        byte[] buf = new byte[1024];
        DatagramPacket getDatas = new DatagramPacket(buf, buf.length);
        String mes = null;
        try
        {
            ds.receive(getDatas);
            mes = new String(buf, 0, getDatas.getLength());
        }
        catch (Exception e)
        {
            System.out.println("!-Can not receive the message!");
        }
        finally
        {
        }
        return mes;
    }
   
    /**
     * 显示在线用户列表
     *
     * @param mes
     */
    private void getList(String mes)
    {
        String[] list = mes.split(",");
        System.out.println("在线用户:\n-------------");
        for (int i = 1; i < list.length; i++)
        {
            System.out.println("    * " + list[i]);
        }
        System.out.println("-------------");
    }
   
    /**
     * 判断用户名输入是否正确
     */
    private boolean checkNickName(String nickName)
    {
        test = true;
        String mes = null;
        // 判断昵称是否符合约定
        for (int i = 0; i < nickName.length(); i++)
        {
            char temp = nickName.charAt(i);
            // 如果不符合,则终止测试
            if (!Character.isLetterOrDigit(temp))
            {
                test = false;
                break;
            }
        }
        // 如果通过约定,则试图向服务器发送昵称,进行判断
        if (test)
        {
            this.sendMes("-nick " + nickName);
            mes = this.getMesOnce();
            // 如果服务器返回"-nick"标识
            // 说明测试昵称失败,终止测试
            if (mes.startsWith("-nick"))
            {
                test = false;
            }
        }
       
        System.out.println(mes);
        return test;
    }
   
    /**
     * 得到帮助列表
     *
     */
    public void helpList()
    {
        System.out.println("重要说明:如果已经成功连接,只要输入内容,所有在线用户都能看到您的发言。" + "\n" + "-help" + "         获取客户端相应操作的帮助" + "\n"
                + "-test" + "         测试与服务器的连接,如果已经服务器连接,请不要选用此项" + "\n" + "-getList" + "    得到在线用户的列表" + "\n"
                + "-to <name> <message>" + "\n" + "                    将消息发送到特定的在线用户处" + "\n" + "-quit"
                + "         断开连接,退出聊天室" + "\n");
    }
   
    /**
     * 线程部分
     */
    public void run()
    {
        getMes();
    }
   
    /**
     * 各项内容的操作器
     */
    public static void main(String[] args)
    {
        ChatClient cc = new ChatClient();
       
        // serverAddr && serverPort
        String serverIp = "localhost";
        int serverPort = 9999;
        InetAddress serverAddr = null;
       
        if (args != null && args.length > 0)
        {
            int i = 0;
            while (i < args.length)
            {
                // serverAddr
                if (args[i].equalsIgnoreCase("-ServerAddr"))
                {
                    i = i + 1;
                    serverIp = args[i];
                    continue;
                }
               
                // serverPort
                int ti = 9999;
                if (args[i].equalsIgnoreCase("-ServerPort"))
                {
                    i = i + 1;
                    ti = Integer.parseInt(args[i]);
                    if (ti > 0)
                    {
                        serverPort = ti;
                    }
                    i = i + 1;
                    continue;
                }
            }
        }
       
        try
        {
            serverAddr = InetAddress.getByName(serverIp);
        }
        catch (UnknownHostException e)
        {
            e.printStackTrace();
            System.exit(-1);
        }
       
        System.out.println("欢迎登录Lexiaofei聊天室!");
        Scanner input = new Scanner(System.in);
       
        // 连接服务器
        cc.initServer(serverAddr, serverPort);
       
        // 输入昵称
        boolean goon = true;
        while (goon)
        {
            // 第三步:输入昵称
            System.out.println("3.请输入您登录后显示的昵称(只能输入中文、英文字母及数字):");
            String nick = input.next();
            boolean judge = cc.checkNickName(nick);
            // 判断昵称是否输入正确
            if (judge)
                goon = false;
            else
                System.out.println("!-您输入的用户名不符合条件,请重新输入!");
        }
       
        // 开始运行接收数据
        new Thread(cc).start();
        // 聊天
        String mes = null;
        System.out.println("!-您成功进入聊天室!");
       
        while (!(mes = input.nextLine()).equalsIgnoreCase("-quit"))
        {
            // 如果输入"-test"命令,开始测试
            if (mes.trim().equalsIgnoreCase("-getList"))
            {
                cc.sendMes(mes);
                // -nick 设置昵称
            }
            else if (mes.equalsIgnoreCase("-help"))
            {
                cc.helpList();
                // 如果输入的是空字符,则不发送
            }
            else
            {
                if (!mes.equals(""))
                {
                    cc.sendMes(mes);
                }
            }
        }
       
        // 退出
        input.close();
        cc.disconnectServer();
       
    }
   
    /**
     * 错误提示标记
     *
     * @param str
     */
    public static void errorTip(String str)
    {
        System.out.println("-----------------\n" + str + "\n-----------------");
    }
}

你可能感兴趣的:(ChatClient)