论坛首页 Java企业应用论坛

javaSocket与C通信

浏览 10858 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (6) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-12-14   最后修改:2009-12-14

前段时间写了个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[i] = 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();
		} 
		{
			newsDetail nn2 = new newsDetail();
		}
	      	


	}

}

 

   发表时间:2009-12-14  
汗死我,大家都好喜欢测试用8888端口啊... ...
0 请登录后投票
   发表时间:2009-12-14  
nishizhutoua 写道
汗死我,大家都好喜欢测试用8888端口啊... ...

8080 Eclipse 占了  8081被 netbean 占了  ╮(╯▽╰)╭
0 请登录后投票
   发表时间:2009-12-15  
楼主类名不规范的说
1 请登录后投票
   发表时间:2009-12-15  
linliangyi2007 写道
楼主类名不规范的说

1 请登录后投票
   发表时间:2009-12-15  
我错了,汗死我了
0 请登录后投票
   发表时间:2009-12-16  
开发一个servlet,初始化的时候就用你那个核心类去连接服务器,并将servlet设置成loadonstartup
0 请登录后投票
   发表时间:2009-12-16  
如果网络断开或者程序出现异常该如何重连呢?
0 请登录后投票
   发表时间:2009-12-16  
有没有遇到 字节序的问题。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
0 请登录后投票
   发表时间:2009-12-16  
trydofor 写道
有没有遇到 字节序的问题。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。

C服务端将 java 的低字节与高字节的 位子交换了
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics