简体   繁体   English

多次读取时,TCP服务器的读取挂起

[英]The read from a TCP Server hangs when reading more than once

I am testing some TCP code and it seems to work fine except for one problem. 我正在测试一些TCP代码,除了一个问题外,它似乎工作正常。 The read from the socket hangs in one of the methods when there is nothing more to read: 当没有更多要读取的内容时,从套接字读取将挂在其中一种方法中:

Here is the TCP code: 这是TCP代码:

package com.comp424.service;

import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class TCPService implements Runnable
{
    protected int             serverPort;
    protected InetAddress     bindAddress;

    protected ServerSocket    serverSocket  = null;
    protected boolean         isStopped     = false;
    protected Thread          runningThread = null;

    protected ExecutorService threadPool = Executors.newFixedThreadPool(10);

    public TCPService(String host,int port)
    {
        serverPort = port;

        try
        {
            bindAddress = InetAddress.getByName(host);
        }
        catch (UnknownHostException e)
        {
            throw new RuntimeException("Failed to get bind address", e);
        }
    }

    private void start()
    {
        try
        {
            serverSocket = new ServerSocket(serverPort, 10, bindAddress);
        }
        catch (IOException e)
        {
            throw new RuntimeException("Cannot open port " + serverPort, e);
        }
    }

    public void run()
    {
        synchronized (this)
        {
            runningThread = Thread.currentThread();
        }

        start();

        while (!isStopped())
        {
            Socket clientSocket = null;

            try
            {
                clientSocket = serverSocket.accept();
            }
            catch (IOException e)
            {
                if (isStopped())
                {
                    System.out.println("Server Stopped.");
                    break;
                }
                throw new RuntimeException("Error accepting client connection", e);
            }

            threadPool.execute(new ClientHandler(clientSocket));
        }
        threadPool.shutdown();

        System.out.println("Server Stopped.");
    }

    public synchronized void stop()
    {
        isStopped = true;

        try
        {
            serverSocket.close();
        }
        catch (IOException e)
        {
            throw new RuntimeException("Error closing server", e);
        }
    }    

    private synchronized boolean isStopped()
    {
        return isStopped;
    }  
}

package com.comp424.service;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;

import com.comp424.impl.dao.DaoFactory;
import com.comp424.intf.dao.ICourseDao;
import com.comp424.intf.dao.IPersonDao;
import com.comp424.intf.dao.IRegisterCourseDao;
import com.comp424.model.Course;
import com.comp424.model.Person;

public class ClientHandler implements Runnable
{
    private static IRegisterCourseDao registrationDao;
    private static IPersonDao         personDao;
    private static ICourseDao         courseDao;

    protected Socket                  clientSocket = null;

    public ClientHandler(Socket socket)
    {
        registrationDao = DaoFactory.getInstance().getCourseRegistrationDao();
        personDao = DaoFactory.getInstance().getPersonDao();
        courseDao = DaoFactory.getInstance().getCourseDao();
        clientSocket = socket;
    }

    public void run()
    {
        try
        {
            String command = null;

            OutputStream output = clientSocket.getOutputStream();
            BufferedReader buffer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));

            command = buffer.readLine();

            while (command != null)
            {
                String separator = ":";

                StringTokenizer tokenizer = new StringTokenizer(command, separator);

                List<String> tokens = new ArrayList<>();

                while (tokenizer.hasMoreElements())
                {
                    tokens.add((String) tokenizer.nextElement());
                }

                int operation = Integer.parseInt(tokens.get(0));

                switch (operation)
                {
                    case 1:
                        try
                        {
                            Person person = personDao.findByID(Long.parseLong(tokens.get(1)));
                            Course course = courseDao.findByID(Long.parseLong(tokens.get(2)));

                            registrationDao.register(person, course);
                            output.write(("0\r\n").getBytes());
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                            output.write(("1\r\n").getBytes());
                        }
                        break;

                    case 2:
                        try
                        {
                            Person person = personDao.findByID(Long.parseLong(tokens.get(1)));
                            Course course = courseDao.findByID(Long.parseLong(tokens.get(2)));

                            registrationDao.register(person, course);
                            output.write(("0\r\n").getBytes());
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                            output.write(("1\r\n").getBytes());
                        }
                        break;

                    case 3:
                        try
                        {
                            Person person = personDao.findByID(Long.parseLong(tokens.get(1)));

                            List<Course> courses = registrationDao.findByPerson(person);

                            for (Course c : courses)
                            {
                                output.write((c.getName() + "\r\n").getBytes());
                            }
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                            output.write(("1\r\n").getBytes());
                        }
                        break;

                }
                command = buffer.readLine();
            }

            output.close();
        }
        catch (IOException e)
        {
            // report exception somewhere.
            e.printStackTrace();
        }
    }
}

And here is the code where it just hangs in findRegisteredCourses() after reading two strings returned instead of exiting the while loop: 这是在读取返回的两个字符串而不是退出while循环之后,将其挂在findRegisteredCourses()中的代码:

    while (response != null)
    {
        result.add(response);
        System.out.println("findRegisteredCourses():Response = " + response);
        response = reader.readLine();

    }

Full code for findRegisteredCourses(): findRegisteredCourses()的完整代码:

    @Override
    public List<String> findRegisteredCourses(String personID) throws Exception
    {
        try (Socket server = new Socket("localhost", 7000))
        {
            List<String> result = new ArrayList<>();

            DataOutputStream writer = new DataOutputStream(server.getOutputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(server.getInputStream()));

            String operation = "3:" + personID + "\r\n";
            writer.writeBytes(operation);
            writer.flush();

            String response = reader.readLine();

            while (response != null)
            {
                result.add(response);
                System.out.println("findRegisteredCourses():Response = " + response);
                response = reader.readLine();

            }
            server.close();
            return result;
        }
    }

You're continuing to try to read from the server until it's closed the socket - whereas the server is waiting for another command from the client. 您将继续尝试从服务器读取数据,直到它关闭套接字为止-而服务器正在等待来自客户端的另一个命令。 Neither side is going to do anything, as they're waiting for the other. 双方都不会做任何事情,因为他们正在等待对方。

Basically, you need to change your protocol, either to have some "here's the end of the response" indication (such as an empty line, if that's not a valid value in the response data), or to only have a single request/response per connection. 基本上,您需要更改协议,或者具有一些“这里是响应的结尾”指示(例如,如果在响应数据中不是有效值,则为空行),或者仅具有单个请求/响应每个连接。

Your suggested "fix" of using the ready() method is very broken - it basically means you assume there's no more data as soon as there's a pause. 您建议使用ready()方法的“解决方法”非常糟糕-它基本上意味着您假设有一个暂停就不会再有更多数据了。 Maybe the server is taking a while to find the next item. 也许服务器需要一段时间才能找到下一个项目。 Maybe there's a delay on the network - or maybe it's finished. 也许网络上存在延迟-也许已经完成。 You can't tell, and basically you're violating the design of streaming protocols (such as TCP) by trying to infer information from the fact that there's no data available right now . 你看不出来,而且基本上你试图从事实,有没有可用的数据,现在推断信息违反了流媒体协议(如TCP)的设计。 Don't do that - fix your protocol. 不要那样做-修正您的协议。

Deleted my original answer because it was wrong as per @Jon Skeet's comments. 删除了我的原始答案,因为根据@Jon Skeet的评论,该答案有误。 I now just send a special end of data token and it works fine. 现在,我只发送一个特殊的数据令牌结尾,它工作正常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在Java中多次从BufferedReader读取 - Read from a BufferedReader more than once in Java ObjectInputStream读取不止一次 - ObjectInputStream Not Reading More Than Once Java:服务器不会多次通过tcp套接字接收消息。 - Java: Server not receiveing messages over tcp socket more than once. 从两个以上的表中读取数据库数据到Swing表中,但是该框架无限期地挂起 - Reading database data from more than two tables into a Swing table but the frame hangs indefinitely Java TCP服务器无法从多个客户端接收消息 - Java TCP server cannot receive message from more than one client Jmeter:TCP采样器错误:500 ReadException:从服务器读取时出错,读取的字节数为0 - Jmeter: TCP Sampler error: 500 ReadException: Error reading from server, bytes read: 0 当您无法控制第二次读取它的代码时,如何多次读取ServletInputStream - How to read a ServletInputStream more than once when you don't have control of the code that reads it a second time 从服务器读取输入时,我的程序挂起了一行.Java - My program hangs on a line when reading input from a server.. Java 在同一连接中向TCP服务器发送多个消息 - Sending more than 1 message to TCP server in same connection 读取多个资产时出现OutOfMemoryError - OutOfMemoryError when reading more than one asset
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM