📄 tcpconnclient.java
字号:
package org.trinet.waveserver.rt;
import java.io.*;
import java.net.*;
import java.util.*;
/** Implementation of a TRINET WaveClient TCPConnClient class.
* This class extends the base TCPConn class and is used by a WaveClient instance to open a
* TCP socket connection to a specified host and port.
* A Client data member instance is used as a wrapper for requested host server address and port number.
* Methods are implemented to to send/receive TCPMessage objects between a WaveClient and a WaveServer
* instances via the TCPConn socket input/outstreams.<p>
* A TCPMessage is comprised of a collection of DataField objects whose values are
* "serialized" into Packet objects which are then "serialized" as a byte stream by
* the TCPConn socket connection. The serialization is not java.io.Serializable,
* but rather a protocol implemented by subclasses of TrinetSerial which is
* defined in the WaveClinet/Server API documentation.
* @see Client
* @see TCPConn
* @see TrinetSerial
* @see TCPMessage
* @see Packet
*/
public class TCPConnClient extends TCPConn implements java.io.Serializable {
/** Implementation version identifier.*/
public static final int TCP_CONN_VERSION = 1;
/** Length of field storing the length of a serially formatted DataField. */
public static final int PACKET_FIELD_HEADER_BYTES = 4;
/** Container for the server name and port id. */
Client client;
/** Default constructer, a no-op, no connection is made, must invoke methods to create socket connection.
* @see TCPConn#createSocket(String, int)
* @see TCPConn#initSocket()
public TCPConnClient() {
super();
}
/** Constructor creates a socket connection to the host and port specified by the input Client object.
* Clones the input Client reference.
* @see Client
* @exception java.io.IOException error occurred trying to establish the connection.
* @exception java.lang.NullPointerException input parameter in null
* @exception java.lang.Security if SecurityManager exists its checkConnect(...) doesn't allow connection.
* @exception java.net.UnknownHostException host name cannot be resolved by the socket.
*/
public TCPConnClient(Client client) throws IOException, UnknownHostException {
if (client == null) throw new NullPointerException("TCPConnClient constructor null input Client parameter.");
createSocket(client.host, client.port);
this.client = (Client) client.clone();
}
/** Constructor creates a socket connection to the host and port specified the inputs.
* Creates a new Client data member from the input parameters.
* @exception java.io.IOException error occurred trying to establish the connection.
* @exception java.net.UnknownHostException host name cannot be resolved by the socket.
* @exception java.lang.Security if SecurityManager exists its checkConnect(...) doesn't allow connection.
*/
public TCPConnClient(String host, int port) throws IOException, UnknownHostException {
super(host, port);
client = new Client(host, port);
}
/** Constructor creates a socket connection to the host and port specified the inputs.
* Creates a new Client data member from the input parameters.
* @exception java.io.IOException error occurred trying to establish the connection.
* @exception java.lang.Security if SecurityManager exists its checkConnect(...) doesn't allow connection.
*/
public TCPConnClient(InetAddress inetAddr, int port) throws IOException {
super(inetAddr, port);
client = new Client(inetAddr.getHostName(), port);
}
/** Constructor set the connection reference to input socket reference. Initializes socket attributes to defaults.
* @exception java.lang.NullPointerException null input reference
* @exception java.io.IOException error occurred trying to establish the connection.
* @exception java.lang.Security if SecurityManager exists its checkConnect(...) doesn't allow connection.
*/
public TCPConnClient(Socket socket) throws IOException {
super(socket);
client = new Client(socket.getInetAddress().getHostName(), socket.getPort());
}
/** Returns true only if the input object is an instance of this class
* and the Client data members (host, port) have equivalent values.
*/
public boolean equals(Object object) {
if (this == object) return true;
else if (! super.equals(object) ) return false;
return (client.equals(client)) ? true: false;
}
/** Returns a String summarizing the labeled connection attributes of the client. */
public String toString() {
StringBuffer sb = new StringBuffer(512);
sb.append(getSocketInfo());
sb.append(" client : ");
if (client == null) sb.append("null");
else sb.append(client.toString());
return sb.toString();
}
/** Creates a new Packet object from the serialized input data parsed from the socket input stream.
* @exception java.io.IOException error occurred de-serializing the Packet from the socket input stream.
*/
private Packet receivePacket() throws IOException {
Packet pkt = new Packet(); // null or zero data members;
// read in Packet header
int bytesToRead = Packet.HEADER_BYTES;
byte [] header = new byte [bytesToRead];
int bytesRead = 0;
int offset = 0;
while (bytesToRead > 0) {
bytesRead = socketInStream.read(header, offset, bytesToRead);
if (bytesRead > 0) {
bytesToRead -= bytesRead;
offset += bytesRead;
}
else if (bytesRead <= EOF) {
throw new InterruptedIOException("TCPConnClient receivePacket EOF packet header - is stream closed by server?");
}
}
pkt.setHeader(header);
// read in Packet data content.
bytesToRead = pkt.dataLength;
byte [] data = new byte [bytesToRead];
bytesRead = 0;
offset = 0;
while (bytesToRead > 0) {
bytesRead = socketInStream.read(data, offset, bytesToRead);
if (bytesRead > 0) {
bytesToRead -= bytesRead;
offset += bytesRead;
}
else if (bytesRead <= EOF) {
throw new InterruptedIOException("TCPConnClient receivePacket EOF packet data - is stream closed by server?");
}
}
pkt.setData(data);
return pkt;
}
/** Creates an empty Packet collection. */
private Collection createPacketCollection() {
return new ArrayList();
}
/** Creates an empty DataField collection. */
private Collection createDataFieldCollection(int size) {
return new ArrayList(size);
}
/** Extracts all serialized DataFields found in the input collection of Packet objects.
* @exception java.io.IOException error occurred de-serializing the DataFields from a Packet object.
*/
private Collection extractFields(Collection packetList) throws IOException {
Iterator iter = packetList.iterator();
Collection dataFieldList = createDataFieldCollection(packetList.size());
while (iter.hasNext()) {
Packet pkt = (Packet) iter.next();
int declaredLength = pkt.dataLength;
int foundLength = 0;
DataInputStream dataIn = new DataInputStream(new ByteArrayInputStream(pkt.getDataContent()));
try {
while (foundLength < declaredLength) {
int fieldLength = dataIn.readInt();
dataIn.readFully(dataFieldBuffer, 0, fieldLength);
dataFieldList.add(new DataField(dataFieldBuffer));
foundLength += PACKET_FIELD_HEADER_BYTES + fieldLength;
}
}
catch (IOException ex) {
System.err.println("TCPConn.extractFields() error parsing dataField from input packet byte stream.");
ex.fillInStackTrace();
throw ex;
}
finally {
try {
dataIn.close();
}
catch (IOException ex) { ex.printStackTrace();}
}
if (foundLength != declaredLength) {
String msg = "Error TCPConn.extractFields() Corrupted packet length (declared,found): " +
foundLength + ", " + declaredLength;
System.err.println(msg);
throw new IOException(msg);
}
}
return dataFieldList;
}
/** Creates one TCPMessage from the socket input stream uses default timeout value.
* @exception TCPConnException io error or socket timed out before reading enough data to de-serialize message from socket stream.
*/
TCPMessage receive() throws TCPConnException {
return receive(timeoutDefault);
}
/** Creates one TCPMessage from the socket input stream uses specified input timeout value.
* @exception TCPConnException io error or socket timed out before reading enough data to de-serialize message from socket stream.
*/
TCPMessage receive(int timeoutMilliSecs) throws TCPConnException {
Collection packetList = createPacketCollection();
TCPMessage msg = null;
try {
socket.setSoTimeout(timeoutMilliSecs);
Packet pkt = receivePacket();
//DEBUG System.out.println("TCPConnClient receive(int) pkt.toString():\n" + pkt.toString());
msg = new TCPMessage(pkt.msgType);
int currentPacket = 1;
while (pkt.packetNumber <= pkt.totalMsgPackets) {
if (pkt.version != TCP_CONN_VERSION) {
throw new TCPConnException("Error TCPConn.receive() Version mismatch in packet " +
"TCP_CONN_VERSION: " + TCP_CONN_VERSION + " packet version: " + pkt.version);
}
else if (msg.messageType != pkt.msgType) {
throw new TCPConnException("Error TCPConn.receive() Message type mismatch in packets " +
"TCPMessage type: " + msg.messageType + " packet type: " + pkt.msgType);
}
if (currentPacket != pkt.packetNumber) {
throw new TCPConnException("Error TCPConn.receive() Packets missing, current,found: " +
currentPacket + ", " + pkt.packetNumber);
}
packetList.add(pkt);
if (pkt.packetNumber == pkt.totalMsgPackets) break;
pkt = receivePacket();
currentPacket++;
}
socket.setSoTimeout(timeoutDefault);
msg.dataFieldList = extractFields(packetList);
}
catch (IOException ex) {
System.err.println(ex.toString() + " timeout: " + timeoutMilliSecs);
ex.printStackTrace();
throw new TCPConnException("Error TCPConn.receive() parsing message packets, packet list size: " + packetList.size());
}
return msg;
}
/** Sends the TCPMessage request to the server.
* Returns false if socket connection is null, or an io error occurs.
*/
boolean send(TCPMessage msg) {
if (socket == null) return false;
// Initialize the first packet
int packetCount = 1;
// Convert the data field list into packets
Collection packetList = createPacketCollection();
DataOutputStream dataOut = null;
boolean retVal = true;
try {
ByteArrayOutputStream arrayOutStream = new ByteArrayOutputStream(Packet.MAX_DATA_BYTES);
dataOut = new DataOutputStream(arrayOutStream);
Packet pkt = new Packet(TCP_CONN_VERSION, msg.messageType, packetCount);
Iterator iter = msg.dataFieldList.iterator();
while (iter.hasNext()) {
DataField df = (DataField) iter.next(); // retrieve data field from list
int fieldLength = df.getSerializedFieldLength(); // get its length: header + value
if((fieldLength + PACKET_FIELD_HEADER_BYTES) > Packet.MAX_DATA_BYTES) {
throw new IOException("TCPConn.send() data field length exceeds maximum packet size");
}
dataOut.writeInt(fieldLength); // write length to array buffer "field header"
df.writeDataMembers(dataOut); // write field to array buffer "field data"
if (fieldLength > (Packet.MAX_DATA_BYTES - pkt.dataLength)) { // if full add to list, make new packet
pkt.setData(arrayOutStream.toByteArray()); // add array buffer "field" into current packet
packetList.add(pkt);
packetCount++;
pkt = new Packet(TCP_CONN_VERSION, msg.messageType, packetCount);
arrayOutStream.reset(); // reset the buffer to the begining for new packet
}
pkt.dataLength += PACKET_FIELD_HEADER_BYTES + fieldLength; // increment field datalength for current packet
}
dataOut.flush();
if (pkt.dataLength > 0) {
pkt.setData(arrayOutStream.toByteArray());
packetList.add(pkt); // if data, append the last iteration packet to packet list
}
// Iterate over list, reset totalPackets field in packet header then write packet to the socket output stream
iter = packetList.iterator();
packetCount = 1;
while (iter.hasNext()) {
pkt = (Packet) iter.next();
pkt.totalMsgPackets = packetList.size();
pkt.toOutputStream(socketOutStream);
// pkt.writeDataMembers(new DataOutputStream(socketOutStream));
packetCount++;
}
socketOutStream.flush(); // send the remaining data in the socket buffer, if any
}
catch (IOException ex) {
System.err.println("Error TCPConn.send() Unable to send TCP message, packetList size: " +
packetList.size() + " packet count at error: " + packetCount);
System.err.println(ex.getMessage());
ex.printStackTrace();
retVal = false;
}
finally {
try {
dataOut.close();
}
catch (IOException ex) {
System.err.println("TCPConn.send() unable to close data output stream to packet byte buffer.");
ex.printStackTrace();
}
}
return retVal;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -