我正在学习如何使用Java中的TCP实现多用户聊天服务器。我在网上看到了一个关于此的例子,但是ChatClient.java文件中似乎有些错误。理想情况下,一旦客户端连接到服务器,客户端应该提供昵称,如果此昵称有效,则服务器返回“OK”消息,聊天会话可以开始。
但是,这似乎不起作用。一旦我输入昵称,我就不会从服务器返回“OK”消息,因此无法使用客户端进行聊天。
原始教程网站的链接在这里(这是最后一个例子):http://pguides.net/java/tcp-client-server-chat
我试着在论坛帖子中搜索这篇文章......但似乎已经死了。如果有人能向我解释为什么它不起作用,我真的很感激。
ChatServer.java:
/* ChatServer.java */
import java.net.ServerSocket;
import java.net.Socket;
import java.io.IOException;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Hashtable;
public class ChatServer {
private static int port = 1001; /* port to listen on */
public static void main (String[] args) throws IOException {
ServerSocket server = null;
try {
server = new ServerSocket(port); /* start listening on the port */
} catch (IOException e) {
System.err.println("Could not listen on port: " + port);
System.err.println(e);
System.exit(1);
}
Socket client = null;
while(true) {
try {
client = server.accept();
} catch (IOException e) {
System.err.println("Accept failed.");
System.err.println(e);
System.exit(1);
}
/* start a new thread to handle this client */
Thread t = new Thread(new ClientConn(client));
t.start();
}
}
}
class ChatServerProtocol {
private String nick;
private ClientConn conn;
/* a hash table from user nicks to the corresponding connections */
private static Hashtable<String, ClientConn> nicks =
new Hashtable<String, ClientConn>();
private static final String msg_OK = "OK";
private static final String msg_NICK_IN_USE = "NICK IN USE";
private static final String msg_SPECIFY_NICK = "SPECIFY NICK";
private static final String msg_INVALID = "INVALID COMMAND";
private static final String msg_SEND_FAILED = "FAILED TO SEND";
/**
* Adds a nick to the hash table
* returns false if the nick is already in the table, true otherwise
*/
private static boolean add_nick(String nick, ClientConn c) {
if (nicks.containsKey(nick)) {
return false;
} else {
nicks.put(nick, c);
return true;
}
}
public ChatServerProtocol(ClientConn c) {
nick = null;
conn = c;
}
private void log(String msg) {
System.err.println(msg);
}
public boolean isAuthenticated() {
return ! (nick == null);
}
/**
* Implements the authentication protocol.
* This consists of checking that the message starts with the NICK command
* and that the nick following it is not already in use.
* returns:
* msg_OK if authenticated
* msg_NICK_IN_USE if the specified nick is already in use
* msg_SPECIFY_NICK if the message does not start with the NICK command
*/
private String authenticate(String msg) {
if(msg.startsWith("NICK")) {
String tryNick = msg.substring(5);
if(add_nick(tryNick, this.conn)) {
log("Nick " + tryNick + " joined.");
this.nick = tryNick;
return msg_OK;
} else {
return msg_NICK_IN_USE;
}
} else {
return msg_SPECIFY_NICK;
}
}
/**
* Send a message to another user.
* @recepient contains the recepient's nick
* @msg contains the message to send
* return true if the nick is registered in the hash, false otherwise
*/
private boolean sendMsg(String recipient, String msg) {
if (nicks.containsKey(recipient)) {
ClientConn c = nicks.get(recipient);
c.sendMsg(nick + ": " + msg);
return true;
} else {
return false;
}
}
/**
* Process a message coming from the client
*/
public String process(String msg) {
if (!isAuthenticated())
return authenticate(msg);
String[] msg_parts = msg.split(" ", 3);
String msg_type = msg_parts[0];
if(msg_type.equals("MSG")) {
if(msg_parts.length < 3) return msg_INVALID;
if(sendMsg(msg_parts[1], msg_parts[2])) return msg_OK;
else return msg_SEND_FAILED;
} else {
return msg_INVALID;
}
}
}
class ClientConn implements Runnable {
private Socket client;
private BufferedReader in = null;
private PrintWriter out = null;
ClientConn(Socket client) {
this.client = client;
try {
/* obtain an input stream to this client ... */
in = new BufferedReader(new InputStreamReader(
client.getInputStream()));
/* ... and an output stream to the same client */
out = new PrintWriter(client.getOutputStream(), true);
} catch (IOException e) {
System.err.println(e);
return;
}
}
public void run() {
String msg, response;
ChatServerProtocol protocol = new ChatServerProtocol(this);
try {
/* loop reading lines from the client which are processed
* according to our protocol and the resulting response is
* sent back to the client */
while ((msg = in.readLine()) != null) {
response = protocol.process(msg);
out.println("SERVER: " + response);
}
} catch (IOException e) {
System.err.println(e);
}
}
public void sendMsg(String msg) {
out.println(msg);
}
}
ChatClient.java:
/* ChatClient.java */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class ChatClient {
private static int port = 1001; /* port to connect to */
private static String host = "localhost"; /* host to connect to */
private static BufferedReader stdIn;
private static String nick;
/**
* Read in a nickname from stdin and attempt to authenticate with the
* server by sending a NICK command to @out. If the response from @in
* is not equal to "OK" go bacl and read a nickname again
*/
private static String getNick(BufferedReader in,
PrintWriter out) throws IOException {
System.out.print("Enter your nick: ");
String msg = stdIn.readLine();
out.println("NICK " + msg);
String serverResponse = in.readLine();
if ("SERVER: OK".equals(serverResponse)) return msg;
System.out.println(serverResponse);
return getNick(in, out);
}
public static void main (String[] args) throws IOException {
Socket server = null;
try {
server = new Socket(host, port);
} catch (UnknownHostException e) {
System.err.println(e);
System.exit(1);
}
stdIn = new BufferedReader(new InputStreamReader(System.in));
/* obtain an output stream to the server... */
PrintWriter out = new PrintWriter(server.getOutputStream(), true);
/* ... and an input stream */
BufferedReader in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
nick = getNick(in, out);
/* create a thread to asyncronously read messages from the server */
ServerConn sc = new ServerConn(server);
Thread t = new Thread(sc);
t.start();
String msg;
/* loop reading messages from stdin and sending them to the server */
while ((msg = stdIn.readLine()) != null) {
out.println(msg);
}
}
}
class ServerConn implements Runnable {
private BufferedReader in = null;
public ServerConn(Socket server) throws IOException {
/* obtain an input stream from the server */
in = new BufferedReader(new InputStreamReader(
server.getInputStream()));
}
public void run() {
String msg;
try {
/* loop reading messages from the server and show them
* on stdout */
while ((msg = in.readLine()) != null) {
System.out.println(msg);
}
} catch (IOException e) {
System.err.println(e);
}
}
}
来自评论
当我运行代码时会发生这种情况:
客户方:
Enter your nick: learnHK
hello
SERVER: INVALID COMMAND
not working?
SERVER: INVALID COMMAND
并在服务器端:
Nick learnHK joined.
就是这样。客户端没有从服务器收到“OK”响应消息,因此无法开始聊天。感谢。
答案 0 :(得分:1)
使用
MSG TARGER_USERNAME message_here
答案 1 :(得分:0)
你的问题是,这不是一个简单的聊天服务器,你只需要写任何你想要的东西,然后发送回来。服务器需要特定的命令。
以下是我刚才的一个示例会话:
Enter your nick: arrow
hello
SERVER: INVALID COMMAND
MSG arrow hello
arrow: hello
SERVER: OK
正如你所看到的,当我发送字符串“hello”时,我收到了一个错误。但是当我使用“MSG arrow hello”时,服务器会将其解析为正确的命令。