【问题标题】:Can't achieve simultaneous connections to a server无法同时连接到服务器
【发布时间】:2017-05-23 20:30:07
【问题描述】:

我有一个 java 服务器(java 1.6,以防万一)接受套接字连接,然后启动线程来解决它们,就像任何常规的多线程服务器一样。但我无法进行同时连接。我连接一个不断发送和接收消息的客户端,并尝试连接第二个,但第二个总是返回一个 BindException,告诉我地址​​已在使用中。我是否把整个多线程的事情弄错了,无论是在概念上还是在我的代码中?

我的服务器:

ServerSocket serverSocketUPMS1 = null;
    try {
        serverSocketUPMS1 = new ServerSocket(Integer.parseInt(cfg.getProperty("UPMSServerPort")));
        serverSocketUPMS1.setSoTimeout(0);
        log.info("Starting the USSDInterface server at port "+serverSocketUPMS1.getLocalPort());
    } catch (IOException e) {
        log.error("The TCP server couldn't be started",e);
        finish = true;
    }

    while (!finish) {
            try {
                log.info("Waiting for a socket to connect...");
                Socket subscriberSocket = serverSocketUPMS1.accept();
                //Timeout de sesion ussd para poder crear una TimeoutException
                int timeOutSocket = Integer.parseInt(cfg.getProperty("USSDSocketTimeout"));
                log.info("New client arrived from " + subscriberSocket.getRemoteSocketAddress());

                upms = new USSDSocket2(subscriberSocket,timeOutSocket);
                Thread t1 = new Thread(upms);
                t1.setName(Integer.toString(subscriberSocket.getLocalPort()) +","+ subscriberSocket.getRemoteSocketAddress() +", upms");
                t1.start();
                UPMSSimUtils.createAvailableInstance(upms);
                log.trace("USSD Socket created and initiated");
            }
            catch (Exception e) {
                log.warn("There's been an error while working with the server socket"+e.getMessage(), e);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e1) {
                    log.warn("There's been an error while waiting to resume the socket listenting"+e1.getMessage(), e1);
                }
            }
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            log.warn("There's been an error while waiting in the server"+e.getMessage(), e);
        }
    }

    try {
        serverSocketUPMS1.close();
        log.info("TCP Server is now DOWN");
    } catch (IOException e) {
        log.error("There was an error while closing the server socket. TCP Server is now DOWN",e);
    }
    upms.stop();

处理线程:

public void run() {
    new Thread(new Sender()).start();
    while (!finish) {
        byte buffer[] = new byte[10000];
        byte size[] = new byte[4];
        try {
            this.socket.getInputStream().read(size, 0, 4);
            Integer largo = calcularTamanio(size);
            log.debug("Size in bytes: "+size);
            log.debug("Length of the incoming string: " + largo);
            this.socket.getInputStream().read(buffer, 0, largo);
            log.debug("Buffer of the incoming string: " + tostr2(buffer));
            decodeMessage(parseXML(toStr(buffer)), toStr(buffer));

        } catch (SocketException e) {
            log.error("Socket exception: " + e.getMessage(), e);
            this.finish = true;
        } catch (IOException e) {
            log.error("IO exception: " + e.getMessage(), e);
            this.finish = true;
        } catch (JDOMException e) {
            log.error("JDOM exception: " + e.getMessage(), e);
        } catch (Exception e) {
            log.error("Unknown exception: " + e.getMessage(), e);
            this.finish = true;
        }
        // try {
        // Thread.sleep(1);
        // } catch (InterruptedException e) {
        // log.error(e.getMessage(), e);
        // }
    }
    try {
        this.socket.close();
        this.socketUDP.close();
    } catch (IOException e) {
        log.error("Error closing the sockets at the USSDSocket", e);
    }
}

客户端套接字的创建:

try{
                socketsCreated++;
                log.info("Attempting to create a socket");
                Properties properties=Config.getInstance().getCfg();

                ussdIface = new USSDInterfaceServerClass(properties);

                int port=Integer.parseInt(properties.getProperty("TestClientSocketTargetPort"));

                log.info("Client will connect to "+properties.getProperty("TestClientSocketTargetAddress")+":"+port);

                clientSocket = new Socket(properties.getProperty("TestClientSocketTargetAddress"),port);
                log.info("Socket connected");
                log.info("Client socket targeting "+properties.getProperty("TestClientSocketTargetAddress")+":"+port+" created");

                USSDSocket2 ussdSocket=new USSDSocket2(clientSocket,Integer.parseInt(properties.getProperty("USSDSocketTimeout")));
                UPMSSimUtils.createAvailableInstance(ussdSocket);

                upms = UPMSSimUtils.getAvailable(properties);

                Thread t1 = new Thread(ussdSocket);
                t1.setName("ussdsocket client test");
                t1.start();

                log.info("USSDSocket setted on the UPMSSimUtils");

                USSDSocketClientThread socketClientThread=instance.new USSDSocketClientThread(upms, "ClientSocketThread-"+socketsCreated);
                openSockets.add(socketClientThread);
                new Thread(socketClientThread).start();

                Thread.sleep(waitTimeBetweenConnections);
            }catch(Throwable throwable){
                log.warn("Error with a new connection",throwable);
                socketsCreated--;
            }

唯一通过套接字发送数据的函数:

public void send(String message) throws IOException {
    log.info("Trying to send message "+message);
    if (message != null && !"".equals(message)) {
        int largo = message.length();
        // largo = 800;
        byte largobytes[] = new byte[4];
        largobytes[0] = (byte) (largo % 256);
        largobytes[1] = (byte) (largo / 256);
        largobytes[2] = (byte) (largo & 0x00FF0000);
        largobytes[3] = 0;
        this.socket.getOutputStream().write(largobytes);
        log.trace("Byte length sent: "+largobytes);
        this.socket.getOutputStream().write(message.getBytes());
        log.info("Message sent successfully");
    }
}

处理线程负责读取来自套接字的所有内容。然后,decodeMessage 创建一个响应,在处理后通过同一个套接字发送。一个不同的实用程序类允许我通过引用它并等待它的响应来通过套接字发送消息。

我不知道这是我从输入/输出流中读取的方式还是什么(使用普通流会绑定或阻塞套接字吗?),但每个示例似乎都告诉我什么我做得很好,当它给我那些错误时。

【问题讨论】:

  • upms 是全局变量吗?看起来是这样,如果是,第二个连接会覆盖upms,并且两个客户端线程都使用同一个套接字。
  • 'upms' 不是全局变量,是线程启动前设置的线程类参数。对不起,我应该澄清一下。我马上改正。
  • 在客户端连接期间获取 BindException 是不寻常的,因为您的源端口是短暂的,因此它应该是未绑定的。连接时是否在套接字上显式调用 bind() ?您可以发布您的客户代码吗?如果它抛出异常,我们需要看看它在做什么。
  • 我添加了尽可能多的相关信息。整个事情有点混乱,所以添加每一条相关信息都会太多。但问题是:我没有做任何 bind() 。也许它突然进入类似绑定状态是有原因的?
  • accept 循环中的睡眠实际上是在浪费时间。

标签: java multithreading sockets server


【解决方案1】:

忘记一切。错误是代码的原始制造者留下了一个硬编码的套接字,该套接字在硬编码的端口上启动。由于套接字没有被使用,我从未注意到它的存在(我错误地认为错误的堆栈跟踪导致了实际工作的套接字,但事实并非如此)

【讨论】:

    猜你喜欢
    • 2019-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    • 2020-01-24
    • 1970-01-01
    相关资源
    最近更新 更多