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>
* 客戶端的實現(xiàn)效果 <br>
*<br>
* 1.登錄服務(wù)器,如果服務(wù)器端口號和IP號輸入的字符都是"0"則,客戶端連接到默認的服務(wù)器 <br>
*<br>
* 2.輸入聊天昵稱 <br>
*<br>
* 3.輸入"-quit"會自動退出聊天 <br>
*<br>
* 4.輸入"-getList"會得到在線用戶的名稱 <br>
*<br>
* 5.輸入"-to <用戶名稱> <聊天信息>"會把信息發(fā)送到指定的用戶處,他人看不到 <br>
*<br>
* 6.輸入"-help"會得到客戶端相應(yīng)操作幫助 <br>
*<br>
* 6.直接輸入內(nèi)容則會將內(nèi)容發(fā)送到所有在線的用戶處 <br>
*<br>
*<br>
*<br>
*<br>
* 客戶端的類與方法 <br>
*<br>
* 1.建立連接方法:connectServer(String ip,int serverPort) <br>
*<br>
* 2.斷開連接方法:disconnectServer() <br>
*<br>
* 2.發(fā)送消息方法: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.各項內(nèi)容的輸入在main方法中進行 <br>
*<br>
*<br>
*<br>
*<br>
* 重點注意的地方 <br>
*<br>
* 由于客戶端無法知道服務(wù)器何時轉(zhuǎn)發(fā)數(shù)據(jù),所以客戶端需要一直不停地監(jiān)聽消息,為了不影響其他的方法,如發(fā)送數(shù)據(jù),這里用到多線程,即為接受數(shù)據(jù)單獨建立一個線程,以防止影響其他方法的正常工作。
*
*/
public class ChatClient implements Runnable
{
private String serverIp = "localhost";
private int serverPort = 9999;
private InetAddress serverAddr = null;
// 客戶端
private DatagramSocket ds = null;
// 發(fā)送的數(shù)據(jù)報
private DatagramPacket dp = null;
// 用來測試是否能夠連接成功或者用戶名是否正確
// 在testConnect和checkNickName中會用到.
// 并穿插在sendMes方法中
private boolean test = true;
/**
* 建立連接
*
* @param ip 服務(wù)器IP號
* @param serverPort 服務(wù)器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()
{
// 當客戶端斷開連接之前,客戶端會向服務(wù)器端發(fā)送一個信息,
// 以便告訴服務(wù)器該客戶下線
this.sendMes("-quit");
if (ds != null)
ds.close();
}
/**
* 發(fā)送消息
*
* @param mes
*/
public void sendMes(String mes)
{
byte[] buf = mes.getBytes();
dp = new DatagramPacket(buf, buf.length, serverAddr, serverPort);
// 當建立發(fā)送時,測試正常
test = true;
try
{
ds.send(dp);
}
catch (NullPointerException n)
{
// 如果無法得到要發(fā)送的消息,測試終止
test = false;
System.out.println("The nullity of the address of connection");
}
catch (IOException s)
{
// 如果無法發(fā)送消息至服務(wù)器,測試終止
test = false;
System.out.println("There is a problem to send message.");
}
finally
{
}
}
/**
* 得到數(shù)據(jù)
*/
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());
// 如果服務(wù)器發(fā)送的消息中的頭片段有-getList
// 表明客戶端獲得在線用戶列表,調(diào)用getList方法解析
if (mes.indexOf("-getList") == 0)
this.getList(mes);
else
System.out.println(mes);
}
}
catch (IOException i)
{
System.out.println("Fail in receving message");
}
}
/**
* 得到一次數(shù)據(jù)
*
*/
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;
}
}
// 如果通過約定,則試圖向服務(wù)器發(fā)送昵稱,進行判斷
if (test)
{
this.sendMes("-nick " + nickName);
mes = this.getMesOnce();
// 如果服務(wù)器返回"-nick"標識
// 說明測試昵稱失敗,終止測試
if (mes.startsWith("-nick"))
{
test = false;
}
}
System.out.println(mes);
return test;
}
/**
* 得到幫助列表
*
*/
public void helpList()
{
System.out.println("重要說明:如果已經(jīng)成功連接,只要輸入內(nèi)容,所有在線用戶都能看到您的發(fā)言。" + "\n" + "-help" + " 獲取客戶端相應(yīng)操作的幫助" + "\n"
+ "-test" + " 測試與服務(wù)器的連接,如果已經(jīng)服務(wù)器連接,請不要選用此項" + "\n" + "-getList" + " 得到在線用戶的列表" + "\n"
+ "-to <name> <message>" + "\n" + " 將消息發(fā)送到特定的在線用戶處" + "\n" + "-quit"
+ " 斷開連接,退出聊天室" + "\n");
}
/**
* 線程部分
*/
public void run()
{
getMes();
}
/**
* 各項內(nèi)容的操作器
*/
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);
// 連接服務(wù)器
cc.initServer(serverAddr, serverPort);
// 輸入昵稱
boolean goon = true;
while (goon)
{
// 第三步:輸入昵稱
System.out.println("3.請輸入您登錄后顯示的昵稱(只能輸入中文、英文字母及數(shù)字):");
String nick = input.next();
boolean judge = cc.checkNickName(nick);
// 判斷昵稱是否輸入正確
if (judge)
goon = false;
else
System.out.println("!-您輸入的用戶名不符合條件,請重新輸入!");
}
// 開始運行接收數(shù)據(jù)
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 設(shè)置昵稱
}
else if (mes.equalsIgnoreCase("-help"))
{
cc.helpList();
// 如果輸入的是空字符,則不發(fā)送
}
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-----------------");
}
}