服務器的實現效果:
1.輸入-help得到所有有關服務器操作的命令
2.輸入-run進入服務器各項內容初始化
3.輸入-stop斷開服務器
4.輸入-quit斷開服務器,並退出操作
5.服務器創建成功後,會通過單獨的線程運行監聽客戶端信息(listenLink)
6.服務器接收到數據後,會將數據移交至數據分析器(analyseMes)處理
7.當用戶確定連接並確定昵稱後,服務器將該用戶的地址及姓名存儲在 infoMemory中。
服務器的類與方法:
1.測試服務器創建:testServer(String ip,int port)
2.初始化服務器 :initServer(String ip,int port)
3.確定IP與Port :fixServerLink(String ip,int port)
4.信息監聽器 :listenLink()
5.數據分析器 :analyseMes(String mes)
6.獲取地址用戶名:getConsumerName(SocketAddress sa)
7.數據轉發器 :transforMes(String mes)
8.數據單項轉發器:transforMesSingle(SocketAddress adr,String mes)
9.停止服務器 :cutServer()
10.獲得幫助列表 :helpList()
11.錯誤提示方法 :errorTip(String str)
12.在主函數中進行相應操作
重點注意的地方:
與客戶端相仿,為了順利監聽信息,需要另一個線程運行信息監聽器
package com.sunspot.udp.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;
public class Server implements Runnable{
private DatagramSocket server = null;
private DatagramPacket getDatas = null;
private InetAddress serverAddress = null;
private int port = 0;
//開始運行監聽的變量
private boolean beStart = false;
//用來測試服務器的變量
private boolean test = true;
//信息存儲器
private Hashtable<String,SocketAddress> infoMemory = new Hashtable<String,SocketAddress>();
/**
* 測試服務器連接
* @param ip
* @param port
* @return
*/
public boolean testServer(String ip,int port) {
this.initServer(ip, port);
return test;
}
/**
* 服務器初始化
* @param ip
* @param port
*/
public void initServer(String ip,int port) {
//確定IP與port輸入正確
this.fixServerLink(ip,port);
try {
server = new DatagramSocket(this.port,serverAddress);
System.out.println("!-The Server Initialization Success!");
//可以開始運行變量
beStart = true;
} catch (SocketException s) {
//如果出現異常,則服務器測試不通過
test = false;
errorTip("!-The Server Initialization Fail!");
} finally {
}
}
/**
* 確定服務器IP和端口信息
* @param ip
* @param port
*/
private void fixServerLink(String ip,int port) {
//判斷連接服務器的端口號
//如果輸入命令為0,則為默認端口號9999
//否則端口號為新端口號
if(port == 0)
this.port = 9999;
else
this.port = port;
//判斷連接服務器的IP地址
//如果輸入命令為0,則為默認的本地IP地址
//否則為輸入的IP地址
try {
if(ip.equalsIgnoreCase("0"))
this.serverAddress = InetAddress.getLocalHost();
else
this.serverAddress = InetAddress.getByName(ip);
} catch (UnknownHostException u) {
errorTip("!-Sorry, IP address you put is not currect!");
}
}
/**
* 監聽信息
*
*/
public void listenLink() {
byte[] buf = new byte[1024];
String mes = null;
try {
getDatas = new DatagramPacket(buf,buf.length);
System.out.println("!-The Server starts listenning to message.");
while(beStart) {
server.receive(getDatas);
mes = new String(buf,0,getDatas.getLength());
//將獲取的數據傳遞至數據分析器
this.analyseMes(mes);
}
} catch (IOException e) {
errorTip("!-The Server Can not receive message");
}
}
/**
* 數據分析器,給予相應處理
* @param mes
*/
private void analyseMes(String mes) {
//獲取當前客戶端的地址:
SocketAddress adr = getDatas.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+"//"+adr+" quit! ");
transforMes("* "+name+"退出聊天室");
infoMemory.remove(name);
}
//-getList:接受客戶端獲取列表的請求
//將所有用戶連接為字符串的形式,如:"-getList,用戶1,用戶2...用 戶n"
else if(mes.trim().equals("-getList")) {
StringBuffer list = new StringBuffer();
list.append("-getList,");
Enumeration<String> names = infoMemory.keys();
while (names.hasMoreElements()) {
list.append(names.nextElement()+",");
}
transforMesSingle(getDatas.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(!infoMemory.containsKey(toName))
transforMesSingle(adr,
"!-The message can not be recevie by whom you send for,please check out.");
else
transforMesSingle(infoMemory.get(toName),con);
}
//-nick:接受客戶端登錄請求
//如果輸入的匿名不存在,則登記該用戶與infoMemory
//如果存在則返回相應提示
else if(mes.indexOf("-nick ") != -1 && mes.startsWith ("-nick ")) {
String nickName = mes.substring("-nick ".length(), mes.length());
if(infoMemory.containsKey(nickName))
transforMesSingle(adr,
"-nick: !-The nickname you post is already exist,please try others.");
else {
infoMemory.put(nickName,adr);
transforMes("Welcome "+nickName +" to Sunspot Chat!");
System.out.println(nickName+"//"+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 = infoMemory.keys();
String name = null;
while (names.hasMoreElements()) {
String temp = names.nextElement();
SocketAddress adrs = infoMemory.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 = infoMemory.elements ();
try {
while (all.hasMoreElements()) {
sendDatas = new DatagramPacket (buf,buf.length,all.nextElement());
server.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);
server.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(server != null)
server.close();
System.out.println("!-The server 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) {
Server ser = new Server();
String getIp = null;
int getPort = 0;
//建立輸入
Scanner input = new Scanner(System.in);
System.out.println("!-Please input server command:");
//開始輸入
String command = null;
//如果輸入quit將斷開連接,並退出操作
while (!(command = input.next()).equalsIgnoreCase("-quit")) {
//獲取幫助
if(command.equalsIgnoreCase("-help")) {
ser.helpList();
}
//初始化服務器
if (command.equalsIgnoreCase("-run")) {
boolean goon = true;
while (goon) {
System.out.println("1.輸入服務器的IP地址,默認輸入數字0: ");
getIp = input.next();
System.out.println("2.輸入服務器的端口號,默認輸入數字0: ");
try {
getPort = input.nextInt();
} catch (Exception e) {
System.out.println("!-The port style is not currect!");
}
//測試服務器創建,如果成功則同時為信息監聽器建立線程
System.out.println("!-創建服務器並運行...");
if (ser.testServer(getIp, getPort)) {
new Thread(ser).start();
goon = false;
} else
System.out.println("!-服務器創建失敗,請檢查!");
}
}
//關閉服務器
if (command.equalsIgnoreCase("-stop")) {
ser.cutServer();
}
}
input.close();
ser.cutServer();
}
/**
* 錯誤提示
* @param str
*/
public static void errorTip(String str) {
System.out.println("-----------------\n"+str+"\n-------------- ---");
}
}
本文配套源碼