包結(jié)構(gòu):
1.RadiusServer
2.RadiusClient
3.RadiusPacket
4.RadiusAttribute
RadiusServer:
成員變量:
ExecutorService executor
默認(rèn)為空,即RadiusServer默認(rèn)不會開啟多線程,需要我們自己派生子類來開啟多線程處理請求
函數(shù):
RadiusServer.start()
調(diào)用該函數(shù)后,服務(wù)器會啟動兩個線程分別監(jiān)聽指定的兩個端口(auth,acct),其中一個端口用來進(jìn)行用戶認(rèn)證,另一個端口用來進(jìn)行計費認(rèn)證
boolean isPacketDuplicate(RadiusPacket packet, InetSocketAddress address)
該函數(shù)用于判斷收到的包是否最近就已經(jīng)接收過,這個時間默認(rèn)是3s,并將已接收的包存在一個linkedlist中,每次收到包時,都會遍歷一次這個linkedlist,將過期的包去掉,并逐個對比收到的包,看是否重復(fù),而且這個函數(shù)是加了同步鎖的,即遍歷是單線程的,高并發(fā)下性能非常差,需要改成用緩存
RadiusPacket:
函數(shù):
encodepacket()
對符合radius協(xié)議的報文進(jìn)行編碼,輸出字節(jié)流
decodepacket()
對符合radius協(xié)議的報文進(jìn)行解碼,從字節(jié)流構(gòu)造成RadiusPacket類型的變量
這里對部分代碼進(jìn)行解釋:
...
DataOutputStream dos = new DataOutputStream(out);
dos.writeByte(getPacketType());
dos.writeByte(getPacketIdentifier());
dos.writeShort(packetLength);
dos.write(getAuthenticator());
dos.write(attributes);
dos.flush();
...
上面的這段代碼是RadiusPacket.encodepacket()方法中的代碼,接下來看看decodepacket()中的這段代碼:
/**這里in.read()返回的是8位的byte類型變量,而java里面的int是32位的,為了不造成誤差,必須將高24位清0,所以要與一下0x0ff***/
/**in.read()一次讀取一個字節(jié)(1byte)**/
int type = in.read() & 0x0ff;
int identifier = in.read() & 0x0ff;
/**encode時length是short類型,16位,所以in.read()需要分兩次讀取,第一次讀取的值需要左移8位再或操作拼接上第二次讀取的值**/
int length = (in.read() & 0x0ff) << 8 | (in.read() & 0x0ff);
因為InputStream.read()一次只會讀取一個字節(jié),java中int是32位的,所以需要和0x0ff進(jìn)行與運算,才能把byte轉(zhuǎn)換為int,同樣地,short需要read()兩次才能讀取完,并且第一次讀取的值需要左移8位再拼上第二次讀取的值才能轉(zhuǎn)換為int
RadiusAttribute
該類主要用于存儲radius報文的屬性字段,在TinyRadius中,RadiusAttribute在編碼時會被轉(zhuǎn)換為字節(jié)數(shù)組,該數(shù)組長為2+屬性值的字節(jié)長度,原因在于字節(jié)數(shù)組首元素存儲屬性值的類型,次元素存儲屬性值的長度,方便解碼時轉(zhuǎn)換回來