javaSocket与C通信

前段时间写了个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();
}

标签