我正在尝试将数据从python客户端发送到java nio服务器。我尝试使用python端的普通套接字程序执行此操作 sock.send(数据)。以字节为单位的数据大小约为28000.但是sock.send(数据)的返回值仅为27120(即)传输的字节仅为27120字节。在java nio端,我的butebuffer大小是32000.我在java端接收数据为channel.read(readBuffer)。这里当我在读取后打印readBuffer.position()时它只显示27120.我的问题是如果在python sys.getsizeof(data)中给出28000并且java上的readBuffer大小为32kB,那么整个28000应该已经在readBuffer中接收了,但它显示只读取了27120个字节。这是如何运作的。我是这个TCP nio概念的新手。所以请帮助我,以便更好地理解。
JAVA NIO服务器代码:
import java.net.*;
import java.nio.*;
import java.util.*;
import java.util.logging.*;
import java.nio.channels.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.*;
public class TCPnio
{
public static void main(String[] args) throws Exception
{
try{
TCPServer tcpl = new TCPServer();
tcpl.init();
while(true)
{
Thread.sleep(5000);
}
}
catch(Exception e)
{
}
}
}
class TCPServer implements Runnable
{
private Selector selector;
private ThreadPoolExecutor DataProcessingPool;
private Selector readSelector;
private boolean readThreadStarted = false;
private int port = 4243;
private BlockingQueue infoQueue;
SocketChannelReader reader = null;
private static final Logger LOG = Logger.getLogger(TCPnio.class.getName());
public void init()throws Exception
{
infoQueue = new LinkedBlockingQueue<Runnable>(15470);
DataProcessingPool = new ThreadPoolExecutor(0,40,0l,TimeUnit.MINUTES,infoQueue);
ServerSocketChannel serverChannel = ServerSocketChannel.open();
selector = Selector.open();
serverChannel.socket().bind(new InetSocketAddress(port),100);
serverChannel.configureBlocking(false);
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
new Thread(this,"mi-listener-tcp-"+port+"-thread").start();
readSelector = Selector.open();
// Starting a thread to read client socketChannel from selector
serverChannel.register(readSelector, SelectionKey.OP_ACCEPT);
reader = this.new SocketChannelReader(readSelector);
new Thread(reader,"mi-reader-tcp-4243-thread").start();
}
public void run()
{
try
{
listen(selector);
}
catch(Exception excp)
{
LOG.log(Level.SEVERE,"",excp);
}
}
class SocketChannelReader implements Runnable
{
private Selector selector;
public SocketChannelReader(Selector key)
{
this.selector = key;
}
public void run()
{
try
{
LOG.info("started selector thread read");
while(true)
{
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext())
{
SelectionKey key = it.next();
it.remove();
try
{
if(key.isReadable())
{
handleRead(key);
}
}
catch(RejectedExecutionException e)
{
LOG.log(Level.INFO,"Job submission failed");
}
catch(Exception excp)
{
LOG.log(Level.INFO,"Error.",excp);//No I18N
close(key);
}
}
}
}
catch(Exception e)
{
LOG.log(Level.INFO,"Exception in reader thread",e);
}
}
}
private void listen(Selector selector) throws Exception
{
LOG.info("started selector thread listen");
while(true)
{
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> it = keys.iterator();
while (it.hasNext())
{
SelectionKey key = it.next();
it.remove();
try
{
if(key.isAcceptable())
{
handleAccept(key,readSelector); //put readselector for single thread
if(!(readThreadStarted))
{
new Thread(reader,"mi-reader-tcp-4243-thread").start();
readThreadStarted = true;
}
}
}
catch(Exception excp)
{
LOG.log(Level.INFO,"Error.",excp);//No I18N
close(key);
}
}
}
}
private void handleRead(SelectionKey key) throws Exception
{
Session session =(Session)key.attachment(); // Session is another java class
ByteBuffer buffer=session.readBuffer; // 32011 bytes has been allocated for readBuffer
System.out.println("------------------------- Buffer before read --------------------------------->");
System.out.println(buffer.limit());
System.out.println(buffer.position());
System.out.println(buffer.capacity());
System.out.println("------------------------------------------------------------------------------>");
SocketChannel channel=(SocketChannel)key.channel();
Socket socket = channel.socket();
int bytesRead=channel.read(buffer);
if(bytesRead==-1)
{
LOG.info("HandleRead closing key for "+socket.getPort());
close(key);
return;
}
processClientData(key,buffer,session,socket);
}
private void processClientData(SelectionKey key, ByteBuffer buffer, Session session, Socket socket) throws Exception
{
String resp;
SocketChannel client = (SocketChannel) key.channel();
try
{
System.out.println("------------------Buffer after read---------------------------------------->");
System.out.println(buffer.limit());
System.out.println(buffer.position());
System.out.println(buffer.capacity());
System.out.println("--------------------------------------------------------------------------->");
String firstByte = String.valueOf((char) (buffer.get(0)));
boolean isLastChunk = (firstByte).equals("1");
byte[] tmpArr= new byte[session.payloadLength];
for(int i=1;i<=session.payloadLength;i++)
{
tmpArr[i-1] = buffer.get(i);
}
System.out.println(new String(tmpArr));
int dataLength = Integer.valueOf(new String(tmpArr));
buffer.flip();
if(buffer.remaining()==0)
{
buffer.clear();
return;
}
// To remove the initial bytes which are not part of data (The one's which gives data length)
for(int i=0;i<=session.payloadLength;i++)
{
buffer.get();
}
int buffRem = buffer.remaining();
byte[] data = new byte[buffRem];
buffer.get(data);
System.out.println(buffer.position());
buffer.clear(); // Clearing buffer
System.out.println("----------------->Position:");
System.out.println(buffer.position());
System.out.println("-------------------------------------------------->");
session.key = key;
session.processData(data, isLastChunk);
}
catch(Exception excp)
{
LOG.log(Level.SEVERE,"Going to close client "+socket.getInetAddress().getHostAddress()+" "+socket.getPort()+" since got exception.",excp);
excp.printStackTrace();
resp = "500";
sendResponse(client, resp);
close(key);
}
}
private void handleAccept(SelectionKey key,Selector readSelector) throws Exception
{
ServerSocketChannel serverSocket=(ServerSocketChannel)key.channel();
SocketChannel socketCh=serverSocket.accept();
socketCh.finishConnect();
socketCh.configureBlocking(false);
Socket socket=socketCh.socket();
socket.setKeepAlive(true);//TODO Check if this works. Is it needed?
System.out.println("--------------------------------->Going to reg:");
SelectionKey readKey=socketCh.register(readSelector, SelectionKey.OP_WRITE);
Session session = new Session(socket.getInetAddress().getHostAddress(),DataProcessingPool);
readKey.attach(session);
readKey.interestOps(SelectionKey.OP_READ);
LOG.info("handleAccept complete with "+key);
}
private void sendResponse(SocketChannel client, String resp)
{
Socket socket = client.socket();
try
{
ByteBuffer sendBuffer = ByteBuffer.allocate(1024);
sendBuffer = ByteBuffer.wrap(resp.getBytes());
client.write(sendBuffer);
sendBuffer.clear();
}
catch(Exception excp)
{
LOG.log(Level.SEVERE,"Exception in sending response client "+socket.getInetAddress().getHostAddress()+" "+socket.getPort()+" in TCPlistner.",excp);
}
}
private void close(SelectionKey key)
{
Session session=(Session)key.attachment();
try
{
LOG.info("closing in TCPnio for "+session);
Channel ch=key.channel();
//session.close();
key.cancel();
ch.close();
}
catch(Exception excp)
{
LOG.log(Level.INFO,"Closing key in TCPnio for "+session,excp);
}
}
}
Python客户端代码:
def _send_data(self, param_type, data):
resp = ''
try:
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self._sock.settimeout(15)
self._sock.connect(('',4243))
print "Socket established for "+str(self._sock.getsockname())+"..."
print param_type
tmp_param_type = param_type
#data = "Hello l"#d!!! Hello world!!!"
#param_type_data = ('0'*(self._max_payload_len - len(str(len(param_type))))) + str(len(param_type)) + param_type
#data = ('0'*(self._max_payload_len - len(str(len(param_type))))) + str(len(param_type)) + param_type
data_len = len(data)
import sys
#print sys.getsizeof(data)-sys.getsizeof(str())
print '------------->Len:',len(data) # Length of data=26244
end_idx = 0
finaldataToSnd = ""
while end_idx < data_len:
islast = '0'
if tmp_param_type:
param_type_data = ('0'*(self._max_payload_len - len(str(len(tmp_param_type))))) + str(len(tmp_param_type))
param_type_data += tmp_param_type
else:
param_type_data = '00000'
byteRem = self._max_datalen - len(tmp_param_type)
strt_idx = end_idx
end_idx = strt_idx + byteRem
if end_idx >= data_len:
end_idx = data_len
islast = '1'
content_length = (end_idx - strt_idx)+len(tmp_param_type)
tmp_param_type=''
content_length_data = ('0' * (self._max_payload_len - len(str(content_length)))) + str(content_length)
#print sys.getsizeof(content_length_data)-sys.getsizeof(str())
dataToSnd = islast + content_length_data + param_type_data
print sys.getsizeof(data[strt_idx:end_idx])-sys.getsizeof(str())
dataToSnd = dataToSnd + data[strt_idx:end_idx]
finaldataToSnd += dataToSnd
print len(finaldataToSnd) # after adding header and all to data length is 26273
print self._sock.send(finaldataToSnd) # No.of bytes sent shows as 21720
resp = self._sock.recv(1024)
self._sock.close()
print "Socket closed..."
except:
print traceback.print_exc()
return resp
代码说明:
给python客户端的数据将被发送到带有额外添加字符的java服务器,这些字符决定了数据的内容长度,标题长度和标题。所以在我的情况下,我正在尝试发送长度为26244的数据。要发送的标头是param_type:machine
。因此,要发送的数据将有额外的29个字符(其中18表示标题,11表示内容长度od标题长度)。由于byteBuffer分配的大小为32000字节,因此每个32011字节将在java端处理此数据。