Oh, how I wish TCP was packet based like UDP! [cm. comments] But, alas, this is not so, so I'm trying to implement my own package layer. Here's a chain of events (ignoring package writing)
Oh, and my packets are very simply structured: two unsigned bytes for length, and then byte [long] data. (I canβt imagine if they were more complex, I would have been in my ears in expressions if!)
Serveris in an infinite loop, taking connections and adding them to the Connections list .PacketGatherer(another thread) uses Selectorto find out which ones Connection.SocketChannelare ready for reading.- He reviews the results and tells everyone
Connection read(). - Each
Connectionhas a partial IncomingPacketand list Packetthat has been fully read and awaiting processing. - On
read():- Tell partial
IncomingPacketto read more data. ( IncomingPacket.readDatabelow) - If reading (
IncomingPacket.complete()) did this , make it Packetand paste it Packetinto a list that is awaiting processing, and then replace it with a new one IncomingPacket.
There are a couple of problems with this. First, only one packet is read at a time. If you IncomingPacketneed only one more byte, then only this byte is read. Of course, this can be fixed with a loop, but it is starting to get more complicated, and I wonder if there is a better way.
-, IncomingPacket , , . , :
int readBytes;
byte length1, length2;
public int getLength() {
return (int)(length1 << 8 | length2);
}
public void readData(SocketChannel c) {
if (readBytes < 2) {
ByteBuffer lengthBuffer = ByteBuffer.allocate(2 - readBytes);
numBytesRead = c.read(lengthBuffer);
if(readBytes == 0) {
if(numBytesRead >= 1)
length1 = lengthBuffer.get();
if(numBytesRead == 2)
length2 = lengthBuffer.get();
} else if(readBytes == 1) {
if(numBytesRead == 1)
length2 = lengthBuffer.get();
}
readBytes += numBytesRead;
}
if(readBytes >= 2) {
}
}
public boolean complete() {
return (readBytes > 2 && readBytes == getLength()+2);
}
. . , , . ; . , - .
, : ( , - )
public void fillWriteBuffer() {
while(!writePackets.isEmpty() && writeBuf.remaining() >= writePackets.peek().size()) {
Packet p = writePackets.poll();
assert p != null;
p.writeTo(writeBuf);
}
}
public void fillReadPackets() {
do {
if(readBuf.position() < 1+2) {
break;
}
short packetLength = readBuf.getShort(1);
if(readBuf.limit() >= 1+2 + packetLength) {
readBuf.flip();
byte packetType = readBuf.get();
packetLength = readBuf.getShort();
byte[] packetData = new byte[packetLength];
readBuf.get(packetData);
Packet p = new Packet(packetType, packetData);
readPackets.add(p);
readBuf.compact();
} else {
break;
}
} while(true);
}