java socket连接池 实现

公司目前要求做一个能够并发负载很高的webservice,使用了市面流行的框架例如cxf,axis等效果都不理想,即利用jmeter压力测试时,tps浮动较大,分析原因为每次请求webservice接口都会建立一个socket,如果超过最大端口数,那么就要等待原来的socket释放才能新建socket,所以想到了用socket连接池。

即利用socket发送http请求,可以说是实现了http的长连接

本人也是第一次写socket的连接池,所以把代码发出来,希望有共同研究方向的同行能帮我指正不足之处。

1.池成员数据结构

package com.socket.pool;

import java.net.Socket;

public class SocketMember {
//socket对象
private Socket socket;
//是否正被使用
private boolean inUse=false;
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
public boolean isInUse() {
return inUse;
}
public void setInUse(boolean inUse) {
this.inUse = inUse;
}

}



2.socket连接池类

package com.socket.pool;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class SocketPool {
//host
private String host;
//port
private int port;
//初始化socket数
private int initSize=5;
//最大socket数
private int maxSize=5;
//socket对象容器
private List<SocketMember> socketContainer=new ArrayList<SocketMember>(initSize);

public SocketPool(String host,int port){
this.host=host;
this.port=port;
buildPoolPart();
}
//给socket容器增加成员 一次增加initSize个成员
private List<SocketMember> buildPoolPart(){
List<SocketMember> poolPart=new ArrayList<SocketMember>(initSize);
SocketMember member=null;
for(int i=0;i<initSize;i++){
Socket socket=null;
try {
socket = new Socket(host, port);
}
catch (IOException e) {
e.printStackTrace();
}
member=new SocketMember();
member.setSocket(socket);
poolPart.add(member);
}
if(poolPart.size()>0){
socketContainer.addAll(poolPart);
}else{
try {
throw new Exception("扩大池容量失败");
}
catch (Exception e) {
e.printStackTrace();
}
}
return poolPart;
}
//获取池中空闲的socket 已做线程安全处理
public SocketMember getMemberFromPool(){
SocketMember member=null;
//同步块获取对象
synchronized (this) {
for(int i=0;i<socketContainer.size();i++){
SocketMember memberInPool=socketContainer.get(i);
boolean inUse=memberInPool.isInUse();
if(inUse==false){
memberInPool.setInUse(true);
member=memberInPool;
System.out.println("成功获取对象,在池中的位置为:"+i);
break;
}
}
//pool中没有空余
if(member==null){
if(socketContainer.size()<maxSize){
//扩大池容量
List<SocketMember> newPoolPart=buildPoolPart();
//从新扩大的部分拿出一个来用
member=newPoolPart.get(0);
member.setInUse(true);
System.out.println("成功扩大池容量,当前size为:"+socketContainer.size());
}
}
}
//如果超过最大容量 等待 递归
if(member==null){
try {
Thread.sleep(1000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
member=getMemberFromPool();
}
return member;

}

public int getInitSize() {
return initSize;
}

public void setInitSize(int initSize) {
this.initSize = initSize;
}

public int getMaxSize() {
return maxSize;
}

public void setMaxSize(int maxSize) {
this.maxSize = maxSize;
}
public List<SocketMember> getSocketContainer() {
return socketContainer;
}
public String getHost() {
return host;
}
public int getPort() {
return port;
}


}


3.守护线程

package com.socket.pool;

import java.io.IOException;
import java.net.Socket;
import java.util.List;
/**
* 保持池中的socket一直存活 每隔一段时间遍历池检查socket对象 如果已连接那么发送心跳包 如果已断开 那么重新建立连接
* @ClassName: DaemonThread
* @Description: TODO
* @Copyright: Copyright (c) 2016
* @Company: 深圳市梦网科技股份有限公司
* @author hxq
* @date 2016-8-1 上午10:26:43
* @version V1.0
*/
public class DaemonThread implements Runnable{
private SocketPool pool;
public DaemonThread(SocketPool pool){
this.pool=pool;
}
public void run() {
List<SocketMember> container=pool.getSocketContainer();
while(true){
//10秒检查一次
try {
Thread.sleep(10000);
}
catch (InterruptedException e) {
e.printStackTrace();
}
//遍历检查是否连接
for(int i=0;i<container.size();i++){
SocketMember member=container.get(i);
Socket socket=member.getSocket();
//给此socket加锁
synchronized (socket) {
if(!member.isInUse()){

if(socket.isConnected()){
//如果连接发送心跳包
KeepAliveExcutor excutor=new KeepAliveExcutor(member);
excutor.request();

}else{
//如果失败重新建立socket
try {
socket=new Socket(pool.getHost(), pool.getPort());
member.setSocket(socket);
}
catch (IOException e) {
e.printStackTrace();
}
System.out.println(socket.getLocalPort()+" 断线重连");
}
}
}
//System.out.println(socket.getLocalPort()+" 状态"+socket.isConnected());
}
}

}

}
/**
* 发送心跳包的executor
* @ClassName: KeepAliveExcutor
* @Description: TODO
* @Copyright: Copyright (c) 2016
* @Company: 深圳市梦网科技股份有限公司
* @author hxq
* @date 2016-8-16 下午02:16:32
* @version V1.0
*/
class KeepAliveExcutor extends AbstractSocketExecutor{

public KeepAliveExcutor(SocketMember socketMember) {
super(socketMember);
}

public void request(){
String request=SocketPoolUtil.getNowTimestamp();
super.request(request, "utf-8");
}

}




5.抽象的业务执行类 因为通过socket能发送http tcp等 所以写了一个抽象类封装公共的方法

package com.socket.pool;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


public abstract class AbstractSocketExecutor {
protected SocketMember socketMember=null;
protected Socket socket=null;
protected String host;
protected int port;

public AbstractSocketExecutor(SocketMember socketMember){
this.socketMember=socketMember;
if(socketMember!=null){
this.socket=socketMember.getSocket();
}
host=socket.getInetAddress().getHostName();
port=socket.getPort();
}
/**
* 发送请求
*
* @param request
* @param charset
*
* @Description: TODO
*/
protected void request(String request,String charset){
OutputStream out=null;
try {
out=socket.getOutputStream();
out.write(request.getBytes(charset));
}
catch (IOException e) {
e.printStackTrace();
}
}
/**
* 返回响应stream
*
* @return
*
* @Description: TODO
*/
protected InputStream getResStream(){
InputStream in=null;
try {
in = socket.getInputStream();
}
catch (IOException e) {
e.printStackTrace();
}
return in;
}
/**
* 设置状态为未使用
*
*
* @Description: TODO
*/
public void back(){
//不能关闭流,否则socket会被关闭
/* try {
socket.getOutputStream().close();
socket.getInputStream().close();
}
catch (IOException e) {
e.printStackTrace();
}*/
socketMember.setInUse(false);
}
}



6.抓取html页面的executor

package com.socket.pool;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* 发送http请求 抓取html页面内容 写的并不好 尤其是判断结束的方式 勉强能用。。。
* @ClassName: HTMLSocketExecutor
* @Description: TODO
* @Copyright: Copyright (c) 2016
* @Company: 深圳市梦网科技股份有限公司
* @author hxq
* @date 2016-8-16 下午02:02:47
* @version V1.0
*/
public class HTMLSocketExecutor extends AbstractSocketExecutor {
private String charset="UTF-8";
public HTMLSocketExecutor(SocketMember socketMember) {
super(socketMember);
}

public void setRequest(String path){
StringBuilder requestStr=new StringBuilder();
requestStr.append("GET ");
requestStr.append(path);
requestStr.append(" HTTP/1.1\r\n");
requestStr.append("User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36\r\n");
requestStr.append("Host: ");
requestStr.append(super.host);
if(port!=80){
requestStr.append(":");
requestStr.append(super.port);
}
requestStr.append("\r\n");
requestStr.append("\r\n");
super.request(requestStr.toString(), charset);
}

public String getResponse(){
StringBuilder responseResult=new StringBuilder();
BufferedReader socketReader=null;
try {
socketReader=new BufferedReader(new InputStreamReader(super.getResStream(), charset)) ;
String line=null;
char[] body=null;
int contentLength=-1;
boolean isHeadEnd=false;
while((line=socketReader.readLine())!=null){
//System.out.println(line);
responseResult.append(line);
responseResult.append("\r\n");
//检查请求头是否结束
if(!isHeadEnd){
isHeadEnd=isBlankLine(line);
if(isHeadEnd){
//立即判断是否为请求头结束 如果是且有content-length 那么立即一次读取body 结束循环
if(contentLength!=-1){
if(contentLength==0){
break;
}
//如果content-length>0 那么一次性读出响应体
body=new char[contentLength];
int bodyReadEndFlag=socketReader.read(body);
responseResult.append(body);
if(bodyReadEndFlag==-1){
break;
}

}
}
if(contentLength==-1){
//没有赋值 检查content-length并赋值
contentLength=getContentLength(line);
}
}else{
//已经读过了head结束行
if(isHTMLEnd(line)){
//如果碰到</html>
break;
}
}

}
}
catch (IOException e) {
e.printStackTrace();
}finally{
super.back();
}

return responseResult.toString();

}

private int getContentLength(String line){
int result=-1;
if(line.contains("Content-Length")){
int splitIndex=line.indexOf(":");
String length=line.substring(splitIndex+1,line.length());
length=length.trim();
result=Integer.valueOf(length);
}
return result;
}

private boolean isBlankLine(String line){
boolean result=false;
if("".equals(line)){
result=true;
}
return result;
}

private boolean isHTMLEnd(String line){
boolean result=false;
if(line.indexOf("</html>")>-1){
result=true;
}
return result;
}


}


7.工厂类 用于组装exector对象 实例化executor对象 并将socket对象注入进去 (没有抽象,只能服务HTMLSocketExecutor 。。。 先凑合着用)

package com.socket.pool;


public class SocketExcutorFactory {
/* private SocketExcutorFactory(){}
private final static SocketExcutorFactory instance=new SocketExcutorFactory();
public static SocketExcutorFactory getInstance(){
return instance;
}*/

private SocketPool pool=null;
public SocketExcutorFactory(String host,int port,boolean daemonFlag){
pool=new SocketPool(host, port);
if(daemonFlag){
//守护线程
Thread daemonThread=new Thread(new DaemonThread(pool));
daemonThread.start();
}
}
public SocketExcutorFactory(String host,int port){
this(host, port, true);
}
/**
* 实例化executor 并从池中拿出一个socket注进去
*
* @return
*
* @Description: TODO
*/
public HTMLSocketExecutor getHttpExecutor(){
HTMLSocketExecutor executor=null;
executor=new HTMLSocketExecutor(pool.getMemberFromPool());
return executor;
}


}




单线程测试类

package com.socket.pool;

public class TestPool {
public static void main(String[] args) {
String host="www.cnblogs.com";
int port=80;
SocketExcutorFactory factory=new SocketExcutorFactory(host, port,false);
HTMLSocketExecutor executor=factory.getHttpExecutor();
executor.setRequest("/zhangweizhong/p/5772330.html");
String res=executor.getResponse();
System.out.println(res);
}
}



多线程测试

package com.socket.pool;

public class ExcutorThread implements Runnable {
HTMLSocketExecutor excutor=null;
private static SocketExcutorFactory factory=new SocketExcutorFactory("www.baidu.com", 80);
public ExcutorThread(){
excutor=factory.getHttpExecutor();
}
public void run() {
excutor.setRequest("/");
String res=excutor.getResponse();
if(res.contains("302 Found")){
System.out.println(Thread.currentThread().getName()+" success");
}else{
System.out.println(Thread.currentThread().getName()+" fail");
}

}

public static void main(String[] args) {
Thread thread=null;
for(int i=0;i<10;i++){
thread=new Thread(new ExcutorThread());
thread.start();
}
}

}


源码:
  • 0
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值