A. 如何干净的实现android/java Socket 长连接通信
JavaSocket通信有很多的时候需要我们不断的学习。方面效率虽然不及C与C++但它以灵活语言优势,为大家广为使用。本文就对在使用java做通信方面程序时候应改注意问题做以说明。
1.长连接、短链接只是针对客户端而言,服务器无所谓长、短;
2.无论同步或者异步通信,发送之后务必要又响应回复,确认收到,负责进行一定范围内重发,例如重发三次;
3.长连接服务器与客户端之间务必需要心跳探测,由客户端主动发起;
4.短连接服务器通用代码:
python">packagecom.biesan.sms.gate.unioncom.communication;
importcom.biesan.commons.Constants;
importcom.biesan.commons.util.CodeUtil;
importcom.biesan.sms.gate.unioncom.data.*;
importcom.biesan.sms.gate.unioncom.util.GateInfo;
importjava.net.*;
importjava.io.*;
importjava.util.*;
importorg.apache.log4j.*;
importspApi.*;
{
//stopflag
privatebooleanunInterrupt=true;
privatebooleanunErr=true;
//privatebooleancloseSocketFlag=false;
//serversocket
privateServerSocketserverSo=null;
//currentsocket
privateSocketso=null
privateOutputStreamoutput=null;
privateInputStreaminput=null;
//gatecommand
privateSGIP_CommandtmpCmd=null;
privateSGIP_Commandcmd=null;
privateBindbind=null;
privateBindRespbindResp=null;
//privateUnbinnBind=null;
privateUnbindRespunBindResp=null;
=true;
LoggerunioncomLog=Logger.getLogger(Unioncom
Deliver.class.getName());
publicUnioncomDeliver(){
}
publicvoidrun(){
unioncomLog.info("Start...");
while(unInterrupt){
this.initServer();
this.startServices();
while(this.unAcceptErrorFlag){
try{
//接受连接请求
unioncomLog.info("beforeacceptconnection!.......
FreeMemroy:"+Runtime.getRuntime().freeMemory());
this.acceptConnection();
unioncomLog.info("afteracceptconnection!.......
FreeMemroy:"+Runtime.getRuntime().freeMemory());
while(unErr){
cmd=newCommand();
unioncomLog.info("beforereadcommandfromstream
...........FreeMemroy:"+Runtime.getRuntime().
freeMemory());
tmpCmd=cmd.read(input);
unioncomLog.info("afterreadcommandfromstream"+
getCommandString(cmd.getCommandID())+"FreeMemroy:"+
Runtime.getRuntime().freeMemory());
if(tmpCmd==null){
unErr=false;
break;
}
switch(cmd.getCommandID()){
//biadreadycommunication
caseSGIP_Command.ID_SGIP_BIND:{
this.dealBind();
break;
}//exitbind
caseSGIP_Command.ID_SGIP_UNBIND:{
this.dealUnBind();
unioncomLog.info("afterunbindconnection!.......
FreeMemroy:"+Runtime.getRuntime().freeMemory());
break;
}//deliver
....
default://错误的命令字
break;
}//switch
}//while(unErr)
}catch(Exceptione){
unioncomLog.error("UnioncomRecvServiceError"
+e.getMessage());
}finally{
if(this.so!=null){
this.closeSocket();
}
this.unErr=true;
}
}//while(this.unAcceptErrorFlag)
try{
this.closeServerSocket();
sleep(200);//sleep
}catch(InterruptedExceptionie){
}
}//while(unInterrupt)
}
privateStringgetCommandString(intcmd){
switch(cmd){
//biadreadycommunication
caseSGIP_Command.ID_SGIP_BIND:{
return"BINDCOMMAND";
}//exitbind
caseSGIP_Command.ID_SGIP_UNBIND:{
return"UNBINDCOMMAND";
}//deliver
case...
default:
return"UNKNOWNCOMMAND";
}
}
privatevoiddealBind(){
try{
bind=newBind(tmpCmd);
if(bind.readbody()!=0){
unioncomLog.warn("ReadBinderror");
this.unErr=false;
}
bindResp=newBindResp(tmpCmd.getMsgHead());
bindResp.SetResult(0);
bindResp.write(output);
unioncomLog.debug("Bindsuccess!");
}catch(Exceptione){
unioncomLog.error("DelaUnionRecvBindError!"+
e.getMessage());
this.unErr=false;
}
}
privatevoiddealUnBind(){
try{
//unBind=(Unbind)tmpCmd;
unBindResp=newUnbindResp(tmpCmd.getMsgHead());
unBindResp.write(output);
unioncomLog.debug("UnBindsuccess!");
}catch(Exceptione){
unioncomLog.warn("Unbinderror!"+e.getMessage());
}
this.unErr=false;
}
privatevoidstartServices(){
booleanunStartServices=true;
while(unStartServices){
try{
serverSo=newServerSocket(ugInfo.getLocalServerPort(),5,
InetAddress.getByName(ugInfo.getLocalIpAdd()));
//serverSo.setSoTimeout(60000);
unStartServices=false;
unioncomLog.info("CreateunionrecvsocketOk!");
}catch(IOExceptione){
unioncomLog.warn("Createunionrecvsocketerror!"
+e.getMessage());
unStartServices=true;
UnioncomSubmit.thrSlp(3000);
}
}
}
privatevoidacceptConnection(){
//Accept失败
try{
so=serverSo.accept();
so.setSoTimeout(10000);
}catch(Exceptione){
unioncomLog.warn("AcceptError!"+e.getMessage());
this.closeServerSocket();
this.unAcceptErrorFlag=false;
this.unErr=false;
}
//Accept成功
try{
input=so.getInputStream();
output=so.getOutputStream();
}catch(IOExceptione){
unioncomLog.warn("GetI/OstreamError!"+e.getMessage());
this.closeService();
this.unAcceptErrorFlag=false;
this.unErr=false;
}
}
privatevoidcloseSocket(){
try{
so.close();
unioncomLog.info("SocketCloseSuccess!!!");
}catch(Exceptione){
unioncomLog.error("SocketCloseFailure!!!"+e.getMessage());
}
}
privatevoidcloseServerSocket(){
try{
serverSo.close();
unioncomLog.info("ServerSocketCloseSuccess!!!");
}catch(Exceptione){
unioncomLog
.error("ServerSocketCloseFailure!!!"+e.getMessage());
}
}
privatevoidcloseService(){
this.closeSocket();
this.closeServerSocket();
}
privatevoidinitServer(){
this.bind=null;
this.bindResp=null;
//this.unBind=null;
this.unBindResp=null;
this.tmpCmd=null;
this.cmd=null;
this.serverSo=null;
this.so=null;
this.output=null;
this.input=null;
this.unErr=true;
//this.closeSocketFlag=false;
unioncomLog.info("Memory***==="
+java.lang.Runtime.getRuntime().freeMemory());
}
(){
this.unInterrupt=false;
unioncomLog.info("Requreinterrupt!!!");
}
(intmsgCoding,byte[]msgContent){
StringdeliverContent=null;
try{
if(msgContent!=null){
if(msgCoding==8){//处理ucs32编码
deliverContent=newString(msgContent,
"UnicodeBigUnmarked");
}elseif(msgCoding==0){//处理ASCII编码
deliverContent=newString(msgContent,"ASCII");
}elseif(msgCoding==4){//处理binary编码
deliverContent=newString(msgContent);
}elseif(msgCoding==15){//处理GBK编码
deliverContent=newString(msgContent,"GBK");
//处理DELIVER数据包的短信息ID
}else{
unioncomLog.error("编码格式错误!");
return"";
}
}else
return"";
returndeliverContent;
}catch(){
unioncomLog.error("dealcontenterror!"+
ex.getMessage());
return"";
}
}
}
B. 如何用socket实现android手机与手机之间的通信
参考一般的JAVA的socket编程,如果通过手机网络,就不要使用UDP即可。
C. 安卓手机socket未连接怎么办
安卓手机socket未连接的解决方法是:
1、另开一个线程去做网络连接的操作早凳。
2、在activity类陆高旅中的onCreate方法中添加strict代码念空。
D. 如何干净的实现Android/Java Socket 长连接通信
所谓长连接,它通常包含以下几个关键过程:
轮询的建立
建立轮询的过程很简单,浏览器发起请求后进入循环等待状态,此时由于服务器还未做出应答,所以HTTP也一直处于连接状态中。
2. 数据的推送
在循环过程中,服务器程序对数据变动进行监控,如发现更新,将该信息输出给浏览器,随即断开连接,完成应答过程,实现“服务器推”。
3. 轮询的终止
轮询可能在以下3种情况时终止:
3.1. 有新数据推送
当循环过程中服务器向浏览器推送信息后,应该主动结束程序运行从而让连接断开,这样浏览器才能及时收到数据。
3.2. 没有新数据推送
循环不能一直持续下去,应该设定一个最长时限,避免WEB服务器超时(Timeout),若一直没有新信息,服务器应主动向浏览器发送本次轮询无新信息的正常响应,并断开连接,这也被称为“心跳”信息。
3.3. 网络故障或异常
由于网络故障等因素造成的请求超时或出错也可能导致轮询的意外中断,此时浏览器将收到错误信息。
4. 轮询的重建
浏览器收到回复并进行相应处理后,应马上重新发起请求,开始一个新的轮询周期。
客户端代码片段
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" isELIgnored="false" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="author" content="hoojo & http://hoojo.cnblogs.com"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <%@ include file="/tags/jquery-lib.jsp"%> <script type="text/javascript"> $(function () { window.setInterval(function () { $.get("${pageContext.request.contextPath}/communication/user/ajax.mvc", {"timed": new Date().getTime()}, function (data) { $("#logs").append("[data: " + data + " ]<br/>"); }); }, 3000); }); </script> </head> <body> <div id="logs"></div> </body> </html>
服务器端代码
@RequestMapping("/ajax") public void ajax(long timed, HttpServletResponse response) throws Exception { PrintWriter writer = response.getWriter(); Random rand = new Random(); // 死循环 查询有无数据变化 while (true) { Thread.sleep(300); // 休眠300毫秒,模拟处理业务等 int i = rand.nextInt(100); // 产生一个0-100之间的随机数 if (i > 20 && i < 56) { // 如果随机数在20-56之间就视为有效数据,模拟数据发生变化 long responseTime = System.currentTimeMillis(); // 返回数据信息,请求时间、返回数据时间、耗时 writer.print("result: " + i + ", response time: " + responseTime + ", request time: " + timed + ", use time: " + (responseTime - timed)); break; // 跳出循环,返回数据 } else { // 模拟没有数据变化,将休眠 hold住连接 Thread.sleep(1300); } } }
E. 如何干净的实现Android/Java Socket 长连接通信
在远标实现过:socket模拟网页的报文连接某个网站,创建tcp的socket后,当我socket.connect后,如果在5到7秒钟不socket.send,那么这个链接就失效了。 请问如何长时间的保持这个链接
这是在服务器端的设置的,客户端没法设置,可以发送心跳包。
socket.connect后,每3-4秒用socket.send发送一字节数据(内容随便),然后观查这个连接是否保持。
lientSocket=serverSocket.accept();
OutputStream os = clientSocket.getOutputStream();
ObjectOutputStream oos=new ObjectOutputStream(os);
oos.writeObject(al);
oos.flush();
oos.close()//socket会关闭
实现:
长连接的维持,是要客户端程序,定时向服务端程序,发送一个维持连接包的。
如果,长时间未发送维持连接包,服务端程序将断开连接。
客户端:
通过持有Client对象,可以随时(使用sendObject方法)发送Object给服务端。
如果keepAliveDelay毫秒(程序中是2秒)内未发送任何数据,则,自动发送一个KeepAlive对象给服务端,
用于维持连接。
由于,我们向服务端,可以发送很多不同的对象,服务端也可以返回不同的对象。
所以,对于返回对象的处理,要编写具体的ObjectAction实现类进行处理。
通过Client.addActionMap方法进行添加。这样,程序会回调处理。
服务端:
由于客户端会定时(keepAliveDelay毫秒)发送维持连接的信息过来,所以,服务端要有一个检测机制。
即当服务端receiveTimeDelay毫秒(程序中是3秒)内未接收任何数据,则,自动断开与客户端的连接。
ActionMapping的原理与客户端相似(相同)。
通过添加相应的ObjectAction实现类,可以实现不同对象的响应、应答过程。
F. android如何与手机进行通信(Socket连接)
其实跟电脑差不多了,android里调用socket的方法,拿到socket后就可以发送数据并接收数据。
我最近正在做android方面的通信,真的想把完整的代码都给你,可是没办法,公司机密。。
给你我的socket连接类吧。。。
package sean.socket;
///////////把MyType的一些方法替换成Writer的方法
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import sean.Sysout;
import sean.business.BusinessCenter;
import sean.business.LoginManager;
import sean.format.MyType;
import sean.io.Reader;
import sean.transfer.BytesBuffer;
import sean.transfer.DataCenter;
public class SocketThread implements Runnable {
String Server = "";
int Port = 0;
static Socket cs = null;
// Thread ioThread=null;
static boolean bool_SocketThread = false;
static OutputStream output = null;
public SocketThread(String server, int port) {
Server = server;
Port = port;
bool_SocketThread = true;
}
@Override
public void run() {
// TODO Auto-generated method stub
while (bool_SocketThread) {
try {
// if (cs == null) {
DataCenter.setBool_Login(false);// 设置登录失败
Sysout.println("正在尝试连接ClientSocket...", Sysout.TempOutDebug);
cs = new Socket(InetAddress.getByName(Server), Port);
if (cs != null) {
Sysout.println("ClientSocket连接成功!__" + cs,
Sysout.TempOutDebug);
cs.setKeepAlive(true);//让socket保持活动状态
InputStream input = cs.getInputStream();
output = cs.getOutputStream();
BusinessCenter.sendLoginData();
BytesBuffer bBuffer = new BytesBuffer();
byte[] Buffer = new byte[1024];
int ReadBytes = input.read(Buffer);
while (ReadBytes != -1) {
Sysout.println("已读取" + ReadBytes + "个字节到缓冲区",
Sysout.TempOutDebug);
byte[] b = new byte[ReadBytes];
b = MyType.BytesInsertToBytes(Buffer, b, 0);
Reader r = new Reader(b);
Sysout.println(r.toString() + "____ReadBytes=="
+ ReadBytes, Sysout.TempOutDebug);
bBuffer.InsertToBuffer(Buffer, ReadBytes);
ReadBytes = input.read(Buffer);
}
} else {
Sysout.printException("ClientSocket连接失败!请确认网络正常且服务器已开启。");
}
// }
// 执行到这里说明inputstream.read()已中断,说明socket已断开连接
// cs=null;
LoginManager.setLoginValue(-1);// 业务中心登录注销,即登录管理器注销登录
DataCenter.setBool_Login(false);// 数据中心登录注销
Sysout.printException(cs + "已断开。");
Thread.sleep(2 * 1000);// 睡眠2秒后继续循环
// try {
// // 判断ClientSocket是否已断开
// cs.sendUrgentData(0);
// } catch (IOException e) {
// // TODO Auto-generated catch block
// Sysout.printException("ClientSocket已断开,重新连接。"+e);
// cs.close();
// cs = null;
// }
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
Sysout.printException("SocketThread.java====解析服务器名称发生异常!" + e);
// e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Sysout.printException("SocketThread发生IO异常,异常消息:" + e);
try {
if (cs != null) {
Sysout.println("准备关闭" + cs, Sysout.TempOutDebug);
cs.shutdownOutput();
cs.shutdownInput();
cs.close();
cs = null;
output = null;
LoginManager.setLoginValue(-1);// 业务中心登录注销,即登录管理器注销登录
DataCenter.setBool_Login(false);// 数据中心登录注销
Sysout.println(cs + "已关闭。", Sysout.TempOutDebug);
}
try {
Thread.sleep(5000);
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
Sysout.printException("SocketThread.java====线程睡眠异常!!"
+ e2);
// e2.printStackTrace();
}
String ExceptionInfos=e.toString();
if(ExceptionInfos.endsWith("Connection refused")){
stopSocketThread();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
Sysout.printException(cs + "关闭发生异常::" + e1);
// e1.printStackTrace();
try {
Thread.sleep(5000);
} catch (InterruptedException e2) {
// TODO Auto-generated catch block
Sysout.printException("SocketThread.java====线程睡眠异常!!"
+ e2);
// e2.printStackTrace();
}
}
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// while(bool_SocketThread)
Sysout.println("SocketThread已停止。", Sysout.TempOutDebug);
}
public static Socket getSocket() {
return cs;
}
// public void setBool(boolean bool0) {
// bool_SocketThread = bool0;
// }
public static OutputStream getOutputStream() {
return output;
}
public static void stopSocketThread() {
try {
// 停止SocketThread线程,必须先把循环的标志bool_SocketThread置为false,否则可能继续循环,重新建立socket连接
bool_SocketThread = false;
// 关闭socket
if (cs != null) {
cs.shutdownOutput();
cs.shutdownInput();
cs.close();
cs = null;
output = null;
Sysout.println("ClientSocket已被强制关闭。");
// LoginManager.setLoginValue(-1);// 业务中心登录注销,即登录管理器注销登录
// DataCenter.setBool_Login(false);// 数据中心登录注销
// byte[] lock=LoginActivity.getLock();
// synchronized(lock){
// lock.notify();
// }
}
} catch (IOException e) {
// TODO Auto-generated catch block
Sysout.printException("强制关闭" + cs + "发生异常::" + e);
// e.printStackTrace();
}
}
}
必须先在android里启动一个服务,由服务去启动这个socket线程,因为如果是UI去启动的话,页面会卡住。。。