假设我们在Java中有一个简单的Echo客户机/服务器对。据我所知,一旦插座的一侧断裂,那么整个连接就会消失。
但是,如果我想要一个即使客户端死机也能始终保持活动状态的服务器呢?我希望能够恢复断开的连接。
Echo服务器:
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();
}
}
}感谢您的任何建议
发布于 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会话的生命周期长。
由于您正在编写应用程序,并且听起来您可以在一定程度上控制客户端和服务器之间的内容(“协议”),因此您有更多的选择,比如如何就会话内容达成一致,如何在客户端“离开”时处理问题(会话超时),以及两端如何恢复并“从中断的位置重新开始”(重新建立会话)。不要忘记身份验证,好吗!
正如其他人所说,这在很大程度上取决于你试图实现的目标。
发布于 2015-07-21 14:21:26
当你想创建一个服务器和多个客户端时,我们通常做的是创建一个线程,负责服务器和其中一个客户端之间的通信,所以每次客户端连接到服务器时,服务器都会启动一个新的线程,并为其提供相应的套接字。
代码应该是这样的:
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类:
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();
}
}
}发布于 2016-02-28 04:04:13
正如有人指出的,使用TCP不能做到这一点。
下面是一个简单的DatagramSocket (UDP)回显服务器示例。
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测试它
[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 backhttps://stackoverflow.com/questions/31531422
复制相似问题