📄 sharedsocket.java
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase// Copyright (C) 2004 The jTDS Project//// This library is free software; you can redistribute it and/or// modify it under the terms of the GNU Lesser General Public// License as published by the Free Software Foundation; either// version 2.1 of the License, or (at your option) any later version.//// This library is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU// Lesser General Public License for more details.//// You should have received a copy of the GNU Lesser General Public// License along with this library; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA//package net.sourceforge.jtds.jdbc;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.EOFException;import java.io.File;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.io.RandomAccessFile;import java.net.Socket;import java.net.SocketException;import java.net.UnknownHostException;import java.util.ArrayList;import java.util.LinkedList;import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import net.sourceforge.jtds.ssl.SocketFactories;import net.sourceforge.jtds.util.Logger;/** * This class mananges the physical connection to the SQL Server and * serialises its use amongst a number of virtual sockets. * This allows one physical connection to service a number of concurrent * statements. * <p> * Constraints and assumptions: * <ol> * <li>Callers will not attempt to read from the server without issuing a request first. * <li>The end of a server reply can be identified as byte 2 of the header is non zero. * </ol> * </p> * Comments: * <ol> * <li>This code will discard unread server data if a new request is issued. * Currently the higher levels of the driver attempt to do this but may be * we can just rely on this code instead. * <li>A cancel can be issued by a caller only if the server is currently sending * data for the caller otherwise the cancel is ignored. * <li>Cancel packets on their own are returned as extra records appended to the * previous packet so that the TdsCore module can process them. * </ol> * This version of the class will start to cache results to disk once a predetermined * maximum buffer memory threshold has been passed. Small result sets that will fit * within a specified limit (default 8 packets) will continue to be held in memory * (even if the memory threshold has been passed) in the interests of efficiency. * * @author Mike Hutchinson. * @version $Id: SharedSocket.java,v 1.33 2005/05/20 12:02:25 alin_sinpalean Exp $ */class SharedSocket { /** * This inner class contains the state information for the virtual socket. */ private static class VirtualSocket { /** * The stream ID of the stream objects owning this state. */ final int owner; /** * Memory resident packet queue. */ final LinkedList pktQueue; /** * True to discard network data. */ boolean flushInput; /** * True if output is complete TDS packet. */ boolean complete; /** * File object for disk packet queue. */ File queueFile; /** * I/O Stream for disk packet queue. */ RandomAccessFile diskQueue; /** * Number of packets cached to disk. */ int pktsOnDisk; /** * Total of input packets in memory or disk. */ int inputPkts; /** * Constuct object to hold state information for each caller. * @param streamId the Response/Request stream id. */ VirtualSocket(int streamId) { this.owner = streamId; this.pktQueue = new LinkedList(); this.flushInput = false; this.complete = false; this.queueFile = null; this.diskQueue = null; this.pktsOnDisk = 0; this.inputPkts = 0; } } /** * The shared network socket. */ private Socket socket; /** * The shared SSL network socket; */ private Socket sslSocket; /** * Output stream for network socket. */ private DataOutputStream out; /** * Input stream for network socket. */ private DataInputStream in; /** * Current maxium input buffer size. */ private int maxBufSize = TdsCore.MIN_PKT_SIZE; /** * Table of stream objects sharing this socket. */ private final ArrayList socketTable = new ArrayList(); /** * The Stream ID of the object that is expecting a response from the server. */ private int responseOwner = -1; /** * Buffer for packet header. */ private final byte hdrBuf[] = new byte[TDS_HDR_LEN]; /** * Total memory usage in all instances of the driver * NB. Access to this field should probably be synchronized * but in practice lost updates will not matter much and I think * all VMs tend to do atomic saves to integer variables. */ private static int globalMemUsage; /** * Peak memory usage for debug purposes. */ private static int peakMemUsage; /** * Max memory limit to use for buffers. * Only when this limit is exceeded will the driver * start caching to disk. */ private static int memoryBudget = 100000; // 100K /** * Minimum number of packets that will be cached in memory * before the driver tries to write to disk even if * memoryBudget has been exceeded. */ private static int minMemPkts = 8; /** * Global flag to indicate that security constraints mean * that attempts to create work files will fail. */ private static boolean securityViolation; /** * Tds protocol version */ private int tdsVersion; /** * The servertype one of Driver.SQLSERVER or Driver.SYBASE */ protected final int serverType; /** * The character set to use for converting strings to/from bytes. */ private CharsetInfo charsetInfo; /** * Count of packets received. */ private int packetCount; /** * The server host name. */ private String host; /** * The server port number. */ private int port; /** * A cancel packet is pending. */ private boolean cancelPending; /** * Synchronization monitor for {@link #cancelPending} and * {@link #responseOwner}. */ private Object cancelMonitor = new Object(); /** * Buffer for TDS_DONE packets */ private byte doneBuffer[] = new byte[TDS_DONE_LEN]; /** * TDS done token. */ private static final int TDS_DONE_TOKEN = 253; /** * Length of a TDS_DONE token. */ private static final int TDS_DONE_LEN = 9; /** * Length of TDS packet header. */ private static final int TDS_HDR_LEN = 8; protected SharedSocket(int tdsVersion, int serverType) { this.tdsVersion = tdsVersion; this.serverType = serverType; } /** * Construct a <code>SharedSocket</code> object specifying host name and * port. * * @param host the SQL Server host name * @param port the connection port eg 1433 * @param tdsVersion the TDS protocol version * @param tcpNoDelay <code>true</code> to enable TCP_NODELAY on the * underlying socket; <code>false</code> to disable * @param timeout timeout for establishing connection, in seconds * (only used with Java 1.4+, no support in earlier * versions) * @throws IOException if socket open fails */ SharedSocket(String host, int port, int tdsVersion, int serverType, boolean tcpNoDelay, int timeout) throws IOException, UnknownHostException { this(tdsVersion, serverType); this.host = host; this.port = port; if (Driver.JDBC3) { try { // Create the Socket Constructor constructor = Socket.class.getConstructor(new Class[] {}); this.socket = (Socket) constructor.newInstance(new Object[] {}); // Create the InetSocketAddress constructor = Class.forName("java.net.InetSocketAddress") .getConstructor(new Class[] {String.class, int.class}); Object address = constructor.newInstance( new Object[] {host, new Integer(port)}); // Call Socket.connect(InetSocketAddress, int) Method connect = Socket.class.getMethod("connect", new Class[] {Class.forName("java.net.SocketAddress"), int.class}); connect.invoke(this.socket, new Object[] {address, new Integer(timeout * 1000)}); } catch (InvocationTargetException ite) { // Reflection was OK but invocation of socket.connect() // has failed. Try to report the underlying reason Throwable cause = ite.getTargetException(); if (cause instanceof IOException) { // OK was an IOException or subclass so just throw it throw (IOException) cause; } // Something else so return invocation exception anyway // (This should not normally occur) throw new IOException("Could not create socket: " + cause); } catch (Exception e) { // Reflection has failed for some reason e.g. security so // try to create a socket in the old way. this.socket = new Socket(host, port); } } else { this.socket = new Socket(host, port); } setOut(new DataOutputStream(socket.getOutputStream())); setIn(new DataInputStream(socket.getInputStream())); this.socket.setTcpNoDelay(tcpNoDelay); } /** * Enable TLS encryption by creating a TLS socket over the * existing TCP/IP network socket. * * @param ssl the SSL URL property value * @throws IOException if an I/O error occurs */ void enableEncryption(String ssl) throws IOException { Logger.println("Enabling TLS encryption"); sslSocket = SocketFactories.getSocketFactory(ssl, socket) .createSocket(getHost(), getPort()); setOut(new DataOutputStream(sslSocket.getOutputStream())); setIn(new DataInputStream(sslSocket.getInputStream())); } /** * Disable TLS encryption and switch back to raw TCP/IP socket. * * @throws IOException if an I/O error occurs */ void disableEncryption() throws IOException { Logger.println("Disabling TLS encryption"); sslSocket.close(); sslSocket = null; setOut(new DataOutputStream(socket.getOutputStream())); setIn(new DataInputStream(socket.getInputStream())); } /** * Set the character set descriptor to be used to translate byte arrays to * or from Strings. * * @param charsetInfo the character set descriptor */ void setCharsetInfo(CharsetInfo charsetInfo) { this.charsetInfo = charsetInfo; } /**
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -