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-----------------");
}
}