当客户端的消息类型为“connect”时,我的服务器出现错误,这很奇怪。
服务器接收器代码:
package threads;
public class ReceiveFromClientThread extends Thread {
ObjectInputStream inFromClient = null;
ServerSocket servs = new ServerSocket();
Socket link = null;
Message m = null;
public void run() {
try {
this.servs.servs.accept();
this.inFromClient = new ObjectInputStream(link.getInputStream());
} catch (SocketException e3) {
System.err.println(" Connection reset by peer.");
} catch (IOException e1) {
e1.printStackTrace();
}
while(true) {
try {
if (link.isConnected()) {
this.m = (Message) inFromClient.readObject(); //SHOULDN'T THIS THREAD PAUSE HERE?
if (m.getType().equalsIgnoreCase("normal")) {
System.out.println("[" + m.getTimestamp() + "] "
+ m.getOwner() + " -> " + m.getText());
ServerMain.mc.pushMessageToList(this.m); //Added to message list.
} else if (m.getType().equalsIgnoreCase("connect")) {
System.out.println(m.getOwner() + " connected from "
+ this.link.getInetAddress()+":"+this.link.getPort());
} else if (m.getType() == "disconnect") {
System.err.println("[" + m.getTimestamp() + "] "
+ "[Origin: " + m.getIp() + "] " + m.getOwner()
+ " Disconnected." );
}
}
} catch (IOException | ClassNotFoundException e) {
}
}
}
public ReceiveFromClientThread(Socket link) {
this.link = link;
}
}
客户端连接代码:
ClientMain.sock = new Socket("127.0.0.1",21215);
ClientMain.oos = new ObjectOutputStream(sock.getOutputStream());
Message m = new Message();
m = m.setType("connect");
m.setOwner("Raphael");
m.setIp(sock.getInetAddress().getHostAddress());
m.setPcname(sock.getInetAddress().getCanonicalHostName());
clientmain.ClientMain.oos.writeObject(m);
它应该工作,但它提供无限循环或有时NullPointerException。我的代码中有错误吗?服务器线程不应该挂起readObject()行吗?
答案 0 :(得分:2)
从您提交的代码中,客户端看起来很好,但服务器有一些问题。
创建服务器套接字时,必须指定要绑定的端口(在构造函数中)。这定义了您在哪个端口上侦听并等待客户端。
绑定套接字侦听后,调用.accept()
接受客户端传入连接。 .accept()
方法将返回表示已连接客户端的套接字。通常,您将循环.accept()
并在每次返回时生成一个线程来处理新客户端(您可能有多个客户端)。要与客户端通信,您需要使用返回的套接字。
在您的代码中,您似乎使用的是未绑定的服务器套接字,而link
客户端套接字绝对不是来自.accept()
。
编辑:正如Joachim指出的那样,你还需要通过打破循环来处理套接字关闭的情况。例如。
答案 1 :(得分:0)
这是完全错误的。这种代码一次只能正确处理一个客户端。
一种方式或另一种方式,调用accept()
的结果必须是在其自己的线程中执行的新Runnable
,并且其run()
方法构造其自己的所有流并调用在接受的套接字上执行所有I / O的方法。
这一切都不会发生在Runnable
的构造函数中,它仍然是接受循环线程的一部分。
接受的套接字和那些流必须是Runnable
的实例成员,不是服务器类的实例成员。循环通常看起来像这样:
while (true)
{
new Thread(new ConnectionHandler(ss.accept())).start();
}
其中ConnectionHandler
如上所述实现Runnable
。
请注意,循环没有做任何其他事情,特别是它不会改变它所属的类中的任何实例状态。