Java TCP多用户chatServer与客户端连接到服务器有问题

时间:2011-12-02 06:30:46

标签: java multithreading sockets tcp chat

我正在学习如何使用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”响应消息,因此无法开始聊天。感谢。

2 个答案:

答案 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”时,服务器会将其解析为正确的命令。