- 浏览: 122158 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
roychenyi:
<br>1<br>2<br> ...
pager-taglib 使用说明 -
roychenyi:
<br>换行<br>换行<br& ...
pager-taglib 使用说明 -
wangwenfei1985:
[flash=200,200][url][img][list] ...
pager-taglib 使用说明 -
时光后19:
,看到你这样真好,
FileNet调用webService配置 -
ysen:
大sql导入mysql
如果是SQL格式的。有的可能上100 ...
mysqldump备份详解
前段时间写了个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(); } } }
评论
20 楼
ysen
2009-12-18
topcode 写道
楼主不是很喜欢发设计模式的帖子么
谢谢关注O(∩_∩)O哈哈~
19 楼
topcode
2009-12-18
楼主不是很喜欢发设计模式的帖子么
18 楼
ysen
2009-12-16
pwz1985 写道
我最近刚好做了个javaSocket与C通信的组件
//连接成功flag
boolean connSuccess = false;
while (!connSuccess) {
try {
socket = new Socket(ip,port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//连接失败,3秒后重新连接
System.out.println("(IP="+ip+","+"PORT="+port+")连接失败,3秒后重连");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
continue;
}
connSuccess = true;
}
//连接成功flag
boolean connSuccess = false;
while (!connSuccess) {
try {
socket = new Socket(ip,port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//连接失败,3秒后重新连接
System.out.println("(IP="+ip+","+"PORT="+port+")连接失败,3秒后重连");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
continue;
}
connSuccess = true;
}
这个问题 java 或 c 有一边 转换下就好了
17 楼
bcw104
2009-12-16
linliangyi2007 写道
楼主类名不规范的说
支持
JAVA与C通讯得考虑大端小端问题吧
16 楼
ysen
2009-12-16
tjgamejx2 写道
ysen 写道
tjgamejx2 写道
楼主,如果是长连接的话,每次调用一次doGet()或者doPost()向C德socket发送一个报文,然后C处理后回一个消息,当并发高的时候,不需要很高,发送A,C回A,发送B,C回B。如果并发了,JAVA发条A,紧接着发了条B,C接着回了条消息,楼主,C回的这个消息,您能确定这条消息是A的结果还是B的结果吗。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
发送的报文有流水号啊,根据流水号判断,在转发个客户端,这样的话可能要用到
缓存和服务器推技术,不知道我说的对不对
不管什么标志都是没有用的,你在一个doPost方法里发送了一条消息,你就必须在这个方法里得到回应的消息。比如你发的是00001流水号订单,接到的结果是00002,你怎么办,另外一个方法里发的00002,却得到了00001,它咋办。
我说一个方法吧,楼主socket得到的消息全部存在全局变量里,这样每个方法才能共享资源。你发的00001,你就一直查全局变量里是否有00001回应的消息。但是效率明显很烂。
你的需求应该是要用到短连接阻塞
一开始就是 短连接堵塞, 效果也不错
后来改成上面的样子 短连接非堵塞,有的时候发过去接不到返回的信息,很明显不行
15 楼
tjgamejx2
2009-12-16
ysen 写道
tjgamejx2 写道
楼主,如果是长连接的话,每次调用一次doGet()或者doPost()向C德socket发送一个报文,然后C处理后回一个消息,当并发高的时候,不需要很高,发送A,C回A,发送B,C回B。如果并发了,JAVA发条A,紧接着发了条B,C接着回了条消息,楼主,C回的这个消息,您能确定这条消息是A的结果还是B的结果吗。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
发送的报文有流水号啊,根据流水号判断,在转发个客户端,这样的话可能要用到
缓存和服务器推技术,不知道我说的对不对
不管什么标志都是没有用的,你在一个doPost方法里发送了一条消息,你就必须在这个方法里得到回应的消息。比如你发的是00001流水号订单,接到的结果是00002,你怎么办,另外一个方法里发的00002,却得到了00001,它咋办。
我说一个方法吧,楼主socket得到的消息全部存在全局变量里,这样每个方法才能共享资源。你发的00001,你就一直查全局变量里是否有00001回应的消息。但是效率明显很烂。
你的需求应该是要用到短连接阻塞
14 楼
ysen
2009-12-16
tjgamejx2 写道
楼主,如果是长连接的话,每次调用一次doGet()或者doPost()向C德socket发送一个报文,然后C处理后回一个消息,当并发高的时候,不需要很高,发送A,C回A,发送B,C回B。如果并发了,JAVA发条A,紧接着发了条B,C接着回了条消息,楼主,C回的这个消息,您能确定这条消息是A的结果还是B的结果吗。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
发送的报文有流水号啊,根据流水号判断,在转发个客户端,这样的话可能要用到
缓存和服务器推技术,不知道我说的对不对
13 楼
tjgamejx2
2009-12-16
楼主,如果是长连接的话,每次调用一次doGet()或者doPost()向C德socket发送一个报文,然后C处理后回一个消息,当并发高的时候,不需要很高,发送A,C回A,发送B,C回B。如果并发了,JAVA发条A,紧接着发了条B,C接着回了条消息,楼主,C回的这个消息,您能确定这条消息是A的结果还是B的结果吗。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
补充下:如果你使用长连接,想要每条信息都得到自己对应的结果,你必须用阻塞。处理效果,可想而知。
问下楼主,请问短连接非阻塞,为的是什么,非阻塞和多线程的区别在于,多线程,每个线程独立,发的信息回得到其对应结果。
貌似楼主应该用短连接阻塞。你的业务才能清晰,聊天程序非阻塞还有点道理,毕竟我这次回的消息,不一定就是你上个问题。
短连接的话,每条消息都对应一个socket,你能确定回的消息就是本次处理的结果。
补充下:如果你使用长连接,想要每条信息都得到自己对应的结果,你必须用阻塞。处理效果,可想而知。
问下楼主,请问短连接非阻塞,为的是什么,非阻塞和多线程的区别在于,多线程,每个线程独立,发的信息回得到其对应结果。
貌似楼主应该用短连接阻塞。你的业务才能清晰,聊天程序非阻塞还有点道理,毕竟我这次回的消息,不一定就是你上个问题。
12 楼
pwz1985
2009-12-16
我最近刚好做了个javaSocket与C通信的组件
//连接成功flag
boolean connSuccess = false;
while (!connSuccess) {
try {
socket = new Socket(ip,port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//连接失败,3秒后重新连接
System.out.println("(IP="+ip+","+"PORT="+port+")连接失败,3秒后重连");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
continue;
}
connSuccess = true;
}
//连接成功flag
boolean connSuccess = false;
while (!connSuccess) {
try {
socket = new Socket(ip,port);
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
//连接失败,3秒后重新连接
System.out.println("(IP="+ip+","+"PORT="+port+")连接失败,3秒后重连");
try {
Thread.sleep(3000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
continue;
}
connSuccess = true;
}
11 楼
myworkfirst
2009-12-16
ysen 写道
for_cyan 写道
如果网络断开或者程序出现异常该如何重连呢?
这个问题不知道改如何解决
写一个重连方法,放到异常里,如果断开了,就会抛异常,调用重连方法,判断标志位,如果一直未连接上,每间隔几秒发一次连接请求,如果连接上后,修改标志位,并跳到业务代码,走业务。
这是基本的方法
10 楼
ysen
2009-12-16
for_cyan 写道
如果网络断开或者程序出现异常该如何重连呢?
这个问题不知道改如何解决
9 楼
ysen
2009-12-16
trydofor 写道
有没有遇到 字节序的问题。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
C服务端将 java 的低字节与高字节的 位子交换了
8 楼
trydofor
2009-12-16
有没有遇到 字节序的问题。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
-----------------------------
a) Little-Endian就是低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。
b) Big-Endian就是高位字节排放在内存的低地址端,低位字节排放在内存的高地址端。
c) 网络字节序:TCP/IP各层协议将字节序定义为Big-Endian,因此TCP/IP协议中使用的字节序通常称之为网络字节序。
7 楼
for_cyan
2009-12-16
如果网络断开或者程序出现异常该如何重连呢?
6 楼
diggywang
2009-12-16
开发一个servlet,初始化的时候就用你那个核心类去连接服务器,并将servlet设置成loadonstartup
5 楼
ysen
2009-12-15
我错了,汗死我了
4 楼
ugibb510
2009-12-15
linliangyi2007 写道
楼主类名不规范的说
3 楼
linliangyi2007
2009-12-15
楼主类名不规范的说
2 楼
ysen
2009-12-14
nishizhutoua 写道
汗死我,大家都好喜欢测试用8888端口啊... ...
8080 Eclipse 占了 8081被 netbean 占了 ╮(╯▽╰)╭
1 楼
nishizhutoua
2009-12-14
汗死我,大家都好喜欢测试用8888端口啊... ...
相关推荐
在Java和C这两种语言中,Socket编程提供了丰富的功能,使得跨平台的网络通信变得可能。本篇文章将深入探讨Java和C如何进行Socket编程,并提供相关的实践示例。 首先,我们来了解Socket的基本概念。Socket可以被看作...
1)设计程序,分别构建通信的两端:服务器端和客户端应用程序,套接字类型为面向连接的Socket,自己构建双方的应答模式,实现双方的数据的发送和接收(S发给C,C发给S)。 2)服务端程序能响应单个或任意多个客户端...
在客户机/服务器(C/S)架构中,服务器通常作为守护进程持续运行,监听特定端口,等待客户端发起连接请求。一旦客户端连接,服务器创建一个新的服务进程来处理请求,同时自身继续监听其他客户端的连接。客户端在需要...
Java Socket 实现聊天室毕业设计是一项综合性的编程任务,它涉及到客户端-服务器(C/S)架构、网络通信、用户身份验证以及文件传输等核心概念。在这个项目中,开发者需要运用Java语言来创建一个功能完善的聊天应用...
代码如下: 复制代码 代码如下:import java.io.*; import java.net.*; public class Server { public static void main(String[] args) throws IOException{ System.out.println(“Server started !...
Java 网络通信对 ICQ 的实现 ICQ 是一种基于网络的即时通信工具,可以实现点对点的网络聊天系统。ICQ 的成功推动了国内的本土化,出现了许多国产的 ICQ 软件,如 OICQ 和 Tomq 等。 ICQ 的功能主要是即时信息交流,...
每个客户端通过Socket连接到服务器,实现与其他客户端的通信。 9. **安全性**: 虽然题目未提及,但安全是任何通信工具的重要方面。Java的SSL/TLS库可以用于加密Socket连接,保护用户的隐私信息。 10. **多线程**...
最近在开发javaSocket和C的通信,其中有数据校验就是采用CCITT方式,在网上找了好多,都不切合实际使用,经过一个星期的奋斗查资料,再根据网上搜获,写出了一套标准的校验方法,结果和C语言的校验一直,其中考虑了...
UDP套接字与TCP套接字不同,它不需要在通信前建立连接,直接发送和接收数据报即可。 在更复杂的应用中,比如聊天程序或多人网络游戏,仅有一个服务器主线程处理所有客户端的连接请求将无法满足需求。这时就需要利用...
在IT领域,尤其是在Java开发中,Socket编程与JAXB(Java Architecture for XML Binding)是两个极为重要的技术点,它们各自解决着不同的问题,但都扮演着数据通信与处理中的关键角色。 ### Socket编程 Socket是一...
JavaSocket用于网络编程,RMI和CORBA都支持不同计算机上对象之间的通信。MIS(管理信息系统)是企业信息化管理的基础。 总结来说,软件工程师的大学规划应当包括但不限于对C/C++、C#、Java语言的深入学习,熟练掌握...