package com.tianhe.frm.chat;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Scanner;
/**
*
*<br>
* 服務器的實現效果: <br>
*<br>
* 1.輸入-help得到所有有關服務器操作的命令 <br>
*<br>
* 2.輸入-run進入服務器各項內容初始化 <br>
*<br>
* 3.輸入-stop斷開服務器 <br>
*<br>
* 4.輸入-quit斷開服務器,并退出操作 <br>
*<br>
* 5.服務器創建成功后,會通過單獨的線程運行監聽客戶端信息(listenLink) <br>
*<br>
* 6.服務器接收到數據后,會將數據移交至數據分析器(analyseMes)處理 <br>
*<br>
* 7.當用戶確定連接并確定昵稱后,服務器將該用戶的地址及姓名存儲在infoMemory中。 <br>
*<br>
*<br>
*<br>
*<br>
* 服務器的類與方法: <br>
*<br>
* 1.測試服務器創建:testServer(String ip,int serverPort) <br>
*<br>
* 2.初始化服務器 :initServer(String ip,int serverPort) <br>
*<br>
* 3.確定IP與Port :fixServerLink(String ip,int serverPort) <br>
*<br>
* 4.信息監聽器 :listenLink() <br>
*<br>
* 5.數據分析器 :analyseMes(String mes) <br>
*<br>
* 6.獲取地址用戶名:getConsumerName(SocketAddress sa) <br>
*<br>
* 7.數據轉發器 :transforMes(String mes) <br>
*<br>
* 8.數據單項轉發器:transforMesSingle(SocketAddress adr,String mes) <br>
*<br>
* 9.停止服務器 :cutServer() <br>
*<br>
* 10.獲得幫助列表 :helpList() <br>
*<br>
* 11.錯誤提示方法 :errorTip(String str) <br>
*<br>
* 12.在主函數中進行相應操作 <br>
*<br>
*<br>
* 重點注意的地方: <br>
*<br>
* 與客戶端相仿,為了順利監聽信息,需要另一個線程運行信息監聽器
*
*/
public class ChatServer implements Runnable
{
private DatagramSocket ds = null;
private DatagramPacket dp = null;
private String serverIp = "localhost";
private int serverPort = 9999;
private InetAddress serverAddr = null;
// 開始運行監聽的變量
private boolean beStart = false;
// 信息存儲器
private Hashtable<String, SocketAddress> userCache = new Hashtable<String, SocketAddress>();
/**
* 服務器初始化
*
* @param ip
* @param serverPort
*/
public boolean initServer(InetAddress serverAddr, int serverPort)
{
this.serverAddr = serverAddr;
this.serverPort = serverPort;
try
{
ds = new DatagramSocket(serverPort, serverAddr);
System.out.println("!-The Server Initialization Success!");
// 可以開始運行變量
beStart = true;
}
catch (SocketException s)
{
// 如果出現異常,則服務器測試不通過
errorTip("!-The Server Initialization Fail!--new DatagramSocket(" + serverPort + ", " + serverAddr + ")");
return false;
}
return true;
}
/**
* 監聽信息
*
*/
public void listenLink()
{
byte[] buf = new byte[1024];
String mes = null;
try
{
dp = new DatagramPacket(buf, buf.length);
System.out.println("!-The Server starts listenning to message.");
while (beStart)
{
ds.receive(dp);
mes = new String(buf, 0, dp.getLength());
// 將獲取的數據傳遞至數據分析器
this.analyseMes(mes);
}
}
catch (IOException e)
{
errorTip("!-The Server Can not receive message");
}
}
/**
* 數據分析器,給予相應處理
*
* @param mes
*/
private void analyseMes(String mes)
{
// 獲取當前客戶端的地址:
SocketAddress adr = dp.getSocketAddress();
// -test:進行服務器與客戶端的連接測試
// 若成功,則將該客戶端發送成功消息
if (mes.trim().equalsIgnoreCase("-test"))
{
transforMesSingle(adr, "-test: !-From Server:Succeed in Testing.");
}
// -quit:接受客戶端退出信息
// 將該用戶的退出信息轉發至所有在線成員
else if (mes.trim().equalsIgnoreCase("-quit"))
{
String name = this.getConsumerName(adr);
System.out.println(name + "http://" + adr + " quit! ");
transforMes("* " + name + "退出聊天室");
userCache.remove(name);
}
// -getList:接受客戶端獲取列表的請求
// 將所有用戶連接為字符串的形式,如:"-getList,用戶1,用戶2...用戶n"
else if (mes.trim().equals("-getList"))
{
StringBuffer list = new StringBuffer();
list.append("-getList,");
Enumeration<String> names = userCache.keys();
while (names.hasMoreElements())
{
list.append(names.nextElement() + ",");
}
transforMesSingle(dp.getSocketAddress(), list.toString());
}
// -to:接受客戶端請求,將信息轉發給相應客戶
// 如果目標客戶不存在,則向請求客戶發送相應消息
else if (mes.indexOf("-to ") != -1 && mes.startsWith("-to "))
{
String main = mes.substring("-to ".length(), mes.length());
String toName = main.substring(0, main.indexOf(" "));
String name = this.getConsumerName(adr);
String con = name + " say to you :" + main.substring(toName.length() + 1, main.length());
if (!userCache.containsKey(toName))
transforMesSingle(adr, "!-The message can not be recevie by whom you send for,please check out.");
else
transforMesSingle(userCache.get(toName), con);
}
// -nick:接受客戶端登錄請求
// 如果輸入的匿名不存在,則登記該用戶與infoMemory
// 如果存在則返回相應提示
else if (mes.indexOf("-nick ") != -1 && mes.startsWith("-nick "))
{
String nickName = mes.substring("-nick ".length(), mes.length());
if (userCache.containsKey(nickName))
transforMesSingle(adr, "-nick: !-The nickname you post is already exist,please try others.");
else
{
userCache.put(nickName, adr);
transforMes("Welcome " + nickName + " to Sunspot Chat!");
System.out.println(nickName + "http://" + adr.toString() + " succeed in lanuching.");
}
}
// 一般消息將會轉發至所有用戶
else
{
String name = this.getConsumerName(adr);
transforMes(name + ": " + mes);
}
}
/**
* 通過地址得到用戶的昵稱 由于Hashtable無法通過Value獲取Key,所有專門寫該方法
*
* @param sa
* @return
*/
private String getConsumerName(SocketAddress sa)
{
Enumeration<String> names = userCache.keys();
String name = null;
while (names.hasMoreElements())
{
String temp = names.nextElement();
SocketAddress adrs = userCache.get(temp);
// 進行比較
if (sa.equals(adrs))
{
name = temp;
break;
}
}
return name;
}
/**
* 向所有的用戶發送數據
*
* @param mes
*/
public void transforMes(String mes)
{
byte[] buf = mes.getBytes();
DatagramPacket sendDatas = null;
Enumeration<SocketAddress> all = userCache.elements();
try
{
while (all.hasMoreElements())
{
sendDatas = new DatagramPacket(buf, buf.length, all.nextElement());
ds.send(sendDatas);
}
}
catch (SocketException s)
{
errorTip("!-The feedback address is error!");
}
catch (IOException i)
{
errorTip("!-Can not send message!");
}
}
/**
* 向單個用戶發送數據
*
* @param adr
* @param mes
*/
public void transforMesSingle(SocketAddress adr, String mes)
{
byte[] buf = mes.getBytes();
try
{
DatagramPacket sendDatas = new DatagramPacket(buf, buf.length, adr);
ds.send(sendDatas);
}
catch (SocketException s)
{
errorTip("!-The feedback address is error!");
}
catch (IOException i)
{
errorTip("!-Can not send message!");
}
}
/**
* 斷開連接
*
*/
public void cutServer()
{
beStart = false;
if (ds != null)
ds.close();
System.out.println("!-The ds is done.");
}
public void helpList()
{
System.out.println("-help" + " 獲取服務器相應操作的幫助" + "\n" + "-run " + " 運行服務器,并同時建立信息監聽" + "\n" + "-stop"
+ " 停止服務器" + "\n" + "-quit" + " 停止服務器,并退出命令" + "\n");
}
/**
* 線程
*/
public void run()
{
listenLink();
}
/**
* 主要操作
*
* @param args
*/
public static void main(String[] args)
{
ChatServer cs = new ChatServer();
// 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);
System.out.println("!-請輸入服務端命令:");
// 開始輸入
String command = null;
// 如果輸入quit將斷開連接,并退出操作
while (!(command = input.next()).equalsIgnoreCase("-quit"))
{
// 獲取幫助
if (command.equalsIgnoreCase("-help"))
{
cs.helpList();
}
// 初始化服務器
if (command.equalsIgnoreCase("-run"))
{
boolean goon = true;
while (goon)
{
// 測試服務器創建,如果成功則同時為信息監聽器建立線程
System.out.println("!-創建服務器并運行...");
if (cs.initServer(serverAddr, serverPort))
{
new Thread(cs).start();
goon = false;
}
else
System.out.println("!-服務器創建失敗,請檢查!");
}
}
// 關閉服務器
if (command.equalsIgnoreCase("-stop"))
{
cs.cutServer();
}
}
input.close();
cs.cutServer();
}
/**
* 錯誤提示
*
* @param str
*/
public static void errorTip(String str)
{
System.out.println("-----------------\n" + str + "\n-----------------");
}
}