--- xdocs/usermanual/component_reference.xml (revision 1416461) +++ xdocs/usermanual/component_reference.xml (working copy) @@ -1255,9 +1255,11 @@ If "Re-use connection" is selected, connections are shared between Samplers in the same thread, provided that the exact same host name string and port are used. Different hosts/port combinations will use different connections, as will different threads. + And both of "Re-use connection" and "Close connetion" are selected, the socket will be closed after running the sampler. + On the next sampler, another socket will be created. You may want to close a socket at the end of each thread loop.

If an error is detected - or "Re-use connection" is not selected - the socket is closed. - Another socket will be reopened on the next sample. + Also another socket will be reopened on the next sample.

The following properties can be used to control its operation:

@@ -1329,6 +1331,9 @@ Name or IP of TCP server Port to be used If selected, the connection is kept open. Otherwise it is closed when the data has been read. + If selected, the connection will be closed after running the sampler. + Enable/disable SO_LINGER with the specified linger time in seconds when a socket is created. If you set "SO_LINGER" value as 0, you may prevent large numbers of sockets sitting around with a TIME_WAIT status. + Byte value for end of line, set this to a value outside the range -128 to +127 to skip eol checking. You may set this in jmeter.properties file as well with eolByte property. If you set this in TCP Sampler Config and in jmeter.properties file at the same time, the setting value in the TCP Sampler Config will be used. Connect Timeout (milliseconds, 0 disables). Response Timeout (milliseconds, 0 disables). See java.net.Socket.setTcpNoDelay(). @@ -3740,6 +3745,9 @@ Name or IP of TCP server Port to be used If selected, the connection is kept open. Otherwise it is closed when the data has been read. + If selected, the connection will be closed after running the sampler. + Enable/disable SO_LINGER with the specified linger time in seconds when a socket is created. If you set "SO_LINGER" value as 0, you may prevent large numbers of sockets sitting around with a TIME_WAIT status. + Byte value for end of line, set this to a value outside the range -128 to +127 to skip eol checking. You may set this in jmeter.properties file as well with eolByte property. If you set this in TCP Sampler Config and in jmeter.properties file at the same time, the setting value in the TCP Sampler Config will be used. Connect Timeout (milliseconds, 0 disables). Response Timeout (milliseconds, 0 disables). Should the nodelay property be set? --- src/core/org/apache/jmeter/resources/messages.properties (revision 1416461) +++ src/core/org/apache/jmeter/resources/messages.properties (working copy) @@ -801,6 +801,9 @@ retobj=Return object return_code_config_box_title=Return Code Configuration reuseconnection=Re-use connection +closeconnection=Close connection +solinger=SO_LINGER: +eolbyte=End of line(EOL) byte value: revert_project=Revert revert_project?=Revert project? root=Root --- src/protocol/tcp/org/apache/jmeter/protocol/tcp/config/gui/TCPConfigGui.java (revision 1416461) +++ src/protocol/tcp/org/apache/jmeter/protocol/tcp/config/gui/TCPConfigGui.java (working copy) @@ -19,11 +19,16 @@ package org.apache.jmeter.protocol.tcp.config.gui; import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import javax.swing.BorderFactory; import javax.swing.JCheckBox; import javax.swing.JLabel; import javax.swing.JPanel; import javax.swing.JTextArea; +import javax.swing.JTextField; import org.apache.jmeter.config.ConfigTestElement; import org.apache.jmeter.config.gui.AbstractConfigGui; @@ -49,10 +54,18 @@ private JCheckBox setNoDelay; + private JCheckBox closeConnection; + + private JTextField soLinger; + + private JTextField eolByte; + private JTextArea requestData; private boolean displayName = true; + private HorizontalPanel optionsPanel; + public TCPConfigGui() { this(true); } @@ -73,14 +86,18 @@ // N.B. this will be a config element, so we cannot use the getXXX() methods classname.setText(element.getPropertyAsString(TCPSampler.CLASSNAME)); serverPanel.setServer(element.getPropertyAsString(TCPSampler.SERVER)); - // Default to original behaviour, i.e. re-use connection - reUseConnection.setSelected(element.getPropertyAsBoolean(TCPSampler.RE_USE_CONNECTION,true)); serverPanel.setPort(element.getPropertyAsString(TCPSampler.PORT)); // filename.setText(element.getPropertyAsString(TCPSampler.FILENAME)); serverPanel.setResponseTimeout(element.getPropertyAsString(TCPSampler.TIMEOUT)); serverPanel.setConnectTimeout(element.getPropertyAsString(TCPSampler.TIMEOUT_CONNECT)); - setNoDelay.setSelected(element.getPropertyAsBoolean(TCPSampler.NODELAY)); requestData.setText(element.getPropertyAsString(TCPSampler.REQUEST)); + + // Default to original behaviour, i.e. re-use connection + reUseConnection.setSelected(element.getPropertyAsBoolean(TCPSampler.RE_USE_CONNECTION, true)); + closeConnection.setSelected(element.getPropertyAsBoolean(TCPSampler.CLOSE_CONNECTION, false)); + setNoDelay.setSelected(element.getPropertyAsBoolean(TCPSampler.NODELAY)); + soLinger.setText(element.getPropertyAsString(TCPSampler.SO_LINGER)); + eolByte.setText(element.getPropertyAsString(TCPSampler.EOL_BYTE)); } @Override @@ -101,13 +118,17 @@ // N.B. this will be a config element, so we cannot use the setXXX() methods element.setProperty(TCPSampler.CLASSNAME, classname.getText(), ""); element.setProperty(TCPSampler.SERVER, serverPanel.getServer()); - element.setProperty(TCPSampler.RE_USE_CONNECTION, reUseConnection.isSelected()); element.setProperty(TCPSampler.PORT, serverPanel.getPort()); // element.setProperty(TCPSampler.FILENAME, filename.getText()); - element.setProperty(TCPSampler.NODELAY, setNoDelay.isSelected()); element.setProperty(TCPSampler.TIMEOUT, serverPanel.getResponseTimeout()); - element.setProperty(TCPSampler.TIMEOUT_CONNECT, serverPanel.getConnectTimeout(),""); + element.setProperty(TCPSampler.TIMEOUT_CONNECT, serverPanel.getConnectTimeout(), ""); element.setProperty(TCPSampler.REQUEST, requestData.getText()); + + element.setProperty(TCPSampler.RE_USE_CONNECTION, reUseConnection.isSelected()); + element.setProperty(TCPSampler.CLOSE_CONNECTION, closeConnection.isSelected()); + element.setProperty(TCPSampler.NODELAY, setNoDelay.isSelected()); + element.setProperty(TCPSampler.SO_LINGER, soLinger.getText()); + element.setProperty(TCPSampler.EOL_BYTE, eolByte.getText()); } /** @@ -121,43 +142,64 @@ classname.setText(""); //$NON-NLS-1$ requestData.setText(""); //$NON-NLS-1$ reUseConnection.setSelected(true); + closeConnection.setSelected(false); setNoDelay.setSelected(false); + soLinger.setText(""); //$NON-NLS-1$ + eolByte.setText(""); //$NON-NLS-1$ } - - private JPanel createNoDelayPanel() { - JLabel label = new JLabel(JMeterUtils.getResString("tcp_nodelay")); // $NON-NLS-1$ + private void addNoDelayOption() { + setNoDelay = new JCheckBox(JMeterUtils.getResString("tcp_nodelay")); // $NON-NLS-1$ + optionsPanel.add(setNoDelay); + } - setNoDelay = new JCheckBox(); - label.setLabelFor(setNoDelay); + private void addClosePortOption() { + reUseConnection = new JCheckBox(JMeterUtils.getResString("reuseconnection"), true); //$NON-NLS-1$ + reUseConnection.addItemListener(new ItemListener() { + @Override + public void itemStateChanged(final ItemEvent e) { + if (e.getStateChange() == ItemEvent.SELECTED) { + closeConnection.setEnabled(true); + } else { + closeConnection.setEnabled(false); + closeConnection.setSelected(true); + } + } + }); - JPanel nodelayPanel = new JPanel(new BorderLayout(5, 0)); - nodelayPanel.add(label, BorderLayout.WEST); - nodelayPanel.add(setNoDelay, BorderLayout.CENTER); - return nodelayPanel; + optionsPanel.add(reUseConnection); } - private JPanel createClosePortPanel() { - JLabel label = new JLabel(JMeterUtils.getResString("reuseconnection")); //$NON-NLS-1$ - - reUseConnection = new JCheckBox("", true); - label.setLabelFor(reUseConnection); + private void addCloseConnectionOption() { + closeConnection = new JCheckBox(JMeterUtils.getResString("closeconnection"), false); //$NON-NLS-1$ + optionsPanel.add(closeConnection); + } - JPanel closePortPanel = new JPanel(new BorderLayout(5, 0)); - closePortPanel.add(label, BorderLayout.WEST); - closePortPanel.add(reUseConnection, BorderLayout.CENTER); - return closePortPanel; + private void addSoLingerOption() { + JLabel soLingerLable = new JLabel(JMeterUtils.getResString("solinger")); //$NON-NLS-1$ + soLinger = new JTextField(5); // 5 columns size + soLinger.setMaximumSize(new Dimension(50, 20)); + soLingerLable.setLabelFor(soLinger); + optionsPanel.add(soLingerLable); + optionsPanel.add(soLinger); + } + + private void addEolByteOption() { + JLabel eolByteLabel = new JLabel(JMeterUtils.getResString("eolbyte")); //$NON-NLS-1$ + eolByte = new JTextField(3); // 3 columns size + eolByte.setMaximumSize(new Dimension(30, 20)); + eolByteLabel.setLabelFor(eolByte); + optionsPanel.add(eolByteLabel); + optionsPanel.add(eolByte); } private JPanel createRequestPanel() { - JLabel reqLabel = new JLabel(JMeterUtils.getResString("tcp_request_data")); // $NON-NLS-1$ requestData = new JTextArea(3, 0); requestData.setLineWrap(true); - reqLabel.setLabelFor(requestData); - JPanel reqDataPanel = new JPanel(new BorderLayout(5, 0)); - reqDataPanel.add(reqLabel, BorderLayout.WEST); - reqDataPanel.add(requestData, BorderLayout.CENTER); + final JPanel reqDataPanel = new VerticalPanel(); + reqDataPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), JMeterUtils.getResString("tcp_request_data"))); // $NON-NLS-1$ + reqDataPanel.add(requestData); return reqDataPanel; } @@ -191,13 +233,18 @@ mainPanel.add(classname); mainPanel.add(serverPanel); - HorizontalPanel optionsPanel = new HorizontalPanel(); - optionsPanel.add(createClosePortPanel()); - optionsPanel.add(createNoDelayPanel()); + optionsPanel = new HorizontalPanel(); + addClosePortOption(); + addCloseConnectionOption(); + addNoDelayOption(); + addSoLingerOption(); + addEolByteOption(); + mainPanel.add(optionsPanel); mainPanel.add(createRequestPanel()); // mainPanel.add(createFilenamePanel()); add(mainPanel, BorderLayout.CENTER); } + } --- src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java (revision 1416461) +++ src/protocol/tcp/org/apache/jmeter/protocol/tcp/sampler/TCPSampler.java (working copy) @@ -82,6 +82,12 @@ public static final String REQUEST = "TCPSampler.request"; //$NON-NLS-1$ public static final String RE_USE_CONNECTION = "TCPSampler.reUseConnection"; //$NON-NLS-1$ + + public static final String CLOSE_CONNECTION = "TCPSampler.closeConnection"; //$NON-NLS-1$ + + public static final String SO_LINGER = "TCPSampler.soLinger"; //$NON-NLS-1$ + + public static final String EOL_BYTE = "TCPSampler.EolByte"; //$NON-NLS-1$ //-- JMX file constants - do not change private static final String TCPKEY = "TCP"; //$NON-NLS-1$ key for HashMap @@ -168,6 +174,9 @@ closeSocket(socketKey); // Bug 44910 - close previous socket (if any) SocketAddress sockaddr = new InetSocketAddress(getServer(), getPort()); con = new Socket(); + if (!"".equals(getPropertyAsString(SO_LINGER,""))){ + con.setSoLinger(true, getSoLinger()); + } con.connect(sockaddr, getConnectTimeout()); if(log.isDebugEnabled()) { log.debug("Created new connection " + con); //$NON-NLS-1$ @@ -227,6 +236,31 @@ public boolean isReUseConnection() { return getPropertyAsBoolean(RE_USE_CONNECTION); } + + public void setCloseConnection(String close) { + this.setProperty(CLOSE_CONNECTION, close); + } + + public boolean isCloseConnection() { + return getPropertyAsBoolean(CLOSE_CONNECTION); + } + + public void setSoLinger(String soLinger) { + this.setProperty(SO_LINGER, soLinger, ""); + } + + public int getSoLinger() { + return getPropertyAsInt(SO_LINGER,0); + } + + public void setEolByte(String eol) { + this.setProperty(EOL_BYTE, eol); + } + + public int getEolByte() { + return getPropertyAsInt(EOL_BYTE); + } + public void setPort(String newFilename) { this.setProperty(PORT, newFilename); @@ -323,6 +357,11 @@ } try { TCPClient = (TCPClient) javaClass.newInstance(); + if (!"".equals(getPropertyAsString(EOL_BYTE,""))){ + TCPClient.setEolByte(getEolByte()); + log.info("Using eolByte=" + getEolByte()); + } + if (log.isDebugEnabled()) { log.debug(this + "Created: " + getClassname() + "@" + Integer.toHexString(TCPClient.hashCode())); //$NON-NLS-1$ } @@ -381,7 +420,7 @@ // Set if we were successful or not res.setSuccessful(isSuccessful); - if (!isReUseConnection()) { + if (!isReUseConnection() || isCloseConnection()) { closeSocket(socketKey); } }