java nio socket長連接_nio實現Socket長連接和心跳

前段時間用bio方式,也就是傳統io實現了socket的長連接和心跳,總覺著服務端開啟多線程管理socket連接的方式過于消耗資源,數據并發的情況下可能會影響到性能,因此就嘗試使用nio改進原來的代碼。

然而改進的過程卻不像我起初設想的那般容易,可以說一波三折,原因主要是nio讀寫都是字節流,LZ一開始依然通過ObjectOutputStream.writeObject直接向Socket服務端發送數據,然而問題出現了,每次從ByteBuffer解析出來字節流都不一樣,LZ使出渾身解數,一個字節一個字節的讀取啊,問題沒有了,可是由于是長連接,數據怎么解析啊,查資料,找大神,最后一個網友說有可能是粘包和分包的問題,一時暈菜,LZ網絡可是渣渣啊,行吧,惡補一番,想了解的童鞋可以看看這個。http://blog.csdn.net/sunmenggmail/article/details/38952131

實現原理就像很多協議那樣,自定義一套傳輸協議,比如消息長度(int型,4個字節)+消息體的方式,根據解析的消息長度定長解析消息內容,雖然最后證明LZ的問題不是由于粘包和分包造成的,但是LZ就這樣歪打正著,給實現了!!!數據不正常的問題后來通過DataOutputStream和DataInputStream的方式也得到了解決。

廢話多了,帖代碼。

服務端:

package com.feng.test.longconnection1;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.nio.charset.Charset;

import java.util.Arrays;

import java.util.HashMap;

import java.util.Iterator;

import java.util.Map;

import java.util.concurrent.BlockingQueue;

import java.util.concurrent.LinkedBlockingDeque;

import org.apache.commons.lang.ArrayUtils;

/**

*

* @author songfeng

* @version 1.0

* @since 2015-10-24

* @category com.feng.test.longconnection

*

*/

public class Server

{

private Map heatTimeMap = new HashMap();

public Server(int port)

{

Selector selector = null;

ServerSocketChannel serverChannel = null;

try

{

//獲取一個ServerSocket通道

serverChannel = ServerSocketChannel.open();

serverChannel.configureBlocking(false);

serverChannel.socket().bind(new InetSocketAddress(port));

//獲取通道管理器

selector = Selector.open();

//將通道管理器與通道綁定,并為該通道注冊SelectionKey.OP_ACCEPT事件,

//只有當該事件到達時,Selector.select()會返回,否則一直阻塞。

serverChannel.register(selector, SelectionKey.OP_ACCEPT);

while (selector.select() > 0)

{

//選擇注冊過的io操作的事件

Iterator it = selector.selectedKeys().iterator();

while (it.hasNext())

{

SelectionKey readyKey = it.next();

//刪除已選key,防止重復處理

it.remove();

if (readyKey.isAcceptable())

{

ServerSocketChannel serverSocketChannel = (ServerSocketChannel) readyKey.channel();

SocketChannel socketChannel = serverSocketChannel.accept();

socketChannel.configureBlocking(false);

// 連接成功后,注冊接收服務器消息的事件

socketChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);

}

else if(readyKey.isReadable())

{

SocketChannel socketChannel = (SocketChannel)readyKey.channel();

Object obj = receiveData(socketChannel);

String msg = "Server back:";

if(obj instanceof String)

{

String id = obj.toString().split(",")[0];

if(heatTimeMap.get(id) != null

&& System.currentTimeMillis() - heatTimeMap.get(id) > 5000)

{

socketChannel.socket().close();

}

else

{

heatTimeMap.put(id, System.currentTimeMillis());

}

long time = System.currentTimeMillis();

msg += time + "\n";

sendData(socketChannel, msg);

}

else if(obj instanceof Pojo)

{

msg += ((Pojo)obj).getName() + "\n";

sendData(socketChannel, msg);

}

}

}

}

}

catch (Exception e)

{

e.printStackTrace();

}

finally

{

try

{

selector.close();

if(serverChannel != null)

{

serverChannel.close();

}

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

private static Object receiveData(SocketChannel socketChannel)

{

Object obj = null;

ByteArrayOutputStream baos = new ByteArrayOutputStream();

ByteBuffer intBuffer = ByteBuffer.allocate(4);

ByteBuffer objBuffer = ByteBuffer.allocate(1024);

int size = 0;

int sum = 0;

int objlen = 0;

byte[] bytes = null;

try

{

while((size = socketChannel.read(intBuffer)) > 0)

{

intBuffer.flip();

bytes = new byte[size];

intBuffer.get(bytes);

baos.write(bytes);

intBuffer.clear();

if(bytes.length == 4)

{

objlen = bytesToInt(bytes,0);

}

if(objlen > 0)

{

byte[] objByte = new byte[0];

while(sum != objlen)

{

size = socketChannel.read(objBuffer);

if(size > 0)

{

objBuffer.flip();

bytes = new byte[size];

objBuffer.get(bytes,0,size);

baos.write(bytes);

objBuffer.clear();

objByte = ArrayUtils.addAll(objByte, bytes);

sum += bytes.length;

}

}

obj = ByteToObject(objByte);

break;

}

}

}

catch (Exception e)

{

e.printStackTrace();

}

finally

{

try

{

baos.close();

}

catch (Exception e)

{

e.printStackTrace();

}

}

return obj;

}

private static void sendData(SocketChannel socketChannel,Object obj)

{

byte[] bytes = ObjectToByte(obj);

ByteBuffer buffer = ByteBuffer.wrap(bytes);

try

{

socketChannel.write(buffer);

}

catch (IOException e)

{

e.printStackTrace();

}

}

/**

* byte數組中取int數值,本方法適用于(低位在前,高位在后)的順序。

*

* @param ary

* byte數組

* @param offset

* 從數組的第offset位開始

* @return int數值

*/

public static int bytesToInt(byte[] ary, int offset) {

int value;

value = (int) ((ary[offset]&0xFF)

| ((ary[offset+1]<<8) & 0xFF00)

| ((ary[offset+2]<<16)& 0xFF0000)

| ((ary[offset+3]<<24) & 0xFF000000));

return value;

}

public static Object ByteToObject(byte[] bytes)

{

Object obj = null;

try

{

// bytearray to object

ByteArrayInputStream bi = new ByteArrayInputStream(bytes);

ObjectInputStream oi = new ObjectInputStream(bi);

obj = oi.readObject();

bi.close();

oi.close();

}

catch (Exception e)

{

//e.printStackTrace();

}

return obj;

}

public static byte[] ObjectToByte(Object obj)

{

byte[] bytes = null;

try

{

// object to bytearray

ByteArrayOutputStream bo = new ByteArrayOutputStream();

ObjectOutputStream oo = new ObjectOutputStream(bo);

oo.writeObject(obj);

bytes = bo.toByteArray();

bo.close();

oo.close();

}

catch (Exception e)

{

e.printStackTrace();

}

return bytes;

}

public static void main(String[] args)

{

Server server = new Server(55555);

}

}

客戶端:

package com.feng.test.longconnection1;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.DataInputStream;

import java.io.DataOutputStream;

import java.io.IOException;

import java.io.ObjectInputStream;

import java.io.ObjectOutputStream;

import java.net.Socket;

import java.nio.ByteBuffer;

import java.nio.ByteOrder;

import java.util.ArrayList;

/**

*

* @author songfeng

* @version 1.0

* @since 2015-10-24

* @category com.feng.test.longconnection

*

*/

public class Client

{

private Socket socket;

private String ip;

private int port;

private String id;

DataOutputStream dos;

DataInputStream dis;

public Client(String ip, int port,String id)

{

try

{

this.ip = ip;

this.port = port;

this.id = id;

this.socket = new Socket(ip, port);

//this.socket.setKeepAlive(true);

dos = new DataOutputStream(socket.getOutputStream());

dis = new DataInputStream(socket.getInputStream());

new Thread(new heartThread()).start();

new Thread(new MsgThread()).start();

}

catch (Exception e)

{

e.printStackTrace();

}

}

public void sendMsg(Object content)

{

try

{

int len = ObjectToByte(content).length;

ByteBuffer dataLenBuf = ByteBuffer.allocate(4);

dataLenBuf.order(ByteOrder.LITTLE_ENDIAN);

dataLenBuf.putInt(0, len);

dos.write(dataLenBuf.array(), 0 , 4);

dos.flush();

dos.write(ObjectToByte(content));

dos.flush();

}

catch (Exception e)

{

e.printStackTrace();

closeSocket();

}

}

public void closeSocket()

{

try

{

socket.close();

dos.close();

dis.close();

}

catch (IOException e)

{

e.printStackTrace();

}

}

public static byte[] ObjectToByte(Object obj)

{

byte[] bytes = null;

try

{

// object to bytearray

ByteArrayOutputStream bo = new ByteArrayOutputStream();

ObjectOutputStream oo = new ObjectOutputStream(bo);

oo.writeObject(obj);

bytes = bo.toByteArray();

bo.close();

oo.close();

}

catch (Exception e)

{

e.printStackTrace();

}

return bytes;

}

public static Object ByteToObject(byte[] bytes)

{

Object obj = null;

try

{

// bytearray to object

ByteArrayInputStream bi = new ByteArrayInputStream(bytes);

ObjectInputStream oi = new ObjectInputStream(bi);

obj = oi.readObject();

bi.close();

oi.close();

}

catch (Exception e)

{

e.printStackTrace();

}

return obj;

}

class heartThread implements Runnable

{

@Override

public void run()

{

while(true)

{

try

{

Thread.sleep(1000);

long time = System.currentTimeMillis();

//System.out.println("client send:" + time);

sendMsg("Client" + id + "," + time);

}

catch (Exception e)

{

e.printStackTrace();

}

}

}

}

class MsgThread implements Runnable

{

@Override

public void run()

{

int temp;

while(true)

{

try

{

if(socket.getInputStream().available() > 0)

{

byte[] bytes = new byte[1024];

int len = 0;

while((char)(temp = dis.read()) != '\n')

{

bytes[len]=(byte)temp;

len++;

}

System.out.println(ByteToObject(bytes));

}

}

catch (Exception e)

{

closeSocket();

}

}

}

}

public static void main(String[] args)

{

Client client1 = new Client("127.0.0.1", 55555, "1");

client1.sendMsg(new Pojo("songfeng", 26, new ArrayList()));

try

{

Thread.sleep(500);

}

catch (InterruptedException e)

{

e.printStackTrace();

}

Client client2 = new Client("127.0.0.1", 55555, "2");

}

}

數據類:

package com.feng.test.longconnection1;

import java.io.Serializable;

import java.util.List;

/**

*

* @author songfeng

* @version 1.0

* @since 2015-10-16

* @category com.feng.test.longconnection

*

*/

public class Pojo implements Serializable

{

/**

* 序列化

*/

private static final long serialVersionUID = -8868529619983791261L;

private String name;

private int age;

private List likeThing;

public Pojo(String name, int age, List likeThing)

{

super();

this.name = name;

this.age = age;

this.likeThing = likeThing;

}

public String getName()

{

return name;

}

public void setName(String name)

{

this.name = name;

}

public int getAge()

{

return age;

}

public void setAge(int age)

{

this.age = age;

}

public List getLikeThing()

{

return likeThing;

}

public void setLikeThing(List likeThing)

{

this.likeThing = likeThing;

}

}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/396381.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/396381.shtml
英文地址,請注明出處:http://en.pswp.cn/news/396381.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

unity讓對象作為參數_C#+Unity學習筆記:類與對象

參考文獻蜜酒廳通訊社 游戲部 石中居士對象(object)&#xff1a;有狀態、行為和身份的東西。狀態(state)&#xff1a;表示物體特征的信息&#xff0c;可以用來跟蹤對象的狀態。屬性(properties)&#xff1a;因為編程人員需要把控對象的狀態&#xff0c;所以要對其進行訪問。通過…

Tomcat 報 The valid characters are defined in RFC 7230 and RFC 3986

問題 24-Mar-2017 23:43:21.300 INFO [http-apr-8001-exec-77] org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level. java.lang.IllegalAr…

Linux Kernel Oops異常分析

0&#xff0e;linux內核異常常用分析方法 異常地址是否在0附近&#xff0c;確認是否是空指針解引用問題異常地址是否在iomem映射區&#xff0c;確認是否是設備訪問總線異常問題&#xff0c;如PCI異常導致的地址訪問異常異常地址是否在stack附近&#xff0c;如果相鄰&#xff0c…

Centos7.5 VMtools的安裝與卸載

一、安裝1、自帶tools&#xff1a; 選擇VMware工具欄 > 虛擬機 > 安裝VMtools2、掛載光驅3、tar -zxvf VMwareTools-10.3.2-9925305.tar.gz&#xff08;這里以tar文件為例&#xff09;4、切換到目標目錄&#xff0c;執行&#xff08;一定要使用root權限執行&#xff09;…

gitter 卸載_最佳Gitter渠道:開發人員工具

gitter 卸載by Gitter通過吉特 最佳Gitter渠道&#xff1a;開發人員工具 (Best Gitter channels: Developer Tools) Developer tools have become essential to any kind of serious software development, also in the open source setting. They can ease the daily develop…

java 過濾腳本_我寫的得到天氣的Java代碼,其中有過濾腳本和過濾HTMLtag的函數。...

public class WeatherFilter{private String html;private String target"http://weather.news.sohu.com/query.php?city北京";public WeatherFilter()throws Exception{this(null);}public WeatherFilter(String targetIn)throws Exception{if(targetIn!null)this.…

【懶癌發作】收集各種懶癌發作時用程序寫作業的程序

updata:20170621 好的&#xff0c;已經是準高一了&#xff0c;現在看起來太蠢了。。。 -------------------------------------------------------------------------------------- 要真正的運用&#xff0c;程序一定是要來解決實際問題的——比如作業&#xff08;懶就直說&…

50歐姆線設計 高頻pcb_硬件設計基礎100問(三)

硬件基礎知識問答今天依舊是節前知識儲備哦&#xff0c;jacky大神整理的硬件基礎知識很細致&#xff0c;第三彈學起來&#xff01;01 1、晶體管基本放大電路有共射、共集、共基三種接法&#xff0c;請簡述這三種基本放大電路的特點。共射&#xff1a;共射放大電路具有放大電流和…

如何正確實現 Java 中的 HashCode

相等 和 Hash Code 從一般角度來看&#xff0c;Equality 是不錯的&#xff0c;但是 hash code 更則具技巧性。如果我們在 hash code上多下點功夫&#xff0c;我們就能了解到 hash code 就是用在細微處去提升性能的。 大部分的數據結構使用equals去檢查是否他們包含一個元素。例…

一億小目標成就_成就卓越的一種方式:自我選擇

一億小目標成就by Prosper Otemuyiwa通過Prosper Otemuyiwa 成就卓越的一種方式&#xff1a;自我選擇 (One way to Greatness: Pick Yourself) I’ve heard many people say this: “I want to be great”, but most people only just have wild thoughts & imaginations …

java操作文件愛女_Java的IO操作---File類

目標1)掌握File類作用2)可以使用file類中方法對文件進行讀寫操作。File類唯一與文件有關的類。使用file類可進行創建或刪除操作&#xff0c;要想使用File類&#xff0c;首先觀察File類的構造方法。public File(String pathname);實例化File類的時候&#xff0c;必須設置好路徑。…

openssl創建私有ca

openssl創建私有ca1.ssl大概內容PKI&#xff1a;公鑰基礎設施結構CA&#xff1a;證書權威機構&#xff0c;PKI的核心CRL&#xff1a;證書吊銷列表,使用證書之前需要檢測證書有效性證書存儲格式常見的X509格式包含內容 公鑰有效期限證書的合法擁有人證書該如何使用CA的信息CA簽名…

查詢顯示注釋_SQL的簡單查詢

1.基本的查詢語句-- *代表查詢所有的列select * from <表名>;distinct表示列中不包括重復的值&#xff0c;例如select distinct 姓名&#xff1b;如果是select distinct 姓名,學號&#xff1b;則表示姓名和學號都重復的值才會顯示。as為列設定別名&#xff0c;例如select…

【AC自動機】【數據結構】【樹】【Aho-Corasick automation】AC自動機理解(入門)...

引入 我們首先提出一個問題&#xff1a; 給出n個串每個串的長度≤m 然后給出一個長度為k的串&#xff0c;詢問前n個串中有多少個是匹配成了的 暴力搜索 這題不是sb題目嗎&#xff1f; 隨隨便便O(kmn)跑過。 。。。。 n10000 m50 k1000000 。。。。 好吧——我們用AC自動…

域控dns無法解析域控_域注冊商,DNS和托管

域控dns無法解析域控by ????? ??????????由??????????????? 域名注冊商&#xff0c;DNS和托管 (Domain registrars, DNS, and hosting) 如何正確設置網站 (How to set up your website the right way) It took me a while to set up the infras…

java 棧空間_初學JAVA——棧空間堆空間的理解

1.Person pangzi; //這是在“開拓空間”于棧空間pangzinew Person(); //這是賦值于堆空間上兩步就是在做與空間對應的事。2.值類型直接存入棧空間&#xff0c;如AF&#xff0c;引用類型存入堆空間&#xff0c;在棧空間存有“索引地址”&#xff0c;如當需要B時&#xff0…

二進制安裝kubernetes v1.11.2 (第八章 kube-apiserver 部署)

繼續上一章部署。 八、部署kube-apiserver組件 使用第七章的haproxy和keepalived部署的高可用集群提供的VIP&#xff1a;${MASTER_VIP} 8.1 下載二進制文件&#xff0c;參考 第三章  8.2 創建 kubernetes 證書和私鑰 source /opt/k8s/bin/environment.sh cat > kubernetes-…

element手機驗證格式_vue封裝 element-ui form表單驗證 正則匹配手機號 自定義校驗表格內容...

效果image.png在methods中//檢查手機號isCellPhone(val) {if (!/^1(3|4|5|6|7|8)\d{9}$/.test(val)) {return false;} else {return true;}}在template中v-model"forgetForm.phone"type"text"auto-complete"off"placeholder"請輸入你的手機…

multi-mechanize error: can not find test script: v_user.py問題

從github上下載&#xff0c;安裝multi-mechanize&#xff0c;新建工程&#xff0c;運行工程報錯。 環境&#xff1a; win7-x64, python 2.7 multi-mechanize can not find test script: v_user.py 查看了github上的工程&#xff0c;項目無人維護&#xff0c;這個問題2016年11月…

@RequestMapping 用法詳解之地址映射

引言&#xff1a; 前段時間項目中用到了RESTful模式來開發程序&#xff0c;但是當用POST、PUT模式提交數據時&#xff0c;發現服務器端接受不到提交的數據&#xff08;服務器端參數綁定 沒有加任何注解&#xff09;&#xff0c;查看了提交方式為application/json&#xff0c; 而…