应用场合:
表现层用JSF框架,开发一个网盘,我必须要与集群服务器进行通信之后在将服务器的返回结果呈现给客户端.
考虑到客户端并发及为了减小服务器端开销,我使用了Socket连接池的思想.
对应每一个客户端请求就从池中取出一个socket,发送HTTP请求到集群服务器端,接收服务器端HTTP响应.
其他的请求操作都是完全正确的,但是在上传文件时,服务器端总是报400 bad request错误.
集群服务器开发的大哥告诉我这是我这边发送的请求不正确导致的,但是我查找了好久实在不明白错在什么地方.
贴一段代码,还望各位指点哈,多谢!
//
import java.net.Socket;
import java.net.SocketException;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import cn.com.loongstore.util.IOUtils;
/**
* socket连接池
* @author Administrator
*
*/
public class SocketPool {
private Logger logger = Logger.getLogger(SocketPool.class);
public static int MIN_CONNECTIONS = 0; // 最大socket连接数
public static int MAX_CONNECTIONS = 0; // 最小socket连接数
private static SocketPool instance = null;
private Lock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private List<Socket> socketList = null;
private SocketPool() {
//
}
public static SocketPool getInstance() {
if(instance == null) {
instance = new SocketPool();
}
return instance;
}
public void init() {
socketList = new LinkedList<Socket>();
int minConnections = LdsConfig.getMinConnections();
int maxConnections = LdsConfig.getMaxConnections();
for(int i=minConnections;i<=maxConnections;i++) {
socketList.add(socketList.size(), produceSocket());
}
logger.info("Socket pool initialized size: "+socketList.size());
}
/**
* 从Socket池中获取一个可用的Socket
* @return
*/
public Socket getSocket() {
Socket socket = null;
lock.lock();
try {
while(socketList.isEmpty()) {
System.out.println(Thread.currentThread().getName()+" wait getting socket...");
condition.await();
}
socket = socketList.remove(0);
}catch(InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
//socket = produceSocket();
return socket;
}
/**
* 使用完Socket之后将Socket归还到Socket池中
* @param socket
*/
public void restoreSocket(Socket socket) {
if(socket == null) {
return;
}
lock.lock();
try {
socketList.add(socketList.size(), socket);
condition.signal();
}finally {
lock.unlock();
}
}
/**
* 关闭Socket池
*/
public void shutDownSocketPool() {
for(Socket socket:socketList) {
IOUtils.closeSocket(socket);
socket = null;
}
}
/**
* 获取Socket池大小
* @return
*/
public int getPoolSize() {
int size = 0;
lock.lock();
try {
size = socketList.size();
}finally {
lock.unlock();
}
return size;
}
/**
* 生成一个新的Socket对象
* @return
*/
public Socket produceSocket() {
Socket socket = new Socket();
try {
socket.setReuseAddress(true);
socket.setKeepAlive(true);
socket.setSoTimeout(10*1000);
} catch (SocketException e) {
e.printStackTrace();
}
return socket;
}
}
// 发送HTTP请求并接收HTTP响应的函数
// 先读HTTP消息头,再读HTTP消息体
protected HttpPacket sendAndReceived(HttpPacket packet) throws IOException {
HttpPacket response = null;
DataOutputStream dos = null;
DataInputStream dis = null;
if(packet == null || packet.getHeader() == null) {
return response;
}
System.out.println("Send http request ...");
dos = new DataOutputStream(socket.getOutputStream());
dos.write(packet.getHeader().getBytes("UTF-8"));
if(!packet.isEmptyBody()) {
dos.write(packet.getBody());
}
dos.flush();
System.out.println("Send http request complete.");
System.out.println("Receive http reponse header ...");
dis = new DataInputStream(socket.getInputStream());
int readLength = 0;
String header = null;
byte[] buffer = new byte[512]; // 预读缓冲区
byte[] sepBytes = new byte[4]; // 存放消息头与消息体的分隔符\r\n\r\n
byte[] headerBytes = null; // 消息头数据
byte[] headerBodyBytes = null; // 在读取消息头时读到的部分消息体数据
int contentLength = 0; // 消息体数据长度
int k = 1;
int index = 0; // 分隔符\r\n\r\n在缓冲区中距离起始位置的偏移量
readLength = dis.read(buffer);// 读取HTTP响应头时一次性读取512个字节,跟响应实体"多退少补"
if(readLength < 0) { // 连接关闭,请求重发
throw new IOException("Socket have closed");
}
for(int i=0;i<readLength;i++) {
sepBytes[(k-1)%4] = buffer[i];
k++;
if(sepBytes[0] == 13 && sepBytes[1] == 10 && sepBytes[2] == 13 && sepBytes[3] == 10) {
index = i;
break;
}else if(sepBytes[3] == 13 && sepBytes[0] == 10 && sepBytes[1] == 13 && sepBytes[2] == 10) {
index = i;
break;
}
}
if(index > 0) {
headerBytes = new byte[index+1];
headerBodyBytes = new byte[readLength-index-1];
System.arraycopy(buffer, 0, headerBytes, 0, (index+1));
System.arraycopy(buffer, (index+1), headerBodyBytes, 0, (readLength-index-1));
}else {
headerBytes = buffer;
}
header = new String(headerBytes);
System.out.println("Receive http response header complete.");
System.out.println("Receive http response boy ...");
readLength = 0;
byte[] body = null;
contentLength = proParser.parseContentLength(header);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
if(headerBodyBytes != null) {
bos.write(headerBodyBytes); // 保存之前读取到的部分响应实体
readLength = headerBodyBytes.length;
}
if(contentLength > readLength) {
if(contentLength > 1024) {
body = new byte[1024];
}else {
body = new byte[contentLength];
}
while(readLength < contentLength) {
int length = dis.read(body);
if(length > 0) {
bos.write(body,0,length);
readLength += length;
}else {
break;
}
}
}
body = bos.toByteArray();
bos = null;
System.out.println("Receive http response body complete.");
System.out.println(header);
System.out.println(body==null?"http response body is empty.":new String(body));
response = new HttpPacket(request.getName(), header,body);
return response;
}
问题补充:greenmartian 写道
不明白为什么要池化socket,连接如果断了,不抛弃留着有什么意义呢
之所以池化socket,是为了重用连接,因为与服务器端建立的实际上是长连接,不是通信完毕就立刻关闭的。倘若面对浏览器的每一操作请求都new一个新的socket是不是开销就大了啊!
相关推荐
总的来说,Java Socket连接池是解决高并发网络环境下性能问题的有效手段。通过合理的设计和管理,不仅可以减少系统资源的浪费,还能提升应用的整体响应速度和稳定性。在选择和使用Socket连接池时,应根据项目需求和...
为了解决这个问题,引入了Socket连接池的概念。 连接池的工作机制如下: 1. 初始化:在服务器启动时,预先创建一定数量的Socket连接,放入池中。 2. 借用与归还:当客户端请求到来时,服务器从连接池中取出一个已...
在Java中,可以使用Apache Commons Pool库来实现Socket连接池,或者自定义一个基于LinkedList或ConcurrentHashMap的数据结构来管理和维护连接。同时,可以结合JMX(Java Management Extensions)进行监控,查看连接...
为此,本文档介绍了一种解决这些问题的方法——Socket连接池技术,并通过具体实例来展示如何在客户端和服务端之间实现这一技术。 #### 二、Socket连接的基础概念 在深入探讨Socket连接池之前,我们需要了解两种...
一个java socket连接池的典型实例 SocketClient,客户端测试类 SocketAdapter继承Socket类,重新封装socket类 SocketConnectionPool,连接池管理类 StartupSocketServer,socket服务器端的主线程,负责监听端口,当有...
解决线程太多导致Java Socket连接池出现的问题 线程太多对Socket连接池的影响 在Java应用程序中,线程太多可能会导致Socket连接池出现问题。这是因为每个线程都需要占用一定的系统资源,如内存、CPU、Socket 等。...
本实例探讨的是如何利用Java中的Socket对象以及线程连接池技术,特别是`GenericObjectPool`来提高程序性能和效率。首先,我们需要理解Socket和线程连接池的基本概念。 **Socket**: Socket是网络通信的一种接口,它...
Socket连接分为两种类型:长连接和短连接。这两种连接方式各有特点,适用于不同的应用场景。 **1. 短连接(Short Connection)** 短连接通常用于一次性、非持久性的通信,如HTTP协议就是典型的短连接。在短连接中...
通过阅读`PoolConnectionHandler.java`、`SocketServerPool.java`和`SocketClient.java`的代码,我们可以深入了解BIO Socket连接池的实现细节,包括线程安全、连接分配策略、连接状态检测等技术。同时,这也为我们...
Socket连接池和消息队列是两种在分布式系统和网络编程中常见的技术,它们在提高系统性能、优化资源管理和实现异步通信方面起着至关重要的作用。在这个“socket连接池加消息队列源码”中,我们可以看到作者创建了一个...
为了解决这个问题,引入了Socket池(或Socket连接池)。Socket池是一种管理机制,它维护着一组预先创建的、可重用的Socket连接。当应用程序需要建立新的网络连接时,不是直接创建新的Socket,而是从池中获取已经存在...
Java的`java.sql.DriverManager`就提供了连接池的支持,但需要第三方库如Apache Commons Pool来实现Socket连接池。 9. **SSL/TLS安全通信** - Java提供`SSLSocket`和`SSLServerSocket`类支持安全的HTTPS通信,利用...
本实例探讨的是如何利用Java的Socket实现TCP(Transmission Control Protocol)协议下的多线程通讯,允许一个服务端同时处理多个客户端的连接请求。 首先,TCP是一种面向连接的、可靠的、基于字节流的传输层通信...
这个类可能负责管理和维护Socket连接池,它可能包含以下功能: 1. 创建Socket连接:根据服务器地址和端口号创建Socket实例。 2. 连接管理:保存和检索已建立的Socket连接,避免频繁创建和销毁。 3. 连接池维护:...
在Java中,`java.sql.ConnectionPoolDataSource`和`javax.sql.PooledConnection`接口用于数据库连接池,而对于Socket连接池,开发者可以使用第三方库如Apache Commons Pool或HikariCP。连接池的主要优点是减少资源...
BoneCP是一款高效、轻量级的Java数据库连接池实现,它的源码分析对于我们理解数据库连接池的工作原理,优化数据库性能以及进行二次开发具有重要意义。 首先,我们需要了解数据库连接池的基本概念。数据库连接池是...
例如,可能有一个预封装好的`SocketUtil`类,包含了建立Socket连接、发送消息、接收消息等常用方法。这样的设计使得开发者在处理Socket通信时只需调用几个简单的API,而无需关心底层的实现细节。 此外,考虑到文件...
Java网络编程是构建分布式应用程序的关键技术,特别是在服务器端开发中,多线程和连接池是其核心概念。本文将深入探讨这两个主题,并结合文件传输的实际应用进行讲解。 首先,我们来理解多线程。在Java中,多线程...
为了实现这些,服务器需要维护一个用户连接池,记录每个Socket连接对应的用户信息,以便正确地路由消息。 在好友列表功能中,用户可以添加、删除或查找好友。这些操作都需要通过Socket通信在客户端和服务器之间传递...
以下是一个简单的Java示例,展示了如何创建MongoDB连接并使用连接池进行基本的操作: ```java Mongo mongo = new Mongo("localhost", 27017); // 创建Mongo对象 DB db = mongo.getDB("mydb"); // 获取数据库 ...