2013年12月19日星期四

[ Java TCP congestion problems ... online ... ] There are no good people to help me find out why this code will block ah ?

Recently read a book "Java TCP / IP Socket" The book explains some of the content on the Socket , which saw the content on obstruction after a little would not understand, you can not help me look at the code , why is there blocking ah ?

example , there are two cases, case 1 : will not clog ; case 2 : will be blocked ;

code is as follows :

//客户端
public class CompressClient
{
    public static final int BUFSIZE = 256;

    public static void main(String[] args) throws IOException
    {
        InetAddress inetAddr = InetAddress.getLocalHost();
        int port = 8888;
        String fileName = "D:\\杂乱\\桌面.jpg";

        FileOutputStream fileOut = new FileOutputStream(fileName + ".gz");
        final FileInputStream fileIn = new FileInputStream(new File(fileName));

        final Socket sock = new Socket(inetAddr, port);

        // 情况一:不会出现阻塞
        // Thread thread = new Thread()
        // {
        // @Override
        // public void run()
        // {
        // try
        // {
        // sendBytes(sock, fileIn);
        // }
        // catch (IOException e)
        // {
        // e.printStackTrace();
        // }
        // }
        // };

        // thread.start();

        // 情况二:会出现阻塞
        sendBytes(sock, fileIn);

        // 接收压缩服务器信息
        InputStream sockIn = sock.getInputStream();
        int bytesRead;
        byte[] buffer = new byte[BUFSIZE];
        while ((bytesRead = sockIn.read(buffer)) != -1)
        {
            fileOut.write(buffer, 0, bytesRead);
            System.out.print("R");
        }
        System.out.println();

        fileIn.close();
        fileOut.close();
        sock.close();
    }

    private static void sendBytes(Socket socket, InputStream fileIn)
            throws IOException
    {
        OutputStream sockOut = socket.getOutputStream();
        int bytesRead = 0;
        byte[] buffer = new byte[BUFSIZE];
        while ((bytesRead = fileIn.read(buffer)) != -1)
        {
            sockOut.write(buffer, 0, bytesRead);
            System.out.print("W");
        }
        System.out.println("\nClient send data complete!");
        socket.shutdownOutput();
        System.out.println("Client is deadlock? No");
    }
}


//服务端
public class TCPEchoServerExecutor
{
    public static void main(String[] args) throws IOException
    {
        int echoServProt = 8888;

        ServerSocket servSock = new ServerSocket(echoServProt);
        Logger logger = Logger.getLogger("practical");
        Executor service = Executors.newCachedThreadPool();

        while (true)
        {
            Socket clntSock = servSock.accept();
            service.execute(new CompressProtocol(clntSock, logger));
        }
    }
}


//线程任务类
public class CompressProtocol implements Runnable
{
    public static final int BUFSIZE = 1024;

    private Socket clntSock;

    private Logger logger;

    public CompressProtocol(Socket clntSock, Logger logger)
    {
        this.clntSock = clntSock;
        this.logger = logger;
    }

    public static void handleCompressClient(Socket clntSock, Logger logger)
    {
        try
        {

            InputStream in = clntSock.getInputStream();
            GZIPOutputStream out = new GZIPOutputStream(
                    clntSock.getOutputStream());

            byte[] buffer = new byte[BUFSIZE];
            int bytesRead;
            while ((bytesRead = in.read(buffer)) != -1)
            {
                out.write(buffer, 0, bytesRead);
            }
            out.finish();

            logger.info("Server:" + clntSock.getRemoteSocketAddress()
                    + " finished");
        }
        catch (IOException e)
        {
            logger.log(Level.WARNING, "Exception in echo protocol", e);
        }

        try
        {
            clntSock.close();
        }
        catch (IOException e)
        {
            logger.info("Exception = " + e.getMessage());
        }

    }

    @Override
    public void run()
    {
        handleCompressClient(clntSock, logger);
    }
}


Two commented the situation , but the use of a code , it will not be blocked . This is what principle ah ? We can explain the explanation?
------ Solution ---------------------------------------- ----
  
private static void sendBytes (Socket socket, InputStream fileIn)
throws IOException
{
OutputStream sockOut = socket.getOutputStream ();
int bytesRead = 0;
byte [] buffer = new byte [BUFSIZE];
while ((bytesRead = fileIn.read (buffer))! = -1) / / Here will be blocked because if there is no bytes are read , then blocked
{
sockOut.write (buffer, 0, bytesRead);
System.out.print ("W");
}
System.out.println ("\ nClient send data complete!");
socket.shutdownOutput ();
System.out.println ("Client is deadlock No?");
}
The code in question ,
------ Solution ------------------------------ --------------

//不管是客户机,还是服务器程序,你这段代码只能是学习用, 要用到项目中去, 不能这么简单的写.
while ((bytesRead = in.read(buffer)) != -1)
            {
             out.write(buffer, 0, bytesRead);
}

use the following code, and then improve their own :

try{

int pava=0;
int cava=0;
int sumb=0;
int i=0;
int c=0;
ByteArrayOutputStream buffeOut =new ByteArrayOutputStream();
byte readbuf[] = new byte[10240];
while (socket.isConnected() && !socket.isClosed()) {
i++;
pava =in.available();
if(pava>0){
while ((c = in.read(readbuf)) != -1) {
buffeOut.write(readbuf, 0, c);
sumb =sumb + c;
cava =in.available();
if(cava<=0){
Thread.sleep(100);
cava =in.available();
if(cava<=0) break;
}
}
String strin = new String(buffeOut.toByteArray(),"utf-8");
System.out.println("读取流数据内容: "+strin+","+sumb);
buffeOut.reset();
//读完后回复信息.
out.write((i+",我是服务器,已收到数据!").getBytes("utf-8"));
out.flush();
if(c == -1) break;//对方关闭了输入流.
}else{
sumb=0;
out.write((i+",我是服务器,请发送数据!").getBytes("utf-8"));
out.flush();
Thread.sleep(1000);
}
}
} catch (SocketException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
System.out.println("Request,NO["+requestCount+"],读取流数据完成.");
}

------ For reference only ----------------------------------- ----
answer is no well-wishers it? Online ......
------ For reference only ---------------------------- -----------
right, I ask you to send queue and (RecvQ) receive queue size is how much ah TCP socket (SendQ) in ?
------ For reference only ---------------------------------------
read the socket read ! (buffer) = -1 only in one case established that in each call socket.shutdownOutput (); methods.
-1 otherwise never have occurred , so you never end here , unless two conditions:
1 each call socket.shutdownOutput () ;/ / You will receive a -1 , but if the other program is not what you write , can not guarantee oh.
2 each call socket.close (); / / there is an exception, the end , but when you have to re- write data anomalies appear
-----!! - For reference only ---------------------------------------


Thank you, my own problems to solve , first you will good, but one thing you analyze wrong, when calling sockOut.write (buffer, 0, bytesRead), I found that the program is here was only blocked , indicating that - " receiving end SendQ queue has been filled , so will cause obstruction when the server calls sockOut.write (buffer, 0, bytesRead)", this problems with "Socket receive queue SendQ" about !

However, there still want to thank you , while ((bytesRead = in.read (buffer))! = -1) is used in this way depends on what the scene , You can also use the " custom message boundary character " to achieve .

Thank you !
------ For reference only -------------------------------------- -


"! socket in the read (buffer) = -1 only established in one case ," you say this view is wrong , the correct view is : Only two views establishment , 1.socket.shutdownOutput () 2.socket.close (), I suggest you try it yourself !
------ For reference only -------------------------------------- -
I'm here to write the code , just learning to use , does not suggest that you direct use projects, is just learning to use Oh !
correct code is as follows :

/*
 * 服务端
 */
public class TestServer
{
    public static void main(String[] args) throws IOException
    {
        System.out.println("服务端启动......");
        ServerSocket server = new ServerSocket(8888);

        Socket client = server.accept();
        OutputStream output = client.getOutputStream();
        InputStream input = client.getInputStream();

        byte[] temp = new byte[10];
        int realLen = 0;
        while ((realLen = input.read(temp)) != -1)
        {
            System.out.println("【服务端】正在发送数据......");
            output.write(temp, 0, realLen);
        }
        System.out.println("【客户端】发送数据完毕!");
        output.flush();

        client.close();
    }
}




/*
 * 客户端
 */
public class TestClient
{
    public static void main(String[] args) throws UnknownHostException,
            IOException
    {
        System.out.println("客户端启动......");
        final Socket client = new Socket(InetAddress.getLocalHost(), 8888);

        final OutputStream out = client.getOutputStream();
        InputStream in = client.getInputStream();
        final FileInputStream fileIn = new FileInputStream(new File(
                "D:\\杂乱\\桌面.jpg"));

        // 使用一个子线程发送数据
        Thread handlerExecute = new Thread()
        {
            @Override
            public void run()
            {
                try
                {
                    byte[] fileTemp = new byte[1024];
                    int realFileLen = 0;

                    while ((realFileLen = fileIn.read(fileTemp)) != -1)
                    {
                        System.out.println("【客户端】正在发送数据......");
                        out.write(fileTemp, 0, realFileLen);
                    }
                    System.out.println("【客户端】发送数据完毕!");

                    out.flush();
                    client.shutdownOutput();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        };

        handlerExecute.start();

        // 使用主线程接收数据
        ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
        int realLen = 0;
        byte[] temp = new byte[10];
        while ((realLen = in.read(temp)) != -1)
        {
            byteArray.write(temp, 0, realLen);
        }
        byte[] recvByte = byteArray.toByteArray();

        System.out.println("客户端接收消息成功,消息长度:" + recvByte.length);

    }
}

everything there intact ! Thank guishuanglin again !!!

没有评论:

发表评论