Phenomenon
The project uses the spring batch framework. Multiple slices use jsch to obtain SFTP connections to read files and report errors
In fact, it is multithreading, using jsch to obtain the session connection and report an error
com.jcraft.jsch.JSchException: Session.connect: java.net.SocketException: Connection reset
Jsch version
version=0.1.54
groupId=com.jcraft
artifactId=jsch
reason
Various reasons have been found on the Internet. Some say the number of SSH terminal connections is limited, and some say there is a TCP connection problem. The final reason has not been found yet. Please inform us in the comment area
Reappearance
public static Session getSshSession(String sftpHost, int sftpPort, String userName, String password) {
JSch jsch = new JSch();
// GET sshSession
Session sshSession = null;
try {
sshSession = jsch.getSession(userName, sftpHost, sftpPort);
} catch (JSchException e) {
e.printStackTrace();
}
if (StringUtils.isNotBlank(password)) {
sshSession.setPassword(password);
}
Properties sshConfig = new Properties();
sshConfig.put("StrictHostKeyChecking", "no");
sshSession.setConfig(sshConfig);
return sshSession;
}
static void test() {
for (int i = 1; i < 50; i++) {
new Thread(() -> {
Session sshSession = getSshSession("*.*.*.*", 22, "root", "***");
try {
Thread.sleep(100);
sshSession.connect();
} catch (Exception e) {
e.printStackTrace();
} finally {
sshSession.disconnect();
}
}).start();
}
}
Solution:
Create a channel pool using apache.commons.pool2
Since the SFTP configuration of the project is dynamic and not fixed, the following code is not encapsulated as a spring boot managed bean
Connection pool configuration:
public class ConnPoolConfig extends GenericObjectPoolConfig {
public ConnPoolConfig() {
// https://blog.csdn.net/weixin_42340670/article/details/108431381
// The minimum number of free objects in the object pool should be
setMinIdle(4);
// The maximum capacity of the pool. The maximum number of objects to be stored in the pool
setMaxTotal(10);
// Check the validity of an object when it is borrowed from the pool.
setTestOnBorrow(true);
// How often the recycler thread performs idle object recovery (polling interval, in milliseconds)
setTimeBetweenEvictionRunsMillis(60 * 60000);
// Whether to verify the validity of the object when the recycler is scanning for idle objects.
// If an object has not reached the specified threshold of idle time, and if testWhileIdle is configured to true
// then it checks if the object is still valid, and if the object's resources have expired (e.g., the connection is disconnected), then he can be recycled.
setTestWhileIdle(true);
}
}
Connection pool factory:
public class ConnPoolFactory extends BasePooledObjectFactory<ChannelSftp> {
private String host;
private Integer port;
private String userName;
private String password;
private final String strictHostKeyChecking = "no";
public ConnPoolFactory(String host, Integer port, String userName, String password) {
this.host = host;
this.port = port;
this.userName = userName;
this.password = password;
}
@Override
public ChannelSftp create() throws Exception {
JSch jsch = new JSch();
Session session = jsch.getSession(userName, host, port);
session.setPassword(password);
Properties config = new Properties();
config.put("StrictHostKeyChecking", strictHostKeyChecking);
session.setConfig(config);
session.connect();
ChannelSftp channel = (ChannelSftp) session.openChannel("sftp");
channel.connect();
return channel;
}
@Override
public PooledObject<ChannelSftp> wrap(ChannelSftp obj) {
return new DefaultPooledObject<>(obj);
}
// https://segmentfault.com/a/1190000003920723
// Destroy the object, if the object pool detects that an "object" idle timeout,
// or if the operator detects that the "object" is no longer valid when "returning the object" to the object pool, then this will result in "object destruction";
// The design of the "destroy object" operation is far different, but it must be clear:
// When this method is called, the life of the "object" must end. If object is a thread, then the thread must exit at this point;
// If object is a socket operation, then the socket must be closed;
// If object is a file stream operation, then "data flush" is done and closed normally.
@Override
public void destroyObject(PooledObject<ChannelSftp> pooledObject) throws Exception {
Channel channel = pooledObject.getObject();
Session session = channel.getSession();
channel.disconnect();
session.disconnect();
}
// Check if the object is "valid";
// The Pool cannot hold invalid "objects", so the "background detection thread" will periodically check the validity of the "objects" in the Pool,
// If the object is invalid, it will be removed from the Pool and destroyed;
// In addition, when the caller gets an "object" from the Pool, it also checks the validity of the "object" to make sure that no "invalid" objects can be output to the caller;
// When the caller returns the "object" to the Pool after use, the validity of the object is still checked. By validity,
// The validity of the object is whether the object is in the expected state and can be used directly by the caller;
// If the object is a socket, then its validity is whether the socket's channel is open/blocking timeout, etc.
@Override
public boolean validateObject(PooledObject<ChannelSftp> pooledObject) {
return pooledObject.getObject().isConnected();
}
// "Activate" an object, an additional "activation" action when the Pool decides to remove an object for delivery to the caller,
// For example, you can "reset" the list of parameters in the activateObject method to make it feel like a "newly created" object when the caller uses it;
// If the object is a thread, you can reset the "thread break flag" in the "activate" operation, or wake up the thread from blocking, etc;
// If the object is a socket, then you can refresh the channel in the "activate" operation,
// or rebuild the link to the socket (if the socket is unexpectedly closed), etc.
@Override
public void activateObject(PooledObject<ChannelSftp> pooledObject) throws Exception {
ChannelSftp channelSftp = pooledObject.getObject();
Session session = channelSftp.getSession();
if (!session.isConnected()) {
session.connect();
channelSftp.connect();
}
}
// "Passivate" the object, when the caller "returns the object", the Pool will "passivate the object".
// The implication of passivate is that the "object" needs a "rest" for a while.
// If the object is a socket, then you can passivateObject to clear the buffer and block the socket;
// If the object is a thread, you can sleep the thread or wait for an object in the thread during the "passivate" operation.
// Note that the methods activateObject and passivateObject need to correspond to each other to avoid deadlocks or confusion about the state of the "object".
@Override
public void passivateObject(PooledObject<ChannelSftp> pooledObject) throws Exception {
}
}
Connection pool:
public class ConnPool extends GenericObjectPool<ChannelSftp> {
private static final Map<String, ConnPool> MAP = new ConcurrentHashMap<>();
private ConnPool(String host, Integer port, String userName, String password) {
super(new ConnPoolFactory(host, port, userName, password), new ConnPoolConfig());
}
public static ConnPool getConnPool(String host, Integer port, String userName, String password) {
String key = host + ":" + port;
ConnPool connPool = MAP.get(key);
if (connPool == null) {
synchronized (ConnPool.class) {
connPool = MAP.get(key);
if (connPool == null) {
connPool = new ConnPool(host, port, userName, password);
MAP.put(key, connPool);
}
}
}
return connPool;
}
}
The connection pool supports the establishment of different pools for different remote IP
Tool class encapsulation:
public static ChannelSftp borrowChannel(ConnectionConfig connCfg) {
ConnPool connPool = ConnPool.getConnPool(connCfg.getHost(), connCfg.getPort(), connCfg.getUserName(),
connCfg.getPassword());
try {
return connPool.borrowObject();
} catch (Exception e) {
logger.error("Get channelSftp from pool fail", e);
}
}
public static void returnChannel(ConnectionConfig connCfg, ChannelSftp channel) {
ConnPool connPool = ConnPool.getConnPool(connCfg.getHost(), connCfg.getPort(), connCfg.getUserName(),
connCfg.getPassword());
try {
connPool.returnObject(channel);
} catch (Exception e) {
logger.error("Return channelSftp to pool fail", e);
}
}
No problem with the test:
static void test2() {
AtomicInteger j = new AtomicInteger(0);
for (int i = 0; i < 50; i++) {
new Thread(() -> {
ConnPool connPool = ConnPool.getConnPool("*", 22, "root", "*");
System.out.println(connPool + "--" + j.getAndIncrement());
ChannelSftp channelSftp = null;
try {
channelSftp = connPool.borrowObject();
} catch (Exception e) {
e.printStackTrace();
} finally {
connPool.returnObject(channelSftp);
}
}).start();
}
}
Read More:
- java.net.SocketException: software caused connection abort: socket write error resolution (selenium)
- [Solved] Hadoop failed on connection exception: java.net.ConnectException: Connection refused
- [Solved] failed on connection exception: java.net.ConnectException: Connection denied
- [Solved] hadoop Error: 9000 failed on connection exception java.net.ConnectException Denied to Access
- [Solved] ClientAbortException: java.io.IOException: Connection reset by peer
- [Solved] Unable to connect to a as user root com.jcraft.jsch.JSchException: Auth failUnable to connect
- Monitoring session to determine whether the user is online or not
- [Solved] port (127.0.0.1:64444): java.net.SocketException “Interrupted function call: accept failed“
- The java springboot websocket service server actively closes the connection and causes java.io.EOFException to be thrown
- [Solved] Tomcat configurate HTTPS error: java.net.SocketException: Permission denied
- [Solved] JAVA Connect rabbitMQ Error: An unexpected connection driver error occured
- Doris streamload task reported an error connection reset [How to Solve]
- Build a mybatis and it will appear session.selectOne Method error
- Tensorflow Error raise RuntimeError(‘The Session graph is empty. Add operations to the ‘ RuntimeError:
- [Solved] Docker-maven-plugin Build Mirror Error: failed: Connection refused: connect
- [Solved] Eclipse Update Error: An error occurred while uninstalling session context was…
- [Solved] Springboot Project Error: Mail server connection failed;
- How to Solve JDBC connection error in spring MVC integration
- Configuration of springboot + Druid connection pool
- [Solved] Jedis connect and operate Redis error: Failed to create socket和connect timed out