Java TCP nio服务器和python2.7客户端

时间:2017-09-21 01:32:44

标签: java python-2.7 tcp nio bytebuffer

我正在尝试将数据从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端处理此数据。

0 个答案:

没有答案