前段时间写了个web端与C服务端之间的通信不过用的是短连接 非堵塞的方式,一直想使用长连接,使tomcat启动的时候就和C服务端进行通信,但是一直没找到方法希望je的朋友能给点思路。先来看我现在的具体实现
通信的核心类
public
class
newsSockBase
{
private
SocketChannel sc;
private
final
int
MAX_LENGTH =
8192
;
private
ByteBuffer r_buff ;
private
ByteBuffer w_buff ;
private
static
String host ;
private
static
int
port;
int
sendBufTotalLen;
int
sendBufLen;
int
sendBufStart;
byte
[] sendBuf;
int
recvBufTotalLen;
int
recvBufLen;
int
recvBufStart;
byte
[] recvBuf;
int
timeout;
String msg;
public
newsSockBase()
{
r_buff = ByteBuffer.allocate(MAX_LENGTH);
w_buff = ByteBuffer.allocate(MAX_LENGTH);
sendBufTotalLen = MAX_LENGTH;
sendBufLen = sendBufStart = 0
;
sendBuf = new
byte
[MAX_LENGTH];
recvBufTotalLen = MAX_LENGTH;
recvBufLen = recvBufStart = 0
;
recvBuf = new
byte
[MAX_LENGTH];
timeout = 6
;
}
public
void
setIPandPort(String str,
int
pt)
{
host = str;
port = pt;
}
//这两个函数一定要注意 形参是基类 而实际传入的参数是子类,到时候也是调用子类的参数来做
public
void
getBufFrompara(InewsDetail nD)
{
int
len = nD.encode(sendBuf, sendBufStart, sendBufTotalLen-sendBufStart-sendBufLen);
sendBufLen += len;
}
public
int
decodeBufToPara(InewsDetail nD)
{
int
len = nD.decode(recvBuf, recvBufStart, recvBufLen);
if
(len>
0
)
//解码正确的时候才做
{
recvBufLen -= len;
recvBufStart += len;
}
return
len;
}
public
void
start(InewsDetail nD)
{
//这里需要先根据传入的参数来
getBufFrompara(nD);
try
{
InetSocketAddress addr = new
InetSocketAddress(host, port);
// 生成一个socketchannel
sc = SocketChannel.open();
sc.configureBlocking( false
);
//
// 连接到server
sc.connect(addr);
while
(!sc.finishConnect())
;
System.out.println( "connection has been established!…"
);
// while (true)
{
// 回射消息 // 复位,清空
w_buff.clear();
w_buff.put(sendBuf,sendBufStart,sendBufLen);
w_buff.flip(); // 转到最开始
// 发送消息
while
(w_buff.hasRemaining())
sc.write(w_buff);
w_buff.clear();
// 进入接收状态
while
(
true
)
{
int
ss=
0
;
int
count;
r_buff.clear();
while
(ss<timeout*
100
)
{
count = sc.read(r_buff);
if
(count>
0
)
break
;
ss++;
Thread.currentThread().sleep( 10
);
}
if
(ss==timeout)
{
break
;
}
r_buff.flip();
//判断recvBuf能不能放下接收到的数据
if
(r_buff.limit()+recvBufStart+recvBufLen>recvBufTotalLen)
{
//放不下了
//那就先看看前面是不是有空余
if
(recvBufStart>
0
)
{
for
(
int
i=
0
;i<recvBufStart;i++)
{
recvBuf = recvBuf[i+recvBufStart];
}
recvBufStart = 0 ;
}
if (r_buff.limit()+recvBufStart+recvBufLen>recvBufTotalLen)
{
//这个时候就是真的说数据区长度不够了,属于致命错误
System.err.println("致命错误! 缓冲区长度过小!" );
}
}
else
{ // 也可以转化为字符串,不过需要借助第三个变量了。
r_buff.get(recvBuf,recvBufStart+recvBufLen,r_buff.limit());
//得到了一次数据就要试着做一次解码,如果能够解码,那就完成解码,不能则表示数据不完整,继续等待新数据
//这里注意返回值 如果是0 表示数据不完整 如果是正数 就是解码的字节数 负数表示解码出错
recvBufLen += r_buff.limit();
if (decodeBufToPara(nD)!=0 )
break ;
}
System.out.println("reply is " + r_buff.limit() + " long " );
}
}
sc.socket().close();
} catch (IOException ioe) {
ioe.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
System.out.println("Exit App....... " );
}
public static void main(String[] args)
{
newsDetailNewsSum nDNS = new newsDetailNewsSum();
newsSockBase nsb = new newsSockBase();
nsb.setIPandPort("192.168.0.106" ,8888 );
nsb.start(nDNS);
System.out.println("Exit Allllll....... " );
}
}
下面是报文协议的基类
//此类试图将所有的通讯协议的编解码都包含在内!按照一次交互的过程来区分
public class newsDetail implements InewsDetail
{
protected int netErr; //用来表示是不是网络出错了,主要是超时。这个时候就不需要检查其他参数了。
protected int type; //就是对应具体的操作类型码
protected byte [] StreamID= new byte [16 ]; //对应具体的流水号
protected byte [] asyn = new byte [2 ];
//这个还是有问题 不能达到预计效果 需要修改
static private int seq=0 ; //生成流水号后2位的时候使用的
static private Calendar lastCa;
public newsDetail()
{
getStreamID();
}
public int getType() {
return type;
}
public void setType( int type) {
this .type = type;
}
//基类中的编解码函数没有作用,具体使用的编解码函数在各个子类中需要重新实现
//必须有返回值 因为调用者需要根据返回值做一些操作
//这里的参数 buf是需要填写的缓冲区 start 是缓冲区开始位置 len 是可用的缓冲区长度
public int encode( byte [] buf, int start, int len)
{
return 0 ;
}
//这里的参数 buf是需要需要解码的缓冲区 start 是缓冲区开始位置 len 是需要解码的长度
public int decode( byte [] buf, int start, int len)
{
return 0 ;
}
public void getStreamID()
{
Calendar ca = Calendar.getInstance();
int year = ca.get(Calendar.YEAR);//获取年份
int month=ca.get(Calendar.MONTH)+1 ;//获取月份
int day=ca.get(Calendar.DATE);//获取日
int minute=ca.get(Calendar.MINUTE);//分
int hour=ca.get(Calendar.HOUR);//小时
int second=ca.get(Calendar.SECOND);//秒
int am_pm=ca.get(Calendar.AM_PM);
if (am_pm==Calendar.PM)
hour += 12 ;
if (hour>=24 )
hour -= 24 ;
System.out.println(seq);
if (lastCa!=ca)
{
lastCa = ca;
seq = 12 ;
}
else
{
seq++;
if (seq>=100 )
seq = 0 ;
}
//现在根据上面的字段组成StreamID字符串
//目前先使用手工的办法来写,效率高一些
StreamID[0 ] = ( byte )(year/1000 +'0' );
StreamID[1 ] = ( byte )((year-(StreamID[0 ]-'0' )*1000 )/100 +'0' );
StreamID[2 ] = ( byte )((year-(StreamID[0 ]-'0' )*1000 -(StreamID[1 ]-'0' )*100 )/10 +'0' );
StreamID[3 ] = ( byte )(year-(StreamID[0 ]-'0' )*1000 -(StreamID[1 ]-'0' )*100 -(StreamID[2 ]-'0' )*10 +'0' );
StreamID[4 ] = ( byte )(month/10 +'0' );
StreamID[5 ] = ( byte )((month-(StreamID[4 ]-'0' )*10 )+'0' );
StreamID[6 ] = ( byte )(day/10 +'0' );
StreamID[7 ] = ( byte )((day-(StreamID[6 ]-'0' )*10 )+'0' );
StreamID[8 ] = ( byte )(hour/10 +'0' );
StreamID[9 ] = ( byte )((hour-(StreamID[8 ]-'0' )*10 )+'0' );
StreamID[10 ] = ( byte )(minute/10 +'0' );
StreamID[11 ] = ( byte )((minute-(StreamID[10 ]-'0' )*10 )+'0' );
StreamID[12 ] = ( byte )(second/10 +'0' );
StreamID[13 ] = ( byte )((second-(StreamID[12 ]-'0' )*10 )+'0' );
StreamID[14 ] = ( byte )(seq/10 +'0' );
StreamID[15 ] = ( byte )((seq-(StreamID[14 ]-'0' )*10 )+'0' );
System.out.println("现在时间" );
System.out.println("用Calendar.getInstance().getTime()方式显示时间: " + ca.getTime());
System.out.println("用Calendar获得日期是:" + year +"年" + month +"月" + day + "日" );
System.out.println("用Calendar获得时间是:" + hour +"时" + minute +"分" + second +"秒" );
}
public static void main(String[] args)
{
{
newsDetail nn1 = new newsDetail();
}
try {
Thread.currentThread().sleep(3000 );
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
通信的核心类
{
String msg;
{
r_buff = ByteBuffer.allocate(MAX_LENGTH);
w_buff = ByteBuffer.allocate(MAX_LENGTH);
sendBufTotalLen = MAX_LENGTH;
sendBufLen = sendBufStart = 0
sendBuf =
recvBufTotalLen = MAX_LENGTH;
recvBufLen = recvBufStart = 0
recvBuf =
timeout = 6
}
{
host = str;
port = pt;
}
//这两个函数一定要注意 形参是基类 而实际传入的参数是子类,到时候也是调用子类的参数来做
{
sendBufLen += len;
}
{
{
recvBufLen -= len;
recvBufStart += len;
}
}
{
//这里需要先根据传入的参数来
getBufFrompara(nD);
InetSocketAddress addr =
// 生成一个socketchannel
sc = SocketChannel.open();
sc.configureBlocking(
// 连接到server
sc.connect(addr);
;
System.out.println( "connection has been established!…"
// while (true)
{
// 回射消息 // 复位,清空
w_buff.clear();
w_buff.put(sendBuf,sendBufStart,sendBufLen);
w_buff.flip(); // 转到最开始
// 发送消息
sc.write(w_buff);
w_buff.clear();
// 进入接收状态
{
r_buff.clear();
{
count = sc.read(r_buff);
ss++;
Thread.currentThread().sleep( 10
}
{
}
r_buff.flip();
//判断recvBuf能不能放下接收到的数据
{
//放不下了
//那就先看看前面是不是有空余
{
{
recvBuf
}
recvBufStart = 0
}
{
//这个时候就是真的说数据区长度不够了,属于致命错误
System.err.println("致命错误! 缓冲区长度过小!"
}
}
{ // 也可以转化为字符串,不过需要借助第三个变量了。
r_buff.get(recvBuf,recvBufStart+recvBufLen,r_buff.limit());
//得到了一次数据就要试着做一次解码,如果能够解码,那就完成解码,不能则表示数据不完整,继续等待新数据
//这里注意返回值 如果是0 表示数据不完整 如果是正数 就是解码的字节数 负数表示解码出错
recvBufLen += r_buff.limit();
}
System.out.println("reply is "
}
}
sc.socket().close();
}
ioe.printStackTrace();
}
ie.printStackTrace();
}
System.out.println("Exit App....... "
}
{
newsDetailNewsSum nDNS =
newsSockBase nsb =
nsb.setIPandPort("192.168.0.106"
nsb.start(nDNS);
System.out.println("Exit Allllll....... "
}
}
下面是报文协议的基类
//此类试图将所有的通讯协议的编解码都包含在内!按照一次交互的过程来区分
{
//这个还是有问题 不能达到预计效果 需要修改
{
getStreamID();
}
}
}
//基类中的编解码函数没有作用,具体使用的编解码函数在各个子类中需要重新实现
//必须有返回值 因为调用者需要根据返回值做一些操作
//这里的参数 buf是需要填写的缓冲区 start 是缓冲区开始位置 len 是可用的缓冲区长度
{
}
//这里的参数 buf是需要需要解码的缓冲区 start 是缓冲区开始位置 len 是需要解码的长度
{
}
{
Calendar ca = Calendar.getInstance();
hour += 12
hour -= 24
System.out.println(seq);
{
lastCa = ca;
seq = 12
}
{
seq++;
seq = 0
}
//现在根据上面的字段组成StreamID字符串
//目前先使用手工的办法来写,效率高一些
StreamID[0
StreamID[1
StreamID[2
StreamID[3
StreamID[4
StreamID[5
StreamID[6
StreamID[7
StreamID[8
StreamID[9
StreamID[10
StreamID[11
StreamID[12
StreamID[13
StreamID[14
StreamID[15
System.out.println("现在时间"
System.out.println("用Calendar.getInstance().getTime()方式显示时间: "
System.out.println("用Calendar获得日期是:"
System.out.println("用Calendar获得时间是:"
}
{
{
newsDetail nn1 =
}
Thread.currentThread().sleep(3000
}
// TODO Auto-generated catch block
e.printStackTrace();
}