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去啟動的話,頁面會卡住。。。