为什么我的套接字只能进行客户端到服务器的通信,而不能进行服务器到客户端的通信?
我编写了一个简单的 Java 调度程序,其中有一个守护线程来处理传入流量,并使用另一个线程发送命令。
当服务器收到第一条消息时,问题就出现了,然后客户端/服务器系统就会陷入服务器试图向客户端发送响应的位置。 当服务器发送数据时,两端的套接字只是冻结。
我将原来的问题简化为回显服务器和客户端; 我想我的代码一定犯了一个非常非常愚蠢的错误。 下面复制了我机器上的代码和结果。 谁能解释一下出了什么问题吗?
谢谢!
这是结果,我们可以看到一旦收到第一条消息,服务器和客户端就卡住了。
Echo Server listening port...
Echo Server: Waiting from client connection.
Connecting to the server.
Connected to the server.
Dispatcher send: 10
Dispatcher send: 11
Dispatcher send: 12
Dispatcher send: 13
Dispatcher read...
Dispatcher read...
Dispatcher readed 10
代码:
EchoTest:
import java.io.*;
import java.net.*;
public class EchoTest {
public static void main(String[] args) {
EchoServer.listen();
EchoClient client = new EchoClient();
EchoServer server = EchoServer.accept();
}
}
客户端和服务器:
class EchoClient implements Runnable {
private static final int PORT = 13244;
Socket socket;
Disp disp;
Thread client;
public EchoClient() {
client = new Thread(this);
client.start();
}
public void run() {
try {
System.out.println("Connecting to the server.");
Socket socket = new Socket("localhost", PORT);
System.out.println("Connected to the server.");
disp = new Disp(socket);
disp.send(10);
disp.send(11);
disp.send(12);
disp.send(13);
} catch(IOException e) {
System.out.println("Would not connect to local host: " + PORT);
System.exit(-1);
}
}
public void send(int m) {
disp.send(m);
System.out.println("Sent message " + m);
int echo = disp.getMsg();
if(m == echo) {
System.out.println("Message " + m + "sent and received.");
} else {
System.out.println("Message " + m + "cannot be echoed correctly.");
}
}
}
class EchoServer implements Runnable{
private static final int PORT = 13244;
private static ServerSocket serverSocket;
Disp disp;
public EchoServer(Socket s) {
disp = new Disp(s);
}
public static void listen() {
System.out.println("Echo Server listening port...");
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
System.out.println("Could not listen on port: " + PORT);
System.exit(-1);
}
}
public static EchoServer accept(){
try {
System.out.println("Echo Server: Waiting from client connection.");
return new EchoServer(serverSocket.accept());
} catch(IOException e) {
System.out.println("Couldn't accept connection from client.");
System.exit(-1);
}
return null;
}
public void run() {
while(true) {
int m = disp.getMsg();
disp.send(m);
}
}
}
显示:
class Disp implements Runnable{
int msg = -1;
Socket socket;
BufferedInputStream input;
DataInputStream dis;
BufferedOutputStream output;
DataOutputStream dos;
Thread daemon;
public Disp(Socket s) {
this.socket = s;
try{
input = new BufferedInputStream(socket.getInputStream());
dis = new DataInputStream(input);
output = new BufferedOutputStream(socket.getOutputStream());
dos = new DataOutputStream(output);
}catch(IOException e) {
}
daemon = new Thread(this);
daemon.start();
}
public void run() {
while(true) {
int m = get();
setMsg(m);
}
}
public void send(int m) {
synchronized(dos) {
try{
System.out.println("Dispatcher send: " + m);
dos.writeInt(m);
dos.flush();
} catch(IOException e) {
}
}
}
public int get() {
System.out.println("Dispatcher read...");
synchronized(dis) {
try{
int m = dis.readInt();
System.out.println("Dispatcher readed " + m);
return m;
} catch(IOException e) {
}
}
return -1;
}
synchronized public void setMsg(int m) {
while(true) {
if(msg == -1) {
try {
wait();
} catch(InterruptedException e) {
}
} else {
msg = m;
notifyAll();
}
}
}
synchronized public int getMsg() {
while(true) {
if(msg != -1) {
try {
wait();
} catch(InterruptedException e) {
}
} else {
notifyAll();
return msg;
}
}
}
}
I have written a simple Java dispatcher with a daemon thread to handle the incoming traffic, and using another thread to send out commands.
The problem comes when the server receives the first message, then the client/server system gets stuck on where the server trying to send out a response to the client. The sockets on both end just simply freeze when the server sends out data.
I have simplified my original problem into a echo server and client; I guess I must have a very very stupid mistake on the code. The code and result on my machine are reproduced below. Can anyone explain what is going wrong?
Thanks!
Here is the results, we can see the server and client stuck once the first message received.
Echo Server listening port...
Echo Server: Waiting from client connection.
Connecting to the server.
Connected to the server.
Dispatcher send: 10
Dispatcher send: 11
Dispatcher send: 12
Dispatcher send: 13
Dispatcher read...
Dispatcher read...
Dispatcher readed 10
Code:
EchoTest:
import java.io.*;
import java.net.*;
public class EchoTest {
public static void main(String[] args) {
EchoServer.listen();
EchoClient client = new EchoClient();
EchoServer server = EchoServer.accept();
}
}
Client and Server:
class EchoClient implements Runnable {
private static final int PORT = 13244;
Socket socket;
Disp disp;
Thread client;
public EchoClient() {
client = new Thread(this);
client.start();
}
public void run() {
try {
System.out.println("Connecting to the server.");
Socket socket = new Socket("localhost", PORT);
System.out.println("Connected to the server.");
disp = new Disp(socket);
disp.send(10);
disp.send(11);
disp.send(12);
disp.send(13);
} catch(IOException e) {
System.out.println("Would not connect to local host: " + PORT);
System.exit(-1);
}
}
public void send(int m) {
disp.send(m);
System.out.println("Sent message " + m);
int echo = disp.getMsg();
if(m == echo) {
System.out.println("Message " + m + "sent and received.");
} else {
System.out.println("Message " + m + "cannot be echoed correctly.");
}
}
}
class EchoServer implements Runnable{
private static final int PORT = 13244;
private static ServerSocket serverSocket;
Disp disp;
public EchoServer(Socket s) {
disp = new Disp(s);
}
public static void listen() {
System.out.println("Echo Server listening port...");
try {
serverSocket = new ServerSocket(PORT);
} catch (IOException e) {
System.out.println("Could not listen on port: " + PORT);
System.exit(-1);
}
}
public static EchoServer accept(){
try {
System.out.println("Echo Server: Waiting from client connection.");
return new EchoServer(serverSocket.accept());
} catch(IOException e) {
System.out.println("Couldn't accept connection from client.");
System.exit(-1);
}
return null;
}
public void run() {
while(true) {
int m = disp.getMsg();
disp.send(m);
}
}
}
Disp:
class Disp implements Runnable{
int msg = -1;
Socket socket;
BufferedInputStream input;
DataInputStream dis;
BufferedOutputStream output;
DataOutputStream dos;
Thread daemon;
public Disp(Socket s) {
this.socket = s;
try{
input = new BufferedInputStream(socket.getInputStream());
dis = new DataInputStream(input);
output = new BufferedOutputStream(socket.getOutputStream());
dos = new DataOutputStream(output);
}catch(IOException e) {
}
daemon = new Thread(this);
daemon.start();
}
public void run() {
while(true) {
int m = get();
setMsg(m);
}
}
public void send(int m) {
synchronized(dos) {
try{
System.out.println("Dispatcher send: " + m);
dos.writeInt(m);
dos.flush();
} catch(IOException e) {
}
}
}
public int get() {
System.out.println("Dispatcher read...");
synchronized(dis) {
try{
int m = dis.readInt();
System.out.println("Dispatcher readed " + m);
return m;
} catch(IOException e) {
}
}
return -1;
}
synchronized public void setMsg(int m) {
while(true) {
if(msg == -1) {
try {
wait();
} catch(InterruptedException e) {
}
} else {
msg = m;
notifyAll();
}
}
}
synchronized public int getMsg() {
while(true) {
if(msg != -1) {
try {
wait();
} catch(InterruptedException e) {
}
} else {
notifyAll();
return msg;
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是一个非常多的代码。 首先我建议把它砍掉。
其次,您似乎从未调用过
EchoServer.run
,但很难看到。That's an awful lot of code. First of all I suggest cutting it down.
Secondly, you never seem to call
EchoServer.run
, but it's difficult to see.您还应该设置 TCP_NODELAY 标志,因为您只发送几个字节。 操作系统通常会在发送包之前等待更多数据(并且您的flush()对该行为没有影响,因为flush只处理java的缓冲区)。
You should also set the TCP_NODELAY flag, as you send only a few bytes. The Operating system usually waits for more data before it sends a package (and your flush() has no influence over that behaviour, as flush only deals with java's buffers).