首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在java网络编程中,有没有一种方法可以在客户端关闭的情况下保持服务器端的打开?

在java网络编程中,有没有一种方法可以在客户端关闭的情况下保持服务器端的打开?
EN

Stack Overflow用户
提问于 2015-07-21 14:00:41
回答 4查看 3.9K关注 0票数 8

假设我们在Java中有一个简单的Echo客户机/服务器对。据我所知,一旦插座的一侧断裂,那么整个连接就会消失。

但是,如果我想要一个即使客户端死机也能始终保持活动状态的服务器呢?我希望能够恢复断开的连接。

Echo服务器:

代码语言:javascript
运行
复制
import java.net.Socket;
import java.net.ServerSocket;

public class EchoServer {

    public static void main(String[] args) throws Exception {

        // create socket
        int port = 4444;
        ServerSocket serverSocket = new ServerSocket(port);
        System.err.println("Started server on port " + port);

        // repeatedly wait for connections, and process
        while (true) {

            // a "blocking" call which waits until a connection is requested
            Socket clientSocket = serverSocket.accept();
            System.err.println("Accepted connection from client");

            // open up IO streams
            In  in  = new In (clientSocket);
            Out out = new Out(clientSocket);

            // waits for data and reads it in until connection dies
            // readLine() blocks until the server receives a new line from client
            String s;
            while ((s = in.readLine()) != null) {
                out.println(s);
            }

            // close IO streams, then socket
            System.err.println("Closing connection with client");
            out.close();
            in.close();
            clientSocket.close();
        }
    }
}

感谢您的任何建议

EN

回答 4

Stack Overflow用户

发布于 2015-11-04 19:45:01

您缺少的是“会话”的概念。想一想服务器的位置,当一些比特到达“网络”时。如何处理这些内容?使用TCP/IP时,线路上已存在一些信息,即:

  • 源地址
  • 源端口
  • 目标地址
  • 目标端口

<代码>H19和消息有效负载本身<代码>H210<代码>H111和一些其他内容(如顺序计数器,以确保在transmission)期间不会弄乱‘数据包’

服务器的操作系统使用src/dest /port信息来确定这是否是“已经在进行中的会话”。它主要考虑dest port (因为消息已经通过互联网和防火墙到达机器本身)来决定它是否是用于监听“目标端口”的Java程序。但是,它使用整个src-addr/src-port/dest/dest来尝试按照发送方发送的顺序将有效负载传递到您的程序(由于互联网的干扰,这可能不是它们到达的顺序)。请注意,单个“消息”实际上可能被分成多个数据包。操作系统的TCP/IP堆栈为您做了相当多的工作。

但是,请注意,为了代表您执行此功能,操作系统必须投入一定数量的资源来“跟踪TCP/IP会话的状态”。至少,对于每组port/addr src/dest,需要有最后一个良好接收的‘包’的计数器,需要一些缓冲区空间来保存包,直到您的程序准备好使用它们,等等。

现在,TCP/IP协议栈实现者面临的问题是“我应该‘坚持’这种状态多久”?10秒够了吗? 20分钟?在某一时刻,在一段时间内没有收到客户端的消息后,会话必须“超时”。如果有更多的数据包要按顺序发送,并且客户端开始再次发送它们,则服务器必须能够说“对不起,您正在向我发送前一个消息的数据包234,但是因为我有一段时间没有收到您的消息,所以我丢弃了数据包1-233。我们可以重新开始吗?”

因此,从这个意义上说,没有办法阻止客户端“断开连接”。当然,您可以继续监听套接字,以防客户端恢复并发送更多数据。但你和你的客户需要一种方法来“从我们停止的地方重新开始”。

在HTTP中,这是通过使用“会话cookie”来实现的--服务器提供给客户端的一个唯一的长字符串,客户端在每次新请求时都会重新发送(无论它是否发生在同一个TCP级别的会话中)。这是一个“应用层会话”,它的生命周期比TCP会话的生命周期长。

由于您正在编写应用程序,并且听起来您可以在一定程度上控制客户端和服务器之间的内容(“协议”),因此您有更多的选择,比如如何就会话内容达成一致,如何在客户端“离开”时处理问题(会话超时),以及两端如何恢复并“从中断的位置重新开始”(重新建立会话)。不要忘记身份验证,好吗!

正如其他人所说,这在很大程度上取决于你试图实现的目标。

票数 10
EN

Stack Overflow用户

发布于 2015-07-21 14:21:26

当你想创建一个服务器和多个客户端时,我们通常做的是创建一个线程,负责服务器和其中一个客户端之间的通信,所以每次客户端连接到服务器时,服务器都会启动一个新的线程,并为其提供相应的套接字。

代码应该是这样的:

代码语言:javascript
运行
复制
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;

public class EchoServer {

    public static void main(String[] args) throws Exception {

        ArrayList<ClientHandler> clientHandlersList = new ArrayList<ClientHandler>();

        // create socket
        int port = 4444;
        boolean isOver = false;
        ServerSocket serverSocket = new ServerSocket(port);
        System.err.println("Started server on port " + port);

        // repeatedly wait for connections, and process
        while (!isOver) {

            // a "blocking" call which waits until a connection is requested
            Socket clientSocket = serverSocket.accept();
            System.err.println("Accepted connection from client");

            ClientHandler handler = new ClientHandler(clientSocket);
            handler.start();
            clientHandlersList.add(handler);
        }

        serverSocket.close();
    }
}

和ClientHandler类:

代码语言:javascript
运行
复制
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;


public class ClientHandler extends Thread {

    private Socket socket;
    private ObjectInputStream in;
    private ObjectOutputStream out;
    private boolean disconnect = false;


    public ClientHandler(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            in = new ObjectInputStream(socket.getInputStream());
            out = new ObjectOutputStream(socket.getOutputStream());
            while(!disconnect){
                Object message = readMessage();

                //DO something
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public Object readMessage(){
        try {
            Object obj = in.readObject();
            return obj;

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return null;
    }

    public void writeMessage(Object obj){
        try {
            out.writeObject(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void disconnect(){
        try {
            disconnect = false;
            out.close();
            in.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
票数 5
EN

Stack Overflow用户

发布于 2016-02-28 04:04:13

正如有人指出的,使用TCP不能做到这一点。

下面是一个简单的DatagramSocket (UDP)回显服务器示例。

代码语言:javascript
运行
复制
package test;

import java.io.*;
import java.net.*;

public class UDPEchoServer {

    public static void main(String[] args) throws IOException
    {
        new ServerThread().start();
    }


    static class ServerThread extends Thread
    {

        protected DatagramSocket socket = null;

        public ServerThread() throws IOException
        {
            this("ServerThread");
        }

        public ServerThread(String name) throws IOException
        {
            super(name);
            socket = new DatagramSocket(4444);

        }

        public void run()
        {
            try {
                while (true) {
                    byte[] buf = new byte[256];

                    // receive data
                    DatagramPacket packet = new DatagramPacket(buf, buf.length);
                    socket.receive(packet);

                    // send back the response to the client at "address" and "port"
                    InetAddress address = packet.getAddress();
                    int port = packet.getPort();
                    packet = new DatagramPacket(buf, buf.length, address, port);
                    socket.send(packet);
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
            socket.close();
        }
    }
}

更新:添加了测试信息

您可以使用nc测试它

代码语言:javascript
运行
复制
[gustaf@gustf-air]$ nc -u 127.0.0.1 4444
testing echo server
testing echo server
killing it now
killing it now
^C
[gustaf@gustf-air]$ nc -u 127.0.0.1 4444
now we are back
now we are back
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31531422

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档