包结构:
1.RadiusServer
2.RadiusClient
3.RadiusPacket
4.RadiusAttribute
RadiusServer:
成员变量:
ExecutorService executor
默认为空,即RadiusServer默认不会开启多线程,需要我们自己派生子类来开启多线程处理请求
函数:
RadiusServer.start()
调用该函数后,服务器会启动两个线程分别监听指定的两个端口(auth,acct),其中一个端口用来进行用户认证,另一个端口用来进行计费认证
boolean isPacketDuplicate(RadiusPacket packet, InetSocketAddress address)
该函数用于判断收到的包是否最近就已经接收过,这个时间默认是3s,并将已接收的包存在一个linkedlist中,每次收到包时,都会遍历一次这个linkedlist,将过期的包去掉,并逐个对比收到的包,看是否重复,而且这个函数是加了同步锁的,即遍历是单线程的,高并发下性能非常差,需要改成用缓存
RadiusPacket:
函数:
encodepacket()
对符合radius协议的报文进行编码,输出字节流
decodepacket()
对符合radius协议的报文进行解码,从字节流构造成RadiusPacket类型的变量
这里对部分代码进行解释:
...
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()一次读取一个字节(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()一次只会读取一个字节,java中int是32位的,所以需要和0x0ff进行与运算,才能把byte转换为int,同样地,short需要read()两次才能读取完,并且第一次读取的值需要左移8位再拼上第二次读取的值才能转换为int
RadiusAttribute
该类主要用于存储radius报文的属性字段,在TinyRadius中,RadiusAttribute在编码时会被转换为字节数组,该数组长为2+属性值的字节长度,原因在于字节数组首元素存储属性值的类型,次元素存储属性值的长度,方便解码时转换回来